Compare commits
477 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
88d134dc1b | ||
|
|
cd3117f9b4 | ||
|
|
f93462d88c | ||
|
|
e3982e48ea | ||
|
|
f77296bb2c | ||
|
|
c0f7220040 | ||
|
|
d435b8b4e3 | ||
|
|
c478ace8bd | ||
|
|
5cfec4c371 | ||
|
|
40cdf0c94d | ||
|
|
9908031b68 | ||
|
|
c5b48b4386 | ||
|
|
11fd3cafb5 | ||
|
|
18dda10b54 | ||
|
|
1a73ddea23 | ||
|
|
f15b7dd75c | ||
|
|
51ed5b78f2 | ||
|
|
fb2ec52464 | ||
|
|
d158ba0464 | ||
|
|
b6b1eb2353 | ||
|
|
fd8eed048a | ||
|
|
25ee2170f6 | ||
|
|
c6641d23cd | ||
|
|
f5f6b69d5d | ||
|
|
e536c94028 | ||
|
|
d57020d269 | ||
|
|
d47aa816d3 | ||
|
|
29a9b3d68a | ||
|
|
b6f70e4bc0 | ||
|
|
73e1e6881e | ||
|
|
ebc3dfc3f0 | ||
|
|
2ae05baec3 | ||
|
|
746bcb1dd0 | ||
|
|
874f8328b8 | ||
|
|
62e2283992 | ||
|
|
0cf407b6f5 | ||
|
|
8a97b7efa4 | ||
|
|
1e2ca7b835 | ||
|
|
f7ea847336 | ||
|
|
9d890e1c21 | ||
|
|
9c7e9e25ca | ||
|
|
4ffe736d46 | ||
|
|
13d82e5a4d | ||
|
|
a7f083dbd1 | ||
|
|
d3b82d68e7 | ||
|
|
bd961025f6 | ||
|
|
c31da4eb2a | ||
|
|
812ecf4041 | ||
|
|
cd8be9ffb5 | ||
|
|
40abb446d4 | ||
|
|
96d740fb15 | ||
|
|
5898436638 | ||
|
|
17fee93002 | ||
|
|
68431ae357 | ||
|
|
ba6ba44955 | ||
|
|
3b101a2086 | ||
|
|
876fd218af | ||
|
|
cbd32e7372 | ||
|
|
324b82187b | ||
|
|
8d19c351e7 | ||
|
|
5c00fb361a | ||
|
|
903e0bc568 | ||
|
|
d12a23b73f | ||
|
|
6e34f84b14 | ||
|
|
c74fa04b7f | ||
|
|
758b05393c | ||
|
|
219066d8d7 | ||
|
|
449dd4730f | ||
|
|
73ffe9ce41 | ||
|
|
c21c24f088 | ||
|
|
f35f548ecd | ||
|
|
69d5283caf | ||
|
|
43950fc398 | ||
|
|
d2e3b80517 | ||
|
|
3728d8ecc1 | ||
|
|
dcca524726 | ||
|
|
9ec5fc29aa | ||
|
|
1d0f3a08f4 | ||
|
|
3d8ffcd0f7 | ||
|
|
8c28871b76 | ||
|
|
df53f827c5 | ||
|
|
83adcd73a9 | ||
|
|
8e6890b4d6 | ||
|
|
bd107e849b | ||
|
|
5893f53b43 | ||
|
|
1894ed7721 | ||
|
|
96b715de8e | ||
|
|
b26890f5b3 | ||
|
|
5ae29eabaa | ||
|
|
d9e4aeb518 | ||
|
|
6b7edbd552 | ||
|
|
12f19299a8 | ||
|
|
0008e5a83b | ||
|
|
0bd1aac0ef | ||
|
|
5145344987 | ||
|
|
cc980fbc0c | ||
|
|
878caff378 | ||
|
|
5ce82d6794 | ||
|
|
d456f91921 | ||
|
|
3be77fc634 | ||
|
|
a4e68733ed | ||
|
|
eaae3f824b | ||
|
|
8d3b9685a1 | ||
|
|
3fa354a815 | ||
|
|
512722695e | ||
|
|
9ed424a5d9 | ||
|
|
a36ef67305 | ||
|
|
be340580d4 | ||
|
|
fbe207dac3 | ||
|
|
f59837f7c3 | ||
|
|
d0d0913c70 | ||
|
|
701c25d07a | ||
|
|
d38b4d7b74 | ||
|
|
8fd9324048 | ||
|
|
6004cd17bf | ||
|
|
746e694d7e | ||
|
|
ead419003b | ||
|
|
6141db8f34 | ||
|
|
6993cbeb9f | ||
|
|
96f2c6e2aa | ||
|
|
65f507bc75 | ||
|
|
05d6484d27 | ||
|
|
41bc08a07e | ||
|
|
98058f600e | ||
|
|
41b302b0b9 | ||
|
|
fbe334e7d7 | ||
|
|
9a155491cb | ||
|
|
ab8ec07f2f | ||
|
|
3e1c886b17 | ||
|
|
21c3d16db5 | ||
|
|
0e181cdc82 | ||
|
|
e168be6d97 | ||
|
|
f65be99017 | ||
|
|
e201d4c896 | ||
|
|
a8035d01c6 | ||
|
|
054275f143 | ||
|
|
e652456d54 | ||
|
|
1e6a7d72ab | ||
|
|
965054a707 | ||
|
|
9a26dc090e | ||
|
|
30b0d4cced | ||
|
|
f973536f7f | ||
|
|
490840b71d | ||
|
|
2ad93c114e | ||
|
|
cec2106cfe | ||
|
|
9200e6fc63 | ||
|
|
5907975c02 | ||
|
|
fe68887cdd | ||
|
|
24df6edbf1 | ||
|
|
710bd270d7 | ||
|
|
147e014205 | ||
|
|
65a7f5f1c6 | ||
|
|
cfc3a4217d | ||
|
|
35be854997 | ||
|
|
58af890abe | ||
|
|
ada878c939 | ||
|
|
08435fbe26 | ||
|
|
00a643e70a | ||
|
|
cc759a8427 | ||
|
|
bb392207ea | ||
|
|
a5b9ff0c3a | ||
|
|
146afce934 | ||
|
|
de0909248d | ||
|
|
d5b3a56129 | ||
|
|
fbed850acc | ||
|
|
25fb467c02 | ||
|
|
8493022f75 | ||
|
|
621c1ed95a | ||
|
|
4992e284fb | ||
|
|
e4fb040ddf | ||
|
|
2bfa49cc2e | ||
|
|
3b9d617e37 | ||
|
|
fdf8025a02 | ||
|
|
423dfb6ace | ||
|
|
0a4aede3a8 | ||
|
|
872705d58d | ||
|
|
ca5776e6f3 | ||
|
|
d4998b5d55 | ||
|
|
e93f5e3e87 | ||
|
|
d29bb90c5a | ||
|
|
1230e5c9e7 | ||
|
|
dc3d23c27b | ||
|
|
6623061c2c | ||
|
|
1ecb853309 | ||
|
|
2a6c52800b | ||
|
|
320ddfda2e | ||
|
|
40febc8ef2 | ||
|
|
56f6519b3e | ||
|
|
f219abf082 | ||
|
|
742a04d149 | ||
|
|
26caacc12e | ||
|
|
1497518867 | ||
|
|
1a4a69f365 | ||
|
|
78520e09c3 | ||
|
|
f0207ff161 | ||
|
|
dd45f1c032 | ||
|
|
ddf1c8e385 | ||
|
|
948efbaa76 | ||
|
|
ccd1a4319d | ||
|
|
22be1f1b72 | ||
|
|
7095862601 | ||
|
|
fa98e0570f | ||
|
|
4316d3eade | ||
|
|
f8cd0b5f52 | ||
|
|
a8b3f69acc | ||
|
|
78cb36ea0e | ||
|
|
b4d58f0609 | ||
|
|
18abc214a6 | ||
|
|
5e3857fd3d | ||
|
|
e35b36643c | ||
|
|
16fa339025 | ||
|
|
051b0e0fd3 | ||
|
|
62d3212f88 | ||
|
|
fd96665e97 | ||
|
|
8f6637773b | ||
|
|
d7f829b3e1 | ||
|
|
3fdb43762b | ||
|
|
7ae02a62fe | ||
|
|
11cb33fe25 | ||
|
|
a09202d1fa | ||
|
|
fcccccaaae | ||
|
|
9f80578bab | ||
|
|
32e3665b7a | ||
|
|
e9c10b306c | ||
|
|
dabadcc00e | ||
|
|
9cc594d633 | ||
|
|
8350eeb751 | ||
|
|
7b61bafab7 | ||
|
|
6407d795ed | ||
|
|
9cf235af39 | ||
|
|
18e5365104 | ||
|
|
c03eff8da2 | ||
|
|
28f79cd6c9 | ||
|
|
fc2786b07f | ||
|
|
620ad13427 | ||
|
|
0776442a5f | ||
|
|
4a207395ca | ||
|
|
2df983a1cf | ||
|
|
03e17aea22 | ||
|
|
aefa481c43 | ||
|
|
553c256d31 | ||
|
|
b6023afb29 | ||
|
|
0df1e3a47f | ||
|
|
78a08c5a0b | ||
|
|
55a880c9ac | ||
|
|
61341b8380 | ||
|
|
a32b567eb1 | ||
|
|
25462d3290 | ||
|
|
a9207b392b | ||
|
|
c0f3c3bd2b | ||
|
|
8621fbda79 | ||
|
|
84de986efd | ||
|
|
0f3ab11532 | ||
|
|
6b4a81e471 | ||
|
|
14a18a42b7 | ||
|
|
2c28eddc2b | ||
|
|
1b22ea661c | ||
|
|
efc3c7532e | ||
|
|
a3a807f22c | ||
|
|
fac5d3c07b | ||
|
|
df5ba25010 | ||
|
|
d66db8ca40 | ||
|
|
0722d7ceb9 | ||
|
|
06a23951c9 | ||
|
|
727d4876f5 | ||
|
|
f5a43786c2 | ||
|
|
30967af8ec | ||
|
|
ccd892708b | ||
|
|
8cf3e38b27 | ||
|
|
4685f42045 | ||
|
|
e6232189e7 | ||
|
|
6e12d06343 | ||
|
|
d02b6d90cc | ||
|
|
d10e9d7098 | ||
|
|
57b0cca6ab | ||
|
|
fc565fd818 | ||
|
|
4e0c439c6f | ||
|
|
39220ba408 | ||
|
|
7fbb9f9df3 | ||
|
|
6c3ca9c364 | ||
|
|
7b648cddfd | ||
|
|
a9e1d7641d | ||
|
|
02823c4158 | ||
|
|
d58789cc25 | ||
|
|
434a0cba9f | ||
|
|
ca8695a1d3 | ||
|
|
7f141605fa | ||
|
|
23f9b5f2fc | ||
|
|
1abbe43785 | ||
|
|
6361737cf4 | ||
|
|
a884f968e1 | ||
|
|
ce611c4773 | ||
|
|
ba75c7ddaa | ||
|
|
ff5dccc2b4 | ||
|
|
9b8994fe43 | ||
|
|
34969d9980 | ||
|
|
da11e90333 | ||
|
|
282d06404e | ||
|
|
64e60c106b | ||
|
|
1b3fd20755 | ||
|
|
ce5a2b1f0a | ||
|
|
d68d5d5c51 | ||
|
|
5a3460efb7 | ||
|
|
edf5ddf027 | ||
|
|
982714fa4c | ||
|
|
90ee525be7 | ||
|
|
600323e027 | ||
|
|
46a8b59196 | ||
|
|
f96ae1a1de | ||
|
|
8894ec3019 | ||
|
|
6f914a8d6b | ||
|
|
9f06b91399 | ||
|
|
9d7f12952d | ||
|
|
bc4e6ab1de | ||
|
|
2300e1baee | ||
|
|
1b00e0f254 | ||
|
|
6534e99103 | ||
|
|
ac98895e15 | ||
|
|
4e0961ae5a | ||
|
|
7669b77069 | ||
|
|
529d5b0b7b | ||
|
|
6edc482aad | ||
|
|
8fce81a264 | ||
|
|
ea2479beda | ||
|
|
40e7ee91d7 | ||
|
|
813942edbd | ||
|
|
b70747de6f | ||
|
|
1c58f9aa5a | ||
|
|
93aa2a4e6e | ||
|
|
0504e0423a | ||
|
|
c1c16ab54e | ||
|
|
76dc856dbf | ||
|
|
227fdf10dd | ||
|
|
19c744b17d | ||
|
|
3ce74d04d0 | ||
|
|
87b8fc6a1b | ||
|
|
9012badfb8 | ||
|
|
3b6e5d8ed1 | ||
|
|
1148724613 | ||
|
|
f526695aae | ||
|
|
e8850eeac2 | ||
|
|
777834d790 | ||
|
|
dca9246450 | ||
|
|
767f7ab40e | ||
|
|
1b810ec74f | ||
|
|
f59b9e1b5f | ||
|
|
398dbe802e | ||
|
|
8b5fa0fe76 | ||
|
|
99042a47f3 | ||
|
|
46e600abe9 | ||
|
|
051dd8b58f | ||
|
|
067b02dba1 | ||
|
|
22a0874188 | ||
|
|
0e25809158 | ||
|
|
305d877896 | ||
|
|
a932a5251a | ||
|
|
7b58fccb9f | ||
|
|
859fef62d4 | ||
|
|
0647a3a233 | ||
|
|
aedf55dba0 | ||
|
|
e9a422b657 | ||
|
|
23df6bdfbf | ||
|
|
1b5fee233e | ||
|
|
63457d2de4 | ||
|
|
732c944e98 | ||
|
|
86c4db8f22 | ||
|
|
8c0c9981de | ||
|
|
e5dcf78ceb | ||
|
|
92bce26e22 | ||
|
|
a72c038435 | ||
|
|
6742cdf373 | ||
|
|
ea72cef7f9 | ||
|
|
565ad83399 | ||
|
|
43f795c9e4 | ||
|
|
1589cfb639 | ||
|
|
a9b9931aa8 | ||
|
|
1cd577cc65 | ||
|
|
13d8db3daa | ||
|
|
40c4a01bc0 | ||
|
|
4301c70ba7 | ||
|
|
d5e9e556ab | ||
|
|
bdf9e04963 | ||
|
|
b95285365d | ||
|
|
abf445e969 | ||
|
|
e988e3a303 | ||
|
|
dca548b8a0 | ||
|
|
56ecfdb4eb | ||
|
|
7640851aa9 | ||
|
|
d9301160e1 | ||
|
|
3656d7f631 | ||
|
|
9f89b07777 | ||
|
|
199dbff7b1 | ||
|
|
88b8cb48fc | ||
|
|
e8b3232966 | ||
|
|
5de7537c71 | ||
|
|
4706313239 | ||
|
|
d32819da4e | ||
|
|
b6becae396 | ||
|
|
d310c5746e | ||
|
|
e2f4e9f30a | ||
|
|
44011afd14 | ||
|
|
cebaa71ce1 | ||
|
|
0ed9105a05 | ||
|
|
69ecbe5ad7 | ||
|
|
a218761e99 | ||
|
|
71d167d5fb | ||
|
|
aabdea8627 | ||
|
|
f220a1384c | ||
|
|
e438ade08e | ||
|
|
ed1d537f60 | ||
|
|
d59bc05f12 | ||
|
|
4608301f1c | ||
|
|
a865320e3a | ||
|
|
bc8c01900b | ||
|
|
9704eefc21 | ||
|
|
52cd52d83c | ||
|
|
4a29371907 | ||
|
|
1e5e4e3189 | ||
|
|
041f7da59b | ||
|
|
4dae3447d6 | ||
|
|
7391af6f08 | ||
|
|
8a640c8219 | ||
|
|
2857582f46 | ||
|
|
1d80f03c38 | ||
|
|
d7c20048fe | ||
|
|
cbbdb77a6e | ||
|
|
2ff995aa95 | ||
|
|
21705a0e96 | ||
|
|
c03da3be54 | ||
|
|
69f48ed11a | ||
|
|
caa0c342a4 | ||
|
|
01b4388b3c | ||
|
|
b870f98ec2 | ||
|
|
a5249102f2 | ||
|
|
5aa0c57a74 | ||
|
|
053b076af0 | ||
|
|
247309e11b | ||
|
|
c9fe08e7b7 | ||
|
|
468d4dd9b0 | ||
|
|
6056ba6475 | ||
|
|
4f03a6fb58 | ||
|
|
d8aa4bc5e4 | ||
|
|
06e46e0f1e | ||
|
|
731295f708 | ||
|
|
9399040cd3 | ||
|
|
9f9fde5811 | ||
|
|
cbc46a8229 | ||
|
|
fb11997430 | ||
|
|
b6fbc46b58 | ||
|
|
21de2513e7 | ||
|
|
51bb2d2bc2 | ||
|
|
8d9043e590 | ||
|
|
59c3e8817c | ||
|
|
3132b3035a | ||
|
|
7ebf5ca16a | ||
|
|
d96f132dc0 | ||
|
|
b26ff08a3c | ||
|
|
44678cf5f1 | ||
|
|
5084ee761e | ||
|
|
91f50ae949 | ||
|
|
15f04edcf1 | ||
|
|
01945675ed | ||
|
|
185c16c3e2 | ||
|
|
d25814b84b | ||
|
|
a09a3fd012 | ||
|
|
871fd83148 | ||
|
|
dd8bc493e7 | ||
|
|
44d3baf51a | ||
|
|
c85c0558b9 | ||
|
|
7f11699fac | ||
|
|
525e48ae59 | ||
|
|
a6369a7dde | ||
|
|
d5ea99603f | ||
|
|
083432cbfe | ||
|
|
dbbce4160d | ||
|
|
885aac69c5 | ||
|
|
b3c301fc2a |
@@ -1,25 +0,0 @@
|
||||
{
|
||||
"env": {
|
||||
"node": true,
|
||||
"es6": true
|
||||
},
|
||||
"extends": "eslint:recommended",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 13
|
||||
},
|
||||
"rules": {
|
||||
"linebreak-style": [
|
||||
"error",
|
||||
"unix"
|
||||
],
|
||||
"quotes": [
|
||||
"error",
|
||||
"single"
|
||||
],
|
||||
"semi": [
|
||||
"error",
|
||||
"always"
|
||||
],
|
||||
"no-console": "off"
|
||||
}
|
||||
}
|
||||
3
.gitignore
vendored
@@ -1,7 +1,4 @@
|
||||
node_modules/
|
||||
coverage/
|
||||
.nyc_output/
|
||||
webadmin/dist/
|
||||
installer/src/certs/server.key
|
||||
|
||||
# vim swap files
|
||||
|
||||
24
.gitlab-ci.yml
Normal file
@@ -0,0 +1,24 @@
|
||||
run_tests:
|
||||
stage: test
|
||||
image: cloudron/base:4.2.0@sha256:46da2fffb36353ef714f97ae8e962bd2c212ca091108d768ba473078319a47f4
|
||||
services:
|
||||
- name: mysql:8.0
|
||||
alias: mysql
|
||||
variables:
|
||||
MYSQL_ROOT_PASSWORD: password
|
||||
MYSQL_DATABASE: box
|
||||
BOX_ENV: ci
|
||||
DATABASE_URL: mysql://root:password@mysql/box
|
||||
script:
|
||||
- echo "Running tests..."
|
||||
- mysql -hmysql -uroot -ppassword -e "ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'password';"
|
||||
- mysql -hmysql -uroot -ppassword -e "CREATE DATABASE IF NOT EXISTS box"
|
||||
- npm install
|
||||
- node_modules/.bin/db-migrate up
|
||||
- ln -s /usr/local/node-18.18.0/bin/node /usr/bin/node
|
||||
- node_modules/.bin/mocha --no-timeouts --bail src/test/tokens-test.js
|
||||
- echo "Done!"
|
||||
|
||||
stages:
|
||||
- test
|
||||
|
||||
120
CHANGES
@@ -2805,3 +2805,123 @@
|
||||
* backups: fix issue with s3 backend where files missing in remote was not detected correctly
|
||||
* provision: redirect to correct task (setup/restore/activation)
|
||||
|
||||
[8.0.2]
|
||||
* tgz: fix unhandled promise error handler
|
||||
* tgz: add underflow/overflow proxy stream to ensure size of a changing file
|
||||
* backups: give task a low oomScoreAdjust to not get killed
|
||||
* Fix issue with uploads via File Manager where temp files were not cleaned up
|
||||
* addons: fix crash when importing database of an app with no addons
|
||||
* sshfs: if remote copy fails, fallback to sshfs based copy
|
||||
* frontend: reduce DOM node creation on very fast logstreams and cap to 1k loglines
|
||||
|
||||
[8.0.3]
|
||||
* logs: fix recursion when displaying box logs
|
||||
* frontend: fix clear view in logs viewer
|
||||
* dashboard: support links/markdown in checklist items
|
||||
|
||||
[8.0.4]
|
||||
* ami: IMDv2 support
|
||||
* ionos: add contract-owned eu-central-3
|
||||
* dashboard: remove mailbox import/export feature
|
||||
* backupcleaner: do not remove the backup in progress
|
||||
* backups: make noop upload work again
|
||||
* volumes: `/mnt/volumes` is reserved
|
||||
* apps: do not log app logs to output
|
||||
* sftp: restore mode and owner
|
||||
* dashboard: also render checklist items in apps.html
|
||||
|
||||
[8.0.5]
|
||||
* cpu quota: fix rounding error
|
||||
* frontend: fix translation resolver to actually fallback to english
|
||||
* i18n: fix crash if language file is missing
|
||||
* memory: fix slider UI where max was incorrectly set
|
||||
* digitalocean: add LON1 Spaces region
|
||||
* exoscale: add sos AT-VIE-2 region
|
||||
* i18n: remove use of "Cloudron"
|
||||
* tz: add note in backup and update UI
|
||||
* backups: do not overflow the schedule timings
|
||||
* checklist: new checklist items on update are acknowledged
|
||||
* backups: automatically trigger a remount if mount is not active
|
||||
* logs: rework the syslog parser
|
||||
* docker: use system dns for app containers
|
||||
* logs: show error message in UI when log rotated
|
||||
* unbound: prefer ip4 for dns queries (only on ubuntu 24 and above)
|
||||
* apps: allow operators to update apps
|
||||
|
||||
[8.0.6]
|
||||
* Fix AdGuard resolving dashboard to docker bridge IP
|
||||
|
||||
[8.1.0]
|
||||
* backups: add hetzner object storage
|
||||
* registry: cloudron container registry
|
||||
* gandi: add PAT token support
|
||||
* OpenID: add groups claim support
|
||||
* OpenID: enable refresh token support (dokuwiki)
|
||||
* filemanger: fix various regressions
|
||||
* dashboard: mobile and dark-mode fixes
|
||||
* syslog: fix multiline timestamps
|
||||
* porkbun: use new API endpoint
|
||||
* fix "happy eyeballs" quirk in nodejs
|
||||
* Update nodejs to 20.18.0
|
||||
|
||||
[8.2.0]
|
||||
* rsync: show better error message with too many empty dirs, symlinks or executables
|
||||
* mail: update Solr to 8.11.4
|
||||
* mail: update Haraka to 3.0.5
|
||||
* Add sqlite3 addon
|
||||
* docker: update docker to 27.3.1
|
||||
* du: add exclude file to skip filesystem usage checks
|
||||
* mail: attachment search
|
||||
* oidc: use cloudron name as provider name
|
||||
* groups: add eventlog
|
||||
* resources: allow mounting devices into apps
|
||||
* remove global lock
|
||||
* hetzner: add helsinki object storage location
|
||||
* backups: implement app archive
|
||||
* notifications: per user email notification config
|
||||
* postgres: enable vector extension
|
||||
* docker: fallback to downloading images from quay if dockerhub does not work
|
||||
|
||||
[8.2.1]
|
||||
* apps: fix bug where update and notes indicator was shown to normal users
|
||||
* archive: disable archiving for pre-8.2 backups. we don't have enough info to unarchive
|
||||
* dashboard: fix browser caching issue
|
||||
|
||||
[8.2.2]
|
||||
* gandi: add token type in the setup view
|
||||
* mail: fix issue with dkim signing
|
||||
* mail: fix crash in dns list plugin
|
||||
* scheduler: create jobs with cloudron tz setting
|
||||
* security: fix issue where '/' symlink allows admins to get ssh access
|
||||
|
||||
[8.2.3]
|
||||
* mail: give container a static IP
|
||||
* firewall: add masquerading rules for containers to reach each other via public IP
|
||||
* docker: fix parsing of optional namespace in image refs
|
||||
|
||||
[8.2.4]
|
||||
* restore: fix crash with invalid backup id
|
||||
* setup: add inwx to dns setup
|
||||
* backups: add preserve attributes checkbox
|
||||
* mail: add ipv6 rdns check
|
||||
* mail: disable OCR in tika. this is too slow
|
||||
* mail: rebuild index script
|
||||
* backups: add preserve attributes checkbox
|
||||
* username: only ending with .app is reserved
|
||||
* cloudron-support: add helper function to free up disk space when full
|
||||
* cloudflare: list API does not return `zone_id` anymore
|
||||
|
||||
[8.3.0]
|
||||
* new base image: cloudron/base:5.0.0@sha256:04fd70dbd8ad6149c19de39e35718e024417c3e01dc9c6637eaf4a41ec4e596c
|
||||
* Database upgrades are automatically performed. This might take some time depending on the amount of data.
|
||||
* Postgres v16
|
||||
* Mongodb v7
|
||||
* PHP v8.3
|
||||
* Node.js v22 LTS
|
||||
|
||||
[8.3.1]
|
||||
* Fix crash in postgresql pgvector extension
|
||||
|
||||
[8.3.2]
|
||||
* Bring back immich vectors hook in postgres addon
|
||||
|
||||
|
||||
13
README.md
@@ -45,20 +45,19 @@ Try our demo at https://my.demo.cloudron.io (username: cloudron password: cloudr
|
||||
|
||||
[Install script](https://docs.cloudron.io/installation/) - [Pricing](https://cloudron.io/pricing.html)
|
||||
|
||||
**Note:** This repo is a small part of what gets installed on your server - there is
|
||||
the dashboard, database addons, graph container, base image etc. Cloudron also relies
|
||||
on external services such as the App Store for apps to be installed. As such, don't
|
||||
clone this repo and npm install and expect something to work.
|
||||
**Note:** This repo is just a part of what gets installed on the server. Database addons,
|
||||
Mail Server, Stat contains etc are not part of this repo. As such, don't clone this repo and
|
||||
npm install and expect something to work.
|
||||
|
||||
## License
|
||||
|
||||
Please note that the Cloudron code is under a source-available license. This is not the same as an
|
||||
open source license but ensures the code is available for introspection (and hacking!).
|
||||
open source license but ensures the code is available for transparency and introspection (and hacking!).
|
||||
|
||||
## Contributions
|
||||
|
||||
Just to give some heads up, we are a bit restrictive in merging changes. We are a small team and
|
||||
would like to keep our maintenance burden low. It might be best to discuss features first in the [forum](https://forum.cloudron.io),
|
||||
We are very restrictive in merging changes. We are a small team and would like to keep our maintenance burden low,
|
||||
not to mention legal issues. It might be best to discuss features first in the [forum](https://forum.cloudron.io),
|
||||
to also figure out how many other people will use it to justify maintenance for a feature.
|
||||
|
||||
# Localization
|
||||
|
||||
12
box.js
@@ -5,6 +5,7 @@
|
||||
const constants = require('./src/constants.js'),
|
||||
fs = require('fs'),
|
||||
ldapServer = require('./src/ldapserver.js'),
|
||||
net = require('net'),
|
||||
oidc = require('./src/oidc.js'),
|
||||
paths = require('./src/paths.js'),
|
||||
proxyAuth = require('./src/proxyauth.js'),
|
||||
@@ -25,9 +26,17 @@ async function setupLogging() {
|
||||
};
|
||||
}
|
||||
|
||||
// happy eyeballs workaround. when there is no ipv6, nodejs timesout prematurely since the default for ipv4 is just 250ms
|
||||
// https://github.com/nodejs/node/issues/54359
|
||||
async function setupNetworking() {
|
||||
net.setDefaultAutoSelectFamilyAttemptTimeout(2500);
|
||||
}
|
||||
|
||||
// this is also used as the 'uncaughtException' handler which can only have synchronous functions
|
||||
function exitSync(status) {
|
||||
if (status.error) fs.write(logFd, status.error.stack + '\n', function () {});
|
||||
const ts = new Date().toISOString();
|
||||
const msg = status.error.stack.replace(/\n/g, `\n${ts} `); // prefix each line with ts
|
||||
if (status.error) fs.write(logFd, `${ts} ${msg}\n`, function () {});
|
||||
fs.fsyncSync(logFd);
|
||||
fs.closeSync(logFd);
|
||||
process.exit(status.code);
|
||||
@@ -35,6 +44,7 @@ function exitSync(status) {
|
||||
|
||||
async function startServers() {
|
||||
await setupLogging();
|
||||
await setupNetworking();
|
||||
await server.start(); // do this first since it also inits the database
|
||||
await proxyAuth.start();
|
||||
await ldapServer.start();
|
||||
|
||||
6
dashboard/.gitattributes
vendored
@@ -1,6 +0,0 @@
|
||||
# following files are skipped when exporting using git archive
|
||||
test export-ignore
|
||||
docs export-ignore
|
||||
.gitattributes export-ignore
|
||||
.gitignore export-ignore
|
||||
|
||||
13
dashboard/.gitignore
vendored
@@ -1,11 +1,16 @@
|
||||
dist/
|
||||
node_modules/
|
||||
|
||||
# will get generated on build
|
||||
public/theme.css
|
||||
public/theme.css.map
|
||||
|
||||
# vim swap files
|
||||
*.swp
|
||||
|
||||
# these are not done yet
|
||||
src/translation/ja.json
|
||||
src/translation/pl.json
|
||||
src/translation/si.json
|
||||
src/translation/gl.json
|
||||
public/translation/ja.json
|
||||
public/translation/pl.json
|
||||
public/translation/si.json
|
||||
public/translation/gl.json
|
||||
public/translation/hr.json
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
{
|
||||
"node": true,
|
||||
"browser": true,
|
||||
"unused": true,
|
||||
"esversion": 6,
|
||||
"globalstrict": false,
|
||||
"predef": [
|
||||
"$",
|
||||
"angular",
|
||||
"async",
|
||||
"describe",
|
||||
"it",
|
||||
"before",
|
||||
"after",
|
||||
"require",
|
||||
"monaco",
|
||||
"Mimer",
|
||||
"ISTATES"
|
||||
]
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
The Cloudron Subscription license
|
||||
Copyright (c) 2022 Cloudron UG
|
||||
|
||||
With regard to the Cloudron Software:
|
||||
|
||||
This software and associated documentation files (the "Software") may only be
|
||||
used in production, if you (and any entity that you represent) have agreed to,
|
||||
and are in compliance with, the Cloudron Subscription Terms of Service, available
|
||||
at https://cloudron.io/legal/terms.html (the “Subscription Terms”), or other
|
||||
agreement governing the use of the Software, as agreed by you and Cloudron,
|
||||
and otherwise have a valid Cloudron Subscription. Subject to the foregoing sentence,
|
||||
you are free to modify this Software and publish patches to the Software. You agree
|
||||
that Subscription and/or its licensors (as applicable) retain all right, title and
|
||||
interest in and to all such modifications and/or patches, and all such modifications
|
||||
and/or patches may only be used, copied, modified, displayed, distributed, or otherwise
|
||||
exploited with a valid Cloudron subscription. Notwithstanding the foregoing, you may copy
|
||||
and modify the Software for development and testing purposes, without requiring a
|
||||
subscription. You agree that Cloudron and/or its licensors (as applicable) retain
|
||||
all right, title and interest in and to all such modifications. You are not
|
||||
granted any other rights beyond what is expressly stated herein. Subject to the
|
||||
foregoing, it is forbidden to copy, merge, publish, distribute, sublicense,
|
||||
and/or sell the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
For all third party components incorporated into the Cloudron Software, those
|
||||
components are licensed under the original license provided by the owner of the
|
||||
applicable component.
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
# Cloudron Dashboard
|
||||
|
||||
This is the front end code of Cloudron. The backend code is [here](https://git.cloudron.io/cloudron/box).
|
||||
|
||||
## Developing
|
||||
|
||||
* `npm install`
|
||||
* `gulp develop --api-origin=https://my.example.com`
|
||||
|
||||
## License
|
||||
|
||||
Please note that the Cloudron code is under a source-available license. This is not the same as an
|
||||
open source license but ensures the code is available for inspection (and hacking!).
|
||||
|
||||
## Contributions
|
||||
|
||||
Just to give a heads-up, we are a bit restrictive in merging changes. We are a small team and
|
||||
would like to keep our maintenance burden low. It might be best to first discuss features in the [forum](https://forum.cloudron.io),
|
||||
which also helps to determine how many other people will use it to justify maintenance for a feature.
|
||||
|
||||
@@ -9,43 +9,41 @@
|
||||
|
||||
<link id="favicon" href="/api/v1/cloudron/avatar" rel="icon" type="image/png">
|
||||
|
||||
<!-- Theme CSS -->
|
||||
<link type="text/css" rel="stylesheet" href="/theme.css">
|
||||
<!-- contains all thing already using import statement -->
|
||||
<script type="module" src="./src/modules.js"></script>
|
||||
|
||||
<!-- Fontawesome -->
|
||||
<link type="text/css" rel="stylesheet" href="/3rdparty/fontawesome/css/all.min.css?<%= revision %>"/>
|
||||
<!-- Theme CSS -->
|
||||
<link type="text/css" rel="stylesheet" href="./src/theme.scss">
|
||||
|
||||
<!-- jQuery-->
|
||||
<script type="text/javascript" src="/3rdparty/js/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="/js/jquery.min.js"></script>
|
||||
|
||||
<!-- async -->
|
||||
<script type="text/javascript" src="/3rdparty/js/async-3.2.0.min.js"></script>
|
||||
|
||||
<!-- Bootstrap Core JavaScript -->
|
||||
<script type="text/javascript" src="/3rdparty/js/bootstrap.min.js"></script>
|
||||
<script type="text/javascript" src="/js/async-3.2.0.min.js"></script>
|
||||
|
||||
<!-- Angularjs scripts -->
|
||||
<script type="text/javascript" src="/3rdparty/js/angular.min.js"></script>
|
||||
<script type="text/javascript" src="/3rdparty/js/angular-loader.min.js"></script>
|
||||
<script type="text/javascript" src="/3rdparty/js/angular-cookies.min.js"></script>
|
||||
<script type="text/javascript" src="/3rdparty/js/angular-md5.min.js"></script>
|
||||
<script type="text/javascript" src="/3rdparty/js/angular-ui-notification.js"></script>
|
||||
<script type="text/javascript" src="/3rdparty/js/autofill-event.js"></script>
|
||||
<script type="text/javascript" src="/js/angular.min.js"></script>
|
||||
<script type="text/javascript" src="/js/angular-loader.min.js"></script>
|
||||
<script type="text/javascript" src="/js/angular-cookies.min.js"></script>
|
||||
<script type="text/javascript" src="/js/angular-md5.min.js"></script>
|
||||
<script type="text/javascript" src="/js/angular-ui-notification.js"></script>
|
||||
|
||||
<!-- Angular directives for bootstrap https://angular-ui.github.io/bootstrap/ -->
|
||||
<script type="text/javascript" src="/3rdparty/js/ui-bootstrap-tpls-1.3.3.min.js"></script>
|
||||
<script type="text/javascript" src="/js/ui-bootstrap-tpls-1.3.3.min.js"></script>
|
||||
|
||||
<!-- Angular translate https://angular-translate.github.io/ -->
|
||||
<script type="text/javascript" src="/3rdparty/js/angular-translate.min.js?<%= revision %>"></script>
|
||||
<script type="text/javascript" src="/3rdparty/js/angular-translate-loader-static-files.min.js?<%= revision %>"></script>
|
||||
<script type="text/javascript" src="/3rdparty/js/angular-translate-storage-cookie.min.js?<%= revision %>"></script>
|
||||
<script type="text/javascript" src="/3rdparty/js/angular-translate-storage-local.min.js?<%= revision %>"></script>
|
||||
<script type="text/javascript" src="/js/angular-translate.min.js"></script>
|
||||
<script type="text/javascript" src="/js/angular-translate-loader-static-files.min.js"></script>
|
||||
<script type="text/javascript" src="/js/angular-translate-storage-cookie.min.js"></script>
|
||||
<script type="text/javascript" src="/js/angular-translate-storage-local.min.js"></script>
|
||||
|
||||
<!-- Showdown (markdown converter) -->
|
||||
<script type="text/javascript" src="/3rdparty/js/showdown-1.9.1.min.js?<%= revision %>"></script>
|
||||
<script type="text/javascript" src="/js/showdown-1.9.1.min.js"></script>
|
||||
|
||||
<!-- Setup Application -->
|
||||
<script type="text/javascript" src="/js/activation.js"></script>
|
||||
<script type="text/javascript" src="/js/activation.js?%VITE_CACHE_ID%"></script>
|
||||
<script type="text/javascript" src="/js/client.js?%VITE_CACHE_ID%"></script>
|
||||
<script type="text/javascript" src="/js/utils.js?%VITE_CACHE_ID%"></script>
|
||||
|
||||
</head>
|
||||
|
||||
14
dashboard/build.sh
Executable file
@@ -0,0 +1,14 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -eu
|
||||
|
||||
echo "=> Create timezones.js"
|
||||
./scripts/createTimezones.cjs ./public/js/timezones.js
|
||||
|
||||
echo "=> Build theme.css for oidc views"
|
||||
./node_modules/.bin/sass --quiet --pkg-importer=node ./src/theme.scss ./public/theme.css
|
||||
|
||||
export VITE_CACHE_ID=$(date +%s)
|
||||
|
||||
echo "=> Build the dashboard apps"
|
||||
./node_modules/.bin/vite build
|
||||
12
dashboard/develop.sh
Executable file
@@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -eu
|
||||
|
||||
echo "=> Set API origin"
|
||||
export VITE_API_ORIGIN="${DASHBOARD_DEVELOPMENT_ORIGIN}"
|
||||
|
||||
# only really used for prod builds to bust cache
|
||||
export VITE_CACHE_ID="develop"
|
||||
|
||||
echo "=> Run vite locally"
|
||||
npm run dev
|
||||
22
dashboard/eslint.config.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import globals from 'globals';
|
||||
import js from '@eslint/js';
|
||||
import pluginVue from 'eslint-plugin-vue';
|
||||
|
||||
export default [
|
||||
js.configs.recommended,
|
||||
...pluginVue.configs['flat/essential'],
|
||||
{
|
||||
files: ["**/*.js"],
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.browser,
|
||||
},
|
||||
ecmaVersion: 13,
|
||||
sourceType: 'module'
|
||||
},
|
||||
rules: {
|
||||
semi: "error",
|
||||
"prefer-const": "error"
|
||||
}
|
||||
}
|
||||
];
|
||||
@@ -1,217 +0,0 @@
|
||||
/* jslint node:true */
|
||||
|
||||
'use strict';
|
||||
|
||||
const argv = require('yargs').argv,
|
||||
concat = require('gulp-concat'),
|
||||
ejs = require('gulp-ejs'),
|
||||
execSync = require('child_process').execSync,
|
||||
fs = require('fs'),
|
||||
gulp = require('gulp'),
|
||||
sass = require('gulp-sass')(require('sass')),
|
||||
serve = require('gulp-serve'),
|
||||
sourcemaps = require('gulp-sourcemaps');
|
||||
|
||||
if (argv.help || argv.h) {
|
||||
console.log('Supported arguments for "gulp develop":');
|
||||
console.log(' --api-origin <cloudron api uri>');
|
||||
console.log(' --revision <revision>');
|
||||
console.log(' --appstore-console-origin <appstore console uri>');
|
||||
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const revision = argv.revision || '';
|
||||
|
||||
let apiOrigin = '';
|
||||
if (argv.apiOrigin) {
|
||||
if (argv.apiOrigin.indexOf('https://') === 0) apiOrigin = argv.apiOrigin;
|
||||
else apiOrigin = 'https://' + argv.apiOrigin;
|
||||
}
|
||||
|
||||
var appstore = {
|
||||
consoleOrigin: argv.appstoreConsoleOrigin || ''
|
||||
};
|
||||
|
||||
console.log();
|
||||
console.log('Cloudron API: %s', apiOrigin || 'default');
|
||||
console.log('Building for revision: %s', revision);
|
||||
console.log();
|
||||
console.log('Overriding appstore origin:');
|
||||
console.log(' Console: %s', appstore.consoleOrigin || 'no');
|
||||
console.log();
|
||||
|
||||
gulp.task('fontawesome', function () {
|
||||
return gulp.src('node_modules/@fortawesome/fontawesome-free/**/*')
|
||||
.pipe(gulp.dest('dist/3rdparty/fontawesome/'));
|
||||
});
|
||||
|
||||
gulp.task('noto-sans', function () {
|
||||
return gulp.src('node_modules/@fontsource/noto-sans/**/*')
|
||||
.pipe(gulp.dest('dist/3rdparty/noto-sans/'));
|
||||
});
|
||||
|
||||
gulp.task('bootstrap', function () {
|
||||
return gulp.src('node_modules/bootstrap-sass/assets/javascripts/bootstrap.min.js')
|
||||
.pipe(gulp.dest('dist/3rdparty/js'));
|
||||
});
|
||||
|
||||
gulp.task('moment', function () {
|
||||
return gulp.src('node_modules/moment/min/*')
|
||||
.pipe(gulp.dest('dist/3rdparty/js'));
|
||||
});
|
||||
|
||||
gulp.task('3rdparty-copy', function () {
|
||||
return gulp.src([
|
||||
'src/3rdparty/**/*.js',
|
||||
'src/3rdparty/**/*.map',
|
||||
'src/3rdparty/**/*.css',
|
||||
'src/3rdparty/**/*.otf',
|
||||
'src/3rdparty/**/*.eot',
|
||||
'src/3rdparty/**/*.svg',
|
||||
'src/3rdparty/**/*.gif',
|
||||
'src/3rdparty/**/*.ttf',
|
||||
'node_modules/chart.js/dist/chart.umd.js'
|
||||
]).pipe(gulp.dest('dist/3rdparty/'));
|
||||
});
|
||||
|
||||
gulp.task('3rdparty', gulp.series(['3rdparty-copy', 'moment', 'bootstrap', 'fontawesome', 'noto-sans']));
|
||||
|
||||
// --------------
|
||||
// JavaScript
|
||||
// --------------
|
||||
|
||||
gulp.task('js-index', function () {
|
||||
return gulp.src([
|
||||
'src/js/index.js',
|
||||
'src/js/client.js',
|
||||
'src/js/utils.js',
|
||||
'src/views/*.js'
|
||||
])
|
||||
.pipe(ejs({ apiOrigin: apiOrigin, revision: revision, appstore: appstore }, {}, { ext: '.js' }))
|
||||
.pipe(sourcemaps.init())
|
||||
.pipe(concat('index.js', { newLine: ';' }))
|
||||
.pipe(sourcemaps.write())
|
||||
.pipe(gulp.dest('dist/js'));
|
||||
});
|
||||
|
||||
gulp.task('js-passwordreset', function () {
|
||||
return gulp.src(['src/js/passwordreset.js', 'src/js/utils.js'])
|
||||
.pipe(ejs({ apiOrigin: apiOrigin, revision: revision, appstore: appstore }, {}, { ext: '.js' }))
|
||||
.pipe(sourcemaps.init())
|
||||
.pipe(concat('passwordreset.js', { newLine: ';' }))
|
||||
.pipe(sourcemaps.write())
|
||||
.pipe(gulp.dest('dist/js'));
|
||||
});
|
||||
|
||||
gulp.task('js-setupaccount', function () {
|
||||
return gulp.src(['src/js/setupaccount.js', 'src/js/utils.js'])
|
||||
.pipe(ejs({ apiOrigin: apiOrigin, revision: revision, appstore: appstore }, {}, { ext: '.js' }))
|
||||
.pipe(sourcemaps.init())
|
||||
.pipe(concat('setupaccount.js', { newLine: ';' }))
|
||||
.pipe(sourcemaps.write())
|
||||
.pipe(gulp.dest('dist/js'));
|
||||
});
|
||||
|
||||
gulp.task('js-activation', function () {
|
||||
return gulp.src(['src/js/activation.js', 'src/js/client.js', 'src/js/utils.js'])
|
||||
.pipe(ejs({ apiOrigin: apiOrigin, revision: revision, appstore: appstore }, {}, { ext: '.js' }))
|
||||
.pipe(sourcemaps.init())
|
||||
.pipe(concat('activation.js', { newLine: ';' }))
|
||||
.pipe(sourcemaps.write())
|
||||
.pipe(gulp.dest('dist/js'));
|
||||
});
|
||||
|
||||
gulp.task('js-setup', function () {
|
||||
return gulp.src(['src/js/setup.js', 'src/js/client.js', 'src/js/utils.js'])
|
||||
.pipe(ejs({ apiOrigin: apiOrigin, revision: revision, appstore: appstore }, {}, { ext: '.js' }))
|
||||
.pipe(sourcemaps.init())
|
||||
.pipe(concat('setup.js', { newLine: ';' }))
|
||||
.pipe(sourcemaps.write())
|
||||
.pipe(gulp.dest('dist/js'));
|
||||
});
|
||||
|
||||
gulp.task('js-restore', function () {
|
||||
return gulp.src(['src/js/restore.js', 'src/js/client.js', 'src/js/utils.js'])
|
||||
.pipe(ejs({ apiOrigin: apiOrigin, revision: revision, appstore: appstore }, {}, { ext: '.js' }))
|
||||
.pipe(sourcemaps.init())
|
||||
.pipe(concat('restore.js', { newLine: ';' }))
|
||||
.pipe(sourcemaps.write())
|
||||
.pipe(gulp.dest('dist/js'));
|
||||
});
|
||||
|
||||
gulp.task('js', gulp.series([ 'js-index', 'js-passwordreset', 'js-setupaccount', 'js-activation', 'js-setup', 'js-restore' ]));
|
||||
|
||||
// --------------
|
||||
// HTML
|
||||
// --------------
|
||||
|
||||
gulp.task('html-views', function () {
|
||||
return gulp.src('src/views/**/*.html').pipe(gulp.dest('dist/views'));
|
||||
});
|
||||
|
||||
gulp.task('html-raw', function () {
|
||||
return gulp.src('src/*.html').pipe(ejs({ apiOrigin: apiOrigin, revision: revision }, {}, { ext: '.html' })).pipe(gulp.dest('dist'));
|
||||
});
|
||||
|
||||
gulp.task('html', gulp.series(['html-views', 'html-raw']));
|
||||
|
||||
// --------------
|
||||
// CSS
|
||||
// --------------
|
||||
|
||||
gulp.task('css', function () {
|
||||
return gulp.src('src/*.scss')
|
||||
.pipe(sass({ includePaths: [
|
||||
'node_modules/bootstrap-sass/assets/stylesheets/',
|
||||
'node_modules/@fontsource/'
|
||||
]}).on('error', sass.logError))
|
||||
.pipe(gulp.dest('dist'));
|
||||
});
|
||||
|
||||
gulp.task('images', function () {
|
||||
return gulp.src('src/img/**')
|
||||
.pipe(gulp.dest('dist/img'));
|
||||
});
|
||||
|
||||
gulp.task('translation', function () {
|
||||
return gulp.src('src/translation/**')
|
||||
.pipe(gulp.dest('dist/translation'));
|
||||
});
|
||||
|
||||
gulp.task('timezones', function (done) {
|
||||
execSync('./scripts/createTimezones.js ./dist/js/timezones.js');
|
||||
done();
|
||||
});
|
||||
|
||||
// --------------
|
||||
// Utilities
|
||||
// --------------
|
||||
|
||||
gulp.task('clean', function (done) {
|
||||
fs.rm('dist', { recursive: true, force: true }, done);
|
||||
});
|
||||
|
||||
gulp.task('default', gulp.series(['clean', 'html', 'js', 'timezones', '3rdparty', 'translation', 'images', 'css']));
|
||||
|
||||
gulp.task('watch', function (done) {
|
||||
gulp.watch(['src/*.scss'], gulp.series(['css']));
|
||||
gulp.watch(['src/img/*'], gulp.series(['images']));
|
||||
gulp.watch(['src/translation/*'], gulp.series(['translation']));
|
||||
gulp.watch(['src/**/*.html'], gulp.series(['html']));
|
||||
gulp.watch(['src/views/*.html'], gulp.series(['html-views']));
|
||||
gulp.watch(['scripts/createTimezones.js', 'src/js/utils.js'], gulp.series(['timezones']));
|
||||
gulp.watch(['src/js/activation.js', 'src/js/client.js', 'src/js/utils.js'], gulp.series(['js-activation']));
|
||||
gulp.watch(['src/js/setup.js', 'src/js/client.js', 'src/js/utils.js'], gulp.series(['js-setup']));
|
||||
gulp.watch(['src/js/restore.js', 'src/js/client.js', 'src/js/utils.js'], gulp.series(['js-restore']));
|
||||
gulp.watch(['src/js/passwordreset.js', 'src/js/utils.js'], gulp.series(['js-passwordreset']));
|
||||
gulp.watch(['src/js/setupaccount.js', 'src/js/utils.js'], gulp.series(['js-setupaccount']));
|
||||
gulp.watch(['src/js/index.js', 'src/js/client.js', 'src/views/*.js', 'src/js/utils.js'], gulp.series(['js-index']));
|
||||
gulp.watch(['src/3rdparty/**/*'], gulp.series(['3rdparty']));
|
||||
done();
|
||||
});
|
||||
|
||||
gulp.task('serve', serve({ root: 'dist', port: 4000, hostname: '0.0.0.0' }));
|
||||
|
||||
gulp.task('develop', gulp.series(['default', 'watch', 'serve']));
|
||||
|
||||
211
dashboard/index.html
Normal file
@@ -0,0 +1,211 @@
|
||||
<!DOCTYPE html>
|
||||
<html ng-app="Application" ng-controller="MainController">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height" />
|
||||
|
||||
<!-- this gets changed once we get the config (because angular has not loaded yet, we see template string for a flash) -->
|
||||
<title>Cloudron Dashboard</title>
|
||||
<meta name="description" content="Cloudron Dashboard">
|
||||
|
||||
<link id="favicon" type="image/png" rel="icon" href="/api/v1/cloudron/avatar">
|
||||
<link rel="apple-touch-icon" href="/api/v1/cloudron/avatar">
|
||||
<link rel="icon" href="/api/v1/cloudron/avatar">
|
||||
|
||||
<!-- contains all thing already using import statement -->
|
||||
<script type="module" src="./src/modules.js"></script>
|
||||
|
||||
<!-- jQuery-->
|
||||
<script type="text/javascript" src="/js/jquery.min.js"></script>
|
||||
|
||||
<!-- CSS -->
|
||||
<link type="text/css" rel="stylesheet" href="/slick.css"/>
|
||||
<link type="text/css" rel="stylesheet" href="/angular-ui-notification.css"/>
|
||||
<link type="text/css" rel="stylesheet" href="./src/theme.scss">
|
||||
|
||||
<!-- async -->
|
||||
<script type="text/javascript" src="/js/async-3.2.0.min.js"></script>
|
||||
|
||||
<!-- Slick carousel -->
|
||||
<script type="text/javascript" src="/js/slick.js"></script>
|
||||
|
||||
<!-- Angularjs scripts -->
|
||||
<script type="text/javascript" src="/js/angular.min.js"></script>
|
||||
<script type="text/javascript" src="/js/angular-loader.min.js"></script>
|
||||
<script type="text/javascript" src="/js/angular-route.min.js"></script>
|
||||
<script type="text/javascript" src="/js/angular-cookies.min.js"></script>
|
||||
<script type="text/javascript" src="/js/angular-animate.min.js"></script>
|
||||
<script type="text/javascript" src="/js/angular-base64.min.js"></script>
|
||||
<script type="text/javascript" src="/js/angular-md5.min.js"></script>
|
||||
<script type="text/javascript" src="/js/angular-sanitize.min.js"></script>
|
||||
<script type="text/javascript" src="/js/angular-slick.min.js"></script>
|
||||
<script type="text/javascript" src="/js/angular-ui-notification.js"></script>
|
||||
<script type="text/javascript" src="/js/angular-fittext.min.js"></script>
|
||||
|
||||
<!-- Angular directives for bootstrap https://angular-ui.github.io/bootstrap/ -->
|
||||
<script type="text/javascript" src="/js/ui-bootstrap-tpls-1.3.3.min.js"></script>
|
||||
|
||||
<!-- Angular translate https://angular-translate.github.io/ -->
|
||||
<script type="text/javascript" src="/js/angular-translate.min.js"></script>
|
||||
<script type="text/javascript" src="/js/angular-translate-loader-static-files.min.js"></script>
|
||||
<script type="text/javascript" src="/js/angular-translate-storage-cookie.min.js"></script>
|
||||
<script type="text/javascript" src="/js/angular-translate-storage-local.min.js"></script>
|
||||
|
||||
<script type="text/javascript" src="/js/clipboard.min.js"></script>
|
||||
|
||||
<!-- Showdown (markdown converter) -->
|
||||
<script type="text/javascript" src="/js/showdown-1.9.1.min.js"></script>
|
||||
|
||||
<!-- Anugular Multiselect https://github.com/sebastianha/angular-bootstrap-multiselect -->
|
||||
<script type="text/javascript" src="/js/angular-bootstrap-multiselect.js"></script>
|
||||
|
||||
<!-- timezone list -->
|
||||
<script type="text/javascript" src="/js/timezones.js?%VITE_CACHE_ID%"></script>
|
||||
|
||||
<!-- Main Application -->
|
||||
<!-- for now we need this in a static non transformed index.js file -->
|
||||
<script> window.VITE_CACHE_ID = '%VITE_CACHE_ID%' </script>
|
||||
<script type="text/javascript" src="/js/index.js?%VITE_CACHE_ID%"></script>
|
||||
<script type="text/javascript" src="/js/client.js?%VITE_CACHE_ID%"></script>
|
||||
<script type="text/javascript" src="/js/utils.js?%VITE_CACHE_ID%"></script>
|
||||
|
||||
<script type="text/javascript" src="/views/app.js?%VITE_CACHE_ID%"></script>
|
||||
<script type="text/javascript" src="/views/apps.js?%VITE_CACHE_ID%"></script>
|
||||
<script type="text/javascript" src="/views/appstore.js?%VITE_CACHE_ID%"></script>
|
||||
<script type="text/javascript" src="/views/backups.js?%VITE_CACHE_ID%"></script>
|
||||
<script type="text/javascript" src="/views/branding.js?%VITE_CACHE_ID%"></script>
|
||||
<script type="text/javascript" src="/views/domains.js?%VITE_CACHE_ID%"></script>
|
||||
<script type="text/javascript" src="/views/email.js?%VITE_CACHE_ID%"></script>
|
||||
<script type="text/javascript" src="/views/emails-eventlog.js?%VITE_CACHE_ID%"></script>
|
||||
<script type="text/javascript" src="/views/emails.js?%VITE_CACHE_ID%"></script>
|
||||
<script type="text/javascript" src="/views/emails-queue.js?%VITE_CACHE_ID%"></script>
|
||||
<script type="text/javascript" src="/views/eventlog.js?%VITE_CACHE_ID%"></script>
|
||||
<script type="text/javascript" src="/views/network.js?%VITE_CACHE_ID%"></script>
|
||||
<script type="text/javascript" src="/views/notifications.js?%VITE_CACHE_ID%"></script>
|
||||
<script type="text/javascript" src="/views/profile.js?%VITE_CACHE_ID%"></script>
|
||||
<script type="text/javascript" src="/views/services.js?%VITE_CACHE_ID%"></script>
|
||||
<script type="text/javascript" src="/views/settings.js?%VITE_CACHE_ID%"></script>
|
||||
<script type="text/javascript" src="/views/support.js?%VITE_CACHE_ID%"></script>
|
||||
<script type="text/javascript" src="/views/system.js?%VITE_CACHE_ID%"></script>
|
||||
<script type="text/javascript" src="/views/user-directory.js?%VITE_CACHE_ID%"></script>
|
||||
<script type="text/javascript" src="/views/users.js?%VITE_CACHE_ID%"></script>
|
||||
<script type="text/javascript" src="/views/volumes.js?%VITE_CACHE_ID%"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<script type="text/ng-template" id="notification.html">
|
||||
<div class="ui-notification">
|
||||
<h3 ng-show="title" ng-bind-html="title"></h3>
|
||||
<div class="message">
|
||||
<a href="{{action}}" ng-show="action" ng-bind-html="message"></a>
|
||||
<span ng-hide="action" ng-bind-html="message"></span>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<a class="offline-banner animateMe" ng-show="client.offline" ng-cloak href="https://docs.cloudron.io/troubleshooting/" target="_blank"><i class="fa fa-circle-notch fa-spin"></i> {{ 'main.offline' | tr }}</a>
|
||||
|
||||
<!-- Modal reboot server -->
|
||||
<div class="modal fade" id="rebootModal" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title">{{ 'main.rebootDialog.title' | tr }}</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p class="text-bold">{{ 'main.rebootDialog.warning' | tr }}</p>
|
||||
<p>{{ 'main.rebootDialog.description' | tr }}</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">{{ 'main.dialog.cancel' | tr }}</button>
|
||||
<button type="button" class="btn btn-danger" ng-click="reboot.submit()" ng-disabled="reboot.busy"><i class="fa fa-circle-notch fa-spin" ng-show="reboot.busy"></i> {{ 'main.rebootDialog.rebootAction' | tr }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="mainContentContainer" class="animateMe ng-hide layout-root" ng-show="initialized">
|
||||
|
||||
<!-- Navigation -->
|
||||
<nav class="navbar navbar-default navbar-static-top shadow" role="navigation" style="margin-bottom: 0">
|
||||
<div class="container-fluid">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="navbar-brand navbar-brand-icon" href="#/"><img ng-src="{{ client.avatar }}" width="40" height="40"/></a>
|
||||
<a class="navbar-brand" href="#/">{{ config.cloudronName || 'Cloudron' }}</a>
|
||||
</div>
|
||||
<!-- /.navbar-header -->
|
||||
|
||||
<div class="collapse navbar-collapse">
|
||||
<ul class="nav navbar-nav navbar-right" ng-hide="hideNavBarActions">
|
||||
<li ng-show="user.isAtLeastOwner && (subscription.plan.id === 'free' || subscription.plan.id === 'expired')">
|
||||
<a ng-click="openSubscriptionSetup()" style="cursor: pointer">
|
||||
<span class="badge" ng-class="{'badge-danger': subscription.plan.id !== 'free', 'badge-success': subscription.plan.id === 'free' }">
|
||||
{{ subscription.plan.id === 'free' ? ('settings.appstoreAccount.subscriptionSetupAction' | tr) : ('settings.appstoreAccount.subscriptionReactivateAction' | tr) }}
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
<li ng-show="!user.isAtLeastOwner && subscription.plan.id === 'expired'">
|
||||
<a>
|
||||
<span class="badge badge-danger">Subscription Expired</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a ng-class="{ active: isActive('/apps')}" href="#/apps" ng-click="closeNavbar()"><i class="fa fa-grip fa-fw"></i> {{ 'apps.title' | tr }}</a>
|
||||
</li>
|
||||
<li ng-show="user.isAtLeastAdmin">
|
||||
<a ng-class="{ active: isActive('/appstore')}" href="#/appstore" ng-click="closeNavbar()"><i class="fa fa-cloud-download-alt fa-fw"></i> {{ 'appstore.title' | tr }}</a>
|
||||
</li>
|
||||
<li ng-show="user.isAtLeastUserManager">
|
||||
<a ng-class="{ active: isActive('/users')}" href="#/users" ng-click="closeNavbar()"><i class="fa fa-users fa-fw"></i> {{ 'main.navbar.users' | tr }}</a>
|
||||
</li>
|
||||
<li ng-show="user.isAtLeastAdmin">
|
||||
<a href="#/notifications" ng-click="closeNavbar()">
|
||||
<i class="fas fa-bell" ng-show="notificationCount"></i>
|
||||
<i class="far fa-bell" ng-hide="notificationCount"></i>
|
||||
<span class="badge badge-danger" ng-show="notificationCount">{{ notificationCount === 100 ? '100+' : notificationCount }}</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a href="" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"><img ng-src="{{user.avatarUrl}}" style="width: 24px; height: 24px;"/> {{user.username}} <span class="caret"></span></a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li><a href="#/profile" ng-click="closeNavbar()"><i class="fa fa-user fa-fw"></i> {{ 'profile.title' | tr }}</a></li>
|
||||
<li ng-show="user.isAtLeastMailManager" class="divider"></li>
|
||||
<li ng-show="user.isAtLeastAdmin"><a href="#/backups" ng-click="closeNavbar()"><i class="fa fa-archive fa-fw"></i> {{ 'backups.title' | tr }}</a></li>
|
||||
<li ng-show="user.isAtLeastAdmin"><a href="#/branding" ng-click="closeNavbar()"><i class="fa fa-passport fa-fw"></i> {{ 'branding.title' | tr }}</a></li>
|
||||
<li ng-show="user.isAtLeastAdmin"><a href="#/domains" ng-click="closeNavbar()"><i class="fa fa-globe fa-fw"></i> {{ 'domains.title' | tr }}</a></li>
|
||||
<li ng-show="user.isAtLeastMailManager"><a href="#/email" ng-click="closeNavbar()"><i class="fa fa-envelope fa-fw"></i> {{ 'emails.title' | tr }}</a></li>
|
||||
<li ng-show="user.isAtLeastAdmin"><a href="#/eventlog" ng-click="closeNavbar()"><i class="fa fa-list-alt fa-fw"></i> {{ 'eventlog.title' | tr }}</a></li>
|
||||
<li ng-show="user.isAtLeastAdmin"><a href="#/network" ng-click="closeNavbar()"><i class="fas fa-network-wired fa-fw"></i> {{ 'network.title' | tr }}</a></li>
|
||||
<li ng-show="user.isAtLeastAdmin"><a href="#/services" ng-click="closeNavbar()"><i class="fa fa-cogs fa-fw"></i> {{ 'services.title' | tr }}</a></li>
|
||||
<li ng-show="user.isAtLeastAdmin"><a href="#/settings" ng-click="closeNavbar()"><i class="fa fa-wrench fa-fw"></i> {{ 'settings.title' | tr }}</a></li>
|
||||
<li ng-show="user.isAtLeastAdmin"><a href="#/user-directory" ng-click="closeNavbar()"><i class="fa fa-users-gear fa-fw"></i> {{ 'users.title' | tr }}</a></li>
|
||||
<li ng-show="user.isAtLeastAdmin"><a href="#/volumes" ng-click="closeNavbar()"><i class="fa fa-hdd fa-fw"></i> {{ 'volumes.title' | tr }}</a></li>
|
||||
<li ng-show="user.isAtLeastAdmin" class="divider"></li>
|
||||
<li ng-show="user.isAtLeastOwner"><a href="#/support" ng-click="closeNavbar()"><i class="fa fa-comment fa-fw"></i> {{ 'support.title' | tr }}</a></li>
|
||||
<li ng-show="user.isAtLeastAdmin"><a href="#/system" ng-click="closeNavbar()"><i class="fa fa-chart-area fa-fw"></i> {{ 'system.title' | tr }}</a></li>
|
||||
<li class="divider"></li>
|
||||
<li><a href="" ng-click="logout($event)"><i class="fa fa-sign-out-alt fa-fw"></i> {{ 'main.logout' | tr }}</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div ng-view id="ng-view" class="layout-content"></div>
|
||||
|
||||
<footer class="text-center ng-cloak">
|
||||
<span class="text-muted" ng-bind-html="config.footer | markdown2html"></span>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
12891
dashboard/package-lock.json
generated
@@ -1,35 +1,33 @@
|
||||
{
|
||||
"name": "dashboard",
|
||||
"version": "1.0.0",
|
||||
"description": "[Cloudron](https://cloudron.io) is the best way to run apps on your server.",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"update-translations": "curl https://translate.cloudron.io/api/components/cloudron/dashboard/file/ -o lang.zip && unzip -jo lang.zip -d ./src/translation/ && rm lang.zip"
|
||||
"update-translations": "curl https://translate.cloudron.io/api/components/cloudron/dashboard/file/ -o lang.zip && unzip -jo lang.zip -d ./public/translation/ && rm lang.zip",
|
||||
"dev": "vite --strictPort --port 4000",
|
||||
"build": "vite build"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "ssh://git@git.cloudron.io:6000/cloudron/dashboard.git"
|
||||
},
|
||||
"author": "",
|
||||
"license": "SEE LICENSE IN LICENSE",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@fontsource/noto-sans": "^5.0.21",
|
||||
"@fortawesome/fontawesome-free": "^6.5.2",
|
||||
"@eslint/js": "^9.16.0",
|
||||
"@fontsource/noto-sans": "^5.1.0",
|
||||
"@fortawesome/fontawesome-free": "^6.7.1",
|
||||
"@vitejs/plugin-vue": "^5.2.1",
|
||||
"@xterm/addon-attach": "^0.11.0",
|
||||
"@xterm/addon-fit": "^0.10.0",
|
||||
"@xterm/xterm": "^5.5.0",
|
||||
"anser": "^2.3.0",
|
||||
"bootstrap-sass": "^3.4.3",
|
||||
"chart.js": "^4.4.2",
|
||||
"gulp": "^4.0.2",
|
||||
"gulp-concat": "^2.6.1",
|
||||
"gulp-ejs": "^5.1.0",
|
||||
"gulp-sass": "^5.1.0",
|
||||
"gulp-serve": "^1.4.0",
|
||||
"gulp-sourcemaps": "^3.0.0",
|
||||
"chart.js": "^4.4.7",
|
||||
"eslint-plugin-vue": "^9.32.0",
|
||||
"filesize": "^10.1.6",
|
||||
"jquery": "^3.7.1",
|
||||
"marked": "^15.0.3",
|
||||
"moment": "^2.30.1",
|
||||
"sass": "^1.75.0",
|
||||
"yargs": "^17.7.2"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"env": {
|
||||
"browser": true
|
||||
}
|
||||
"pankow": "^2.4.2",
|
||||
"pankow-viewers": "^1.0.11",
|
||||
"sass": "^1.82.0",
|
||||
"vite": "^6.0.3",
|
||||
"vue": "^3.5.13",
|
||||
"vue-i18n": "^10.0.5",
|
||||
"vue-router": "^4.5.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,53 +1,47 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height" />
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src <%= apiOrigin %> 'unsafe-inline' 'unsafe-eval' 'self'; img-src <%= apiOrigin %> 'self'" />
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height" />
|
||||
|
||||
<!-- this gets changed once we get the status (because angular has not loaded yet, we see template string for a flash) -->
|
||||
<title>Cloudron Password Reset</title>
|
||||
<meta name="description" content="Cloudron Password Reset">
|
||||
<!-- this gets changed once we get the status (because angular has not loaded yet, we see template string for a flash) -->
|
||||
<title>Cloudron Password Reset</title>
|
||||
<meta name="description" content="Cloudron Password Reset">
|
||||
|
||||
<link id="favicon" href="<%= apiOrigin %>/api/v1/cloudron/avatar" rel="icon" type="image/png">
|
||||
<link id="favicon" href="/api/v1/cloudron/avatar" rel="icon" type="image/png">
|
||||
|
||||
<!-- Theme CSS -->
|
||||
<link type="text/css" rel="stylesheet" href="/theme.css?<%= revision %>">
|
||||
<!-- contains all thing already using import statement -->
|
||||
<script type="module" src="./src/modules.js"></script>
|
||||
|
||||
<!-- Fontawesome -->
|
||||
<link type="text/css" rel="stylesheet" href="/3rdparty/fontawesome/css/all.min.css?<%= revision %>"/>
|
||||
<!-- Theme CSS -->
|
||||
<link type="text/css" rel="stylesheet" href="./src/theme.scss">
|
||||
|
||||
<!-- jQuery-->
|
||||
<script type="text/javascript" src="/3rdparty/js/jquery.min.js?<%= revision %>"></script>
|
||||
<!-- jQuery-->
|
||||
<script type="text/javascript" src="/js/jquery.min.js"></script>
|
||||
|
||||
<!-- async -->
|
||||
<script type="text/javascript" src="/3rdparty/js/async-3.2.0.min.js?<%= revision %>"></script>
|
||||
<!-- async -->
|
||||
<script type="text/javascript" src="/js/async-3.2.0.min.js"></script>
|
||||
|
||||
<!-- Bootstrap Core JavaScript -->
|
||||
<script type="text/javascript" src="/3rdparty/js/bootstrap.min.js?<%= revision %>"></script>
|
||||
<!-- Showdown (markdown converter) -->
|
||||
<script type="text/javascript" src="/js/showdown-1.9.1.min.js"></script>
|
||||
|
||||
<!-- Showdown (markdown converter) -->
|
||||
<script type="text/javascript" src="/3rdparty/js/showdown-1.9.1.min.js?<%= revision %>"></script>
|
||||
<!-- Angularjs scripts -->
|
||||
<script type="text/javascript" src="/js/angular.min.js"></script>
|
||||
<script type="text/javascript" src="/js/angular-loader.min.js"></script>
|
||||
<script type="text/javascript" src="/js/angular-cookies.min.js"></script>
|
||||
|
||||
<!-- Angularjs scripts -->
|
||||
<script type="text/javascript" src="/3rdparty/js/angular.min.js?<%= revision %>"></script>
|
||||
<script type="text/javascript" src="/3rdparty/js/angular-loader.min.js?<%= revision %>"></script>
|
||||
<!-- <script type="text/javascript" src="/3rdparty/js/angular-md5.min.js"></script> -->
|
||||
<!-- <script type="text/javascript" src="/3rdparty/js/angular-ui-notification.js"></script> -->
|
||||
<script type="text/javascript" src="/3rdparty/js/angular-cookies.min.js?<%= revision %>"></script>
|
||||
<script type="text/javascript" src="/3rdparty/js/autofill-event.js?<%= revision %>"></script>
|
||||
<!-- Angular directives for bootstrap https://angular-ui.github.io/bootstrap/ -->
|
||||
<script type="text/javascript" src="/js/ui-bootstrap-tpls-1.3.3.min.js"></script>
|
||||
|
||||
<!-- Angular directives for bootstrap https://angular-ui.github.io/bootstrap/ -->
|
||||
<script type="text/javascript" src="/3rdparty/js/ui-bootstrap-tpls-1.3.3.min.js?<%= revision %>"></script>
|
||||
<!-- Angular translate https://angular-translate.github.io/ -->
|
||||
<script type="text/javascript" src="/js/angular-translate.min.js"></script>
|
||||
<script type="text/javascript" src="/js/angular-translate-loader-static-files.min.js"></script>
|
||||
<script type="text/javascript" src="/js/angular-translate-storage-cookie.min.js"></script>
|
||||
<script type="text/javascript" src="/js/angular-translate-storage-local.min.js"></script>
|
||||
|
||||
<!-- Angular translate https://angular-translate.github.io/ -->
|
||||
<script type="text/javascript" src="/3rdparty/js/angular-translate.min.js?<%= revision %>"></script>
|
||||
<script type="text/javascript" src="/3rdparty/js/angular-translate-loader-static-files.min.js?<%= revision %>"></script>
|
||||
<script type="text/javascript" src="/3rdparty/js/angular-translate-storage-cookie.min.js?<%= revision %>"></script>
|
||||
<script type="text/javascript" src="/3rdparty/js/angular-translate-storage-local.min.js?<%= revision %>"></script>
|
||||
|
||||
<!-- Setup Application -->
|
||||
<script type="text/javascript" src="/js/passwordreset.js?<%= revision %>"></script>
|
||||
<!-- Setup Application -->
|
||||
<script type="text/javascript" src="/js/passwordreset.js?%VITE_CACHE_ID%"></script>
|
||||
<script type="text/javascript" src="/js/utils.js?%VITE_CACHE_ID%"></script>
|
||||
|
||||
</head>
|
||||
|
||||
@@ -59,7 +53,7 @@
|
||||
<div class="card" style="padding: 20px; margin-top: 100px; max-width: 620px;">
|
||||
<div class="row">
|
||||
<div class="col-md-12" style="text-align: center;">
|
||||
<img width="128" height="128" style="margin-top: -84px" src="<%= apiOrigin %>/api/v1/cloudron/avatar"/>
|
||||
<img width="128" height="128" style="margin-top: -84px" src="/api/v1/cloudron/avatar"/>
|
||||
<br/>
|
||||
<h2>{{ 'passwordReset.title' | tr }}</h2>
|
||||
</div>
|
||||
@@ -87,7 +81,7 @@
|
||||
<div class="card" style="padding: 20px; margin-top: 100px; max-width: 620px;">
|
||||
<div class="row">
|
||||
<div class="col-md-12" style="text-align: center;">
|
||||
<img width="128" height="128" style="margin-top: -84px" src="<%= apiOrigin %>/api/v1/cloudron/avatar"/>
|
||||
<img width="128" height="128" style="margin-top: -84px" src="/api/v1/cloudron/avatar"/>
|
||||
<br/>
|
||||
<h2 ng-hide="error">{{ 'passwordReset.emailSent.title' | tr }}</h2>
|
||||
<h4 ng-show="error" class="has-error">{{ error }}</h4>
|
||||
@@ -102,7 +96,7 @@
|
||||
<div class="card" style="padding: 20px; margin-top: 100px; max-width: 620px;">
|
||||
<div class="row">
|
||||
<div class="col-md-12" style="text-align: center;">
|
||||
<img width="128" height="128" style="margin-top: -84px" src="<%= apiOrigin %>/api/v1/cloudron/avatar"/>
|
||||
<img width="128" height="128" style="margin-top: -84px" src="/api/v1/cloudron/avatar"/>
|
||||
<br/>
|
||||
<h2>{{ 'passwordReset.newPassword.title' | tr }}</h2>
|
||||
</div>
|
||||
@@ -150,7 +144,7 @@
|
||||
<div class="card" style="padding: 20px; margin-top: 100px; max-width: 620px;">
|
||||
<div class="row">
|
||||
<div class="col-md-12" style="text-align: center;">
|
||||
<img width="128" height="128" style="margin-top: -84px" src="<%= apiOrigin %>/api/v1/cloudron/avatar"/>
|
||||
<img width="128" height="128" style="margin-top: -84px" src="/api/v1/cloudron/avatar"/>
|
||||
<br/>
|
||||
<h2>{{ 'passwordReset.success.title' | tr }}</h2>
|
||||
<br/>
|
||||
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
BIN
dashboard/public/img/avatar-default-symbolic.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 7.8 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
@@ -1,14 +1,13 @@
|
||||
'use strict';
|
||||
|
||||
/* global angular, window, document, localStorage, redirectIfNeeded */
|
||||
/* global $ */
|
||||
/* global $, angular, redirectIfNeeded */
|
||||
|
||||
// create main application module
|
||||
var app = angular.module('Application', ['pascalprecht.translate', 'ngCookies', 'angular-md5', 'ui-notification', 'ui.bootstrap']);
|
||||
|
||||
app.controller('SetupController', ['$scope', 'Client', function ($scope, Client) {
|
||||
// Stupid angular location provider either wants html5 location mode or not, do the query parsing on my own
|
||||
var search = decodeURIComponent(window.location.search).slice(1).split('&').map(function (item) { return item.split('='); }).reduce(function (o, k) { o[k[0]] = k[1]; return o; }, {});
|
||||
const search = decodeURIComponent(window.location.search).slice(1).split('&').map(function (item) { return item.split('='); }).reduce(function (o, k) { o[k[0]] = k[1]; return o; }, {});
|
||||
|
||||
$scope.client = Client;
|
||||
$scope.view = '';
|
||||
@@ -1,26 +1,23 @@
|
||||
'use strict';
|
||||
|
||||
/* global $ */
|
||||
/* global angular */
|
||||
/* global EventSource */
|
||||
/* global async */
|
||||
/* global $, angular, async */
|
||||
|
||||
// keep in sync with box/src/notfications.js
|
||||
const NOTIFICATION_TYPES = {
|
||||
ALERT_CLOUDRON_INSTALLED: 'cloudronInstalled',
|
||||
ALERT_CLOUDRON_UPDATED: 'cloudronUpdated',
|
||||
ALERT_CLOUDRON_UPDATE_FAILED: 'cloudronUpdateFailed',
|
||||
ALERT_CERTIFICATE_RENEWAL_FAILED: 'certificateRenewalFailed',
|
||||
ALERT_BACKUP_CONFIG: 'backupConfig',
|
||||
ALERT_DISK_SPACE: 'diskSpace',
|
||||
ALERT_MAIL_STATUS: 'mailStatus',
|
||||
ALERT_REBOOT: 'reboot',
|
||||
ALERT_BOX_UPDATE: 'boxUpdate',
|
||||
ALERT_UPDATE_UBUNTU: 'ubuntuUpdate',
|
||||
ALERT_MANUAL_APP_UPDATE: 'manualAppUpdate',
|
||||
ALERT_APP_OOM: 'appOutOfMemory',
|
||||
ALERT_APP_UPDATED: 'appUpdated',
|
||||
ALERT_BACKUP_FAILED: 'backupFailed',
|
||||
CLOUDRON_INSTALLED: 'cloudronInstalled',
|
||||
CLOUDRON_UPDATED: 'cloudronUpdated',
|
||||
CLOUDRON_UPDATE_FAILED: 'cloudronUpdateFailed',
|
||||
CERTIFICATE_RENEWAL_FAILED: 'certificateRenewalFailed',
|
||||
BACKUP_CONFIG: 'backupConfig',
|
||||
DISK_SPACE: 'diskSpace',
|
||||
MAIL_STATUS: 'mailStatus',
|
||||
REBOOT: 'reboot',
|
||||
BOX_UPDATE: 'boxUpdate',
|
||||
UPDATE_UBUNTU: 'ubuntuUpdate',
|
||||
MANUAL_APP_UPDATE: 'manualAppUpdate',
|
||||
APP_OOM: 'appOutOfMemory',
|
||||
APP_UPDATED: 'appUpdated',
|
||||
BACKUP_FAILED: 'backupFailed',
|
||||
};
|
||||
|
||||
// keep in sync with box/src/apps.js
|
||||
@@ -167,10 +164,17 @@ const REGIONS_WASABI = [
|
||||
{ name: 'Virginia (US East 2)', value: 'https://s3.us-east-2.wasabisys.com' }
|
||||
];
|
||||
|
||||
const REGIONS_HETZNER = [
|
||||
{ name: 'Falkenstein (FSN1)', value: 'https://fsn1.your-objectstorage.com' },
|
||||
{ name: 'Helsinki (HEL1)', value: 'https://hel1.your-objectstorage.com' },
|
||||
{ name: 'Nuremberg (NBG1)', value: 'https://nbg1.your-objectstorage.com' }
|
||||
];
|
||||
|
||||
// https://docs.digitalocean.com/products/platform/availability-matrix/
|
||||
const REGIONS_DIGITALOCEAN = [
|
||||
{ name: 'AMS3', value: 'https://ams3.digitaloceanspaces.com' },
|
||||
{ name: 'FRA1', value: 'https://fra1.digitaloceanspaces.com' },
|
||||
{ name: 'LON1', value: 'https://lon1.digitaloceanspaces.com' },
|
||||
{ name: 'NYC3', value: 'https://nyc3.digitaloceanspaces.com' },
|
||||
{ name: 'SFO2', value: 'https://sfo2.digitaloceanspaces.com' },
|
||||
{ name: 'SFO3', value: 'https://sfo3.digitaloceanspaces.com' },
|
||||
@@ -181,6 +185,7 @@ const REGIONS_DIGITALOCEAN = [
|
||||
// https://www.exoscale.com/datacenters/
|
||||
const REGIONS_EXOSCALE = [
|
||||
{ name: 'Vienna (AT-VIE-1)', value: 'https://sos-at-vie-1.exo.io' },
|
||||
{ name: 'Vienna (AT-VIE-2)', value: 'https://sos-at-vie-2.exo.io' },
|
||||
{ name: 'Sofia (BG-SOF-1)', value: 'https://sos-bg-sof-1.exo.io' },
|
||||
{ name: 'Zurich (CH-DK-2)', value: 'https://sos-ch-dk-2.exo.io' },
|
||||
{ name: 'Geneva (CH-GVA-2)', value: 'https://sos-ch-gva-2.exo.io' },
|
||||
@@ -240,9 +245,10 @@ const ENDPOINTS_OVH = [
|
||||
|
||||
// https://docs.ionos.com/cloud/managed-services/s3-object-storage/endpoints
|
||||
const REGIONS_IONOS = [
|
||||
{ name: 'Frankfurt (DE)', value: 'https://s3-de-central.profitbricks.com', region: 's3-de-central' }, // default
|
||||
{ name: 'Berlin (eu-central-2)', value: 'https://s3-eu-central-2.ionoscloud.com', region: 'eu-central-2' }, // default
|
||||
{ name: 'Logrono (eu-south-2)', value: 'https://s3-eu-south-2.ionoscloud.com', region: 'eu-south-2' }, // default
|
||||
{ name: 'Berlin (eu-central-3)', value: 'https://s3.eu-central-3.ionoscloud.com', region: 'de' }, // default. contract-owned
|
||||
{ name: 'Frankfurt (DE)', value: 'https://s3.eu-central-1.ionoscloud.com', region: 'de' },
|
||||
{ name: 'Berlin (eu-central-2)', value: 'https://s3-eu-central-2.ionoscloud.com', region: 'eu-central-2' },
|
||||
{ name: 'Logrono (eu-south-2)', value: 'https://s3-eu-south-2.ionoscloud.com', region: 'eu-south-2' },
|
||||
];
|
||||
|
||||
// this is not used anywhere because upcloud needs endpoint URL. we detect region from the URL (https://upcloud.com/data-centres)
|
||||
@@ -289,6 +295,7 @@ const STORAGE_PROVIDERS = [
|
||||
{ name: 'Filesystem', value: 'filesystem' },
|
||||
{ name: 'Filesystem (Mountpoint)', value: 'mountpoint' }, // legacy
|
||||
{ name: 'Google Cloud Storage', value: 'gcs' },
|
||||
{ name: 'Hetzner Object Storage', value: 'hetzner-objectstorage' },
|
||||
{ name: 'IDrive e2', value: 'idrive-e2' },
|
||||
{ name: 'IONOS (Profitbricks)', value: 'ionos-objectstorage' },
|
||||
{ name: 'Linode Object Storage', value: 'linode-objectstorage' },
|
||||
@@ -420,7 +427,7 @@ angular.module('Application').filter('markdown2html', function () {
|
||||
angular.module('Application').config(['$translateProvider', function ($translateProvider) {
|
||||
$translateProvider.useStaticFilesLoader({
|
||||
prefix: 'translation/',
|
||||
suffix: '.json?' + '<%= revision %>'
|
||||
suffix: '.json'
|
||||
});
|
||||
$translateProvider.useLocalStorage();
|
||||
$translateProvider.preferredLanguage('en');
|
||||
@@ -468,8 +475,6 @@ function redirectIfNeeded(status, currentView) {
|
||||
return false;
|
||||
}
|
||||
|
||||
console.log(status, currentView);
|
||||
|
||||
if (status.activated) {
|
||||
console.log('Already activated');
|
||||
if (currentView === 'dashboard') {
|
||||
@@ -615,21 +620,6 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
|
||||
.error(defaultErrorHandler(callback));
|
||||
}
|
||||
|
||||
function head(url, config, callback) {
|
||||
if (arguments.length !== 3) {
|
||||
console.error('HEAD', arguments);
|
||||
throw('Wrong number of arguments');
|
||||
}
|
||||
|
||||
config = config || {};
|
||||
config.headers = config.headers || {};
|
||||
config.headers.Authorization = 'Bearer ' + token;
|
||||
|
||||
return $http.head(client.apiOrigin + url, config)
|
||||
.success(defaultSuccessHandler(callback))
|
||||
.error(defaultErrorHandler(callback));
|
||||
}
|
||||
|
||||
function post(url, data, config, callback) {
|
||||
if (arguments.length !== 4) {
|
||||
console.error('POST', arguments);
|
||||
@@ -691,7 +681,8 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
|
||||
source: null,
|
||||
avatarUrl: null,
|
||||
avatarType: null,
|
||||
hasBackgroundImage: false
|
||||
hasBackgroundImage: false,
|
||||
notificationConfig: []
|
||||
};
|
||||
this._config = {
|
||||
consoleServerOrigin: null,
|
||||
@@ -707,7 +698,7 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
|
||||
this._installedAppsById = {};
|
||||
this._appTags = [];
|
||||
// window.location fallback for websocket connections which do not have relative uris
|
||||
this.apiOrigin = '<%= apiOrigin %>' || window.location.origin;
|
||||
this.apiOrigin = window.cloudronApiOrigin || window.location.origin;
|
||||
this.avatar = '';
|
||||
this.background = '';
|
||||
this._availableLanguages = ['en'];
|
||||
@@ -733,7 +724,7 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
|
||||
// this happens mostly if the box crashes
|
||||
if (message === 'Empty message or object') {
|
||||
message = 'Got empty response. Click to check the server logs.';
|
||||
action = action || '/frontend/logs.html?id=box';
|
||||
action = action || '/logs.html?id=box';
|
||||
}
|
||||
|
||||
this.notify('Cloudron Error', message, true, 'error', action);
|
||||
@@ -743,7 +734,7 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
|
||||
Client.prototype.initError = function (error, initFunction) {
|
||||
console.error('Application startup error', error);
|
||||
|
||||
$timeout(initFunction, 5000); // we will try to re-init the app
|
||||
// $timeout(initFunction, 5000); // we will try to re-init the app
|
||||
};
|
||||
|
||||
Client.prototype.clearNotifications = function () {
|
||||
@@ -823,6 +814,7 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
|
||||
this._userInfo.avatarUrl = userInfo.avatarUrl + '?ts=' + Date.now(); // we add the timestamp to avoid caching
|
||||
this._userInfo.avatarType = userInfo.avatarType;
|
||||
this._userInfo.hasBackgroundImage = userInfo.hasBackgroundImage;
|
||||
this._userInfo.notificationConfig = userInfo.notificationConfig;
|
||||
this._userInfo.isAtLeastOwner = [ ROLES.OWNER ].indexOf(userInfo.role) !== -1;
|
||||
this._userInfo.isAtLeastAdmin = [ ROLES.OWNER, ROLES.ADMIN ].indexOf(userInfo.role) !== -1;
|
||||
this._userInfo.isAtLeastMailManager = [ ROLES.OWNER, ROLES.ADMIN, ROLES.MAIL_MANAGER ].indexOf(userInfo.role) !== -1;
|
||||
@@ -834,9 +826,9 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
|
||||
|
||||
angular.copy(config, this._config);
|
||||
|
||||
<% if (appstore.consoleOrigin) { -%>
|
||||
this._config.consoleServerOrigin = '<%= appstore.consoleOrigin %>';
|
||||
<% } -%>
|
||||
// <% if (appstore.consoleOrigin) { -%>
|
||||
// this._config.consoleServerOrigin = '<%= appstore.consoleOrigin %>';
|
||||
// <% } -%>
|
||||
|
||||
this._configListener.forEach(function (callback) {
|
||||
callback(that._config);
|
||||
@@ -951,7 +943,7 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
|
||||
});
|
||||
};
|
||||
|
||||
Client.prototype.installApp = function (id, manifest, title, config, callback) {
|
||||
Client.prototype.installApp = function (id, manifest, config, callback) {
|
||||
var data = {
|
||||
appStoreId: id + '@' + manifest.version,
|
||||
subdomain: config.subdomain,
|
||||
@@ -963,10 +955,11 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
|
||||
key: config.key,
|
||||
sso: config.sso,
|
||||
overwriteDns: config.overwriteDns,
|
||||
upstreamUri: config.upstreamUri
|
||||
upstreamUri: config.upstreamUri,
|
||||
backupId: config.backupId // when restoring from archive
|
||||
};
|
||||
|
||||
post('/api/v1/apps/install', data, null, function (error, data, status) {
|
||||
post('/api/v1/apps', data, null, function (error, data, status) {
|
||||
if (error) return callback(error);
|
||||
if (status !== 202) return callback(new ClientError(status, data));
|
||||
|
||||
@@ -1014,6 +1007,17 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
|
||||
});
|
||||
};
|
||||
|
||||
Client.prototype.archiveApp = function (appId, backupId, callback) {
|
||||
var data = { backupId: backupId };
|
||||
|
||||
post('/api/v1/apps/' + appId + '/archive', data, null, function (error, data, status) {
|
||||
if (error) return callback(error);
|
||||
if (status !== 202) return callback(new ClientError(status, data));
|
||||
|
||||
callback(null);
|
||||
});
|
||||
};
|
||||
|
||||
Client.prototype.uninstallApp = function (appId, callback) {
|
||||
var data = {};
|
||||
|
||||
@@ -1399,8 +1403,6 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
|
||||
};
|
||||
|
||||
Client.prototype.getUpdateInfo = function (callback) {
|
||||
if (!this._userInfo.isAtLeastAdmin) return callback(new Error('Not allowed'));
|
||||
|
||||
get('/api/v1/updater/updates', null, function (error, data, status) {
|
||||
if (error) return callback(error);
|
||||
if (status !== 200) return callback(new ClientError(status, data));
|
||||
@@ -1499,6 +1501,41 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
|
||||
});
|
||||
};
|
||||
|
||||
Client.prototype.listArchives = function (callback) {
|
||||
var config = {
|
||||
params: {
|
||||
page: 1,
|
||||
per_page: 100
|
||||
}
|
||||
};
|
||||
|
||||
get('/api/v1/archives', config, function (error, data, status) {
|
||||
if (error) return callback(error);
|
||||
if (status !== 200) return callback(new ClientError(status, data));
|
||||
|
||||
callback(null, data.archives);
|
||||
});
|
||||
};
|
||||
|
||||
Client.prototype.deleteArchive = function (id, callback) {
|
||||
del('/api/v1/archives/' + id, null, function (error, data, status) {
|
||||
if (error) return callback(error);
|
||||
if (status !== 204) return callback(new ClientError(status, data));
|
||||
|
||||
callback(null);
|
||||
});
|
||||
};
|
||||
|
||||
Client.prototype.unarchiveApp = function (archiveId, data, callback) {
|
||||
post('/api/v1/archives/' + archiveId + '/unarchive', data, null, function (error, data, status) {
|
||||
if (error) return callback(error);
|
||||
if (status !== 202) return callback(new ClientError(status, data));
|
||||
|
||||
callback(null, data);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
Client.prototype.getBackups = function (callback) {
|
||||
var page = 1;
|
||||
var perPage = 100;
|
||||
@@ -2327,7 +2364,7 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
|
||||
Client.prototype.updateApplink = function (id, data, callback) {
|
||||
post('/api/v1/applinks/' + id, data, null, function (error, data, status) {
|
||||
if (error) return callback(error);
|
||||
if (status !== 202) return callback(new ClientError(status, data));
|
||||
if (status !== 200) return callback(new ClientError(status, data));
|
||||
|
||||
callback(null);
|
||||
});
|
||||
@@ -2422,6 +2459,15 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
|
||||
});
|
||||
};
|
||||
|
||||
Client.prototype.setNotificationConfig = function (notificationConfig, callback) {
|
||||
post('/api/v1/profile/notification_config', { notificationConfig }, null, function (error, data, status) {
|
||||
if (error) return callback(error);
|
||||
if (status !== 204) return callback(new ClientError(status, data));
|
||||
|
||||
callback(null, data);
|
||||
});
|
||||
};
|
||||
|
||||
Client.prototype.setProfileEmail = function (email, password, callback) {
|
||||
post('/api/v1/profile/email', { email: email, password: password }, null, function (error, data, status) {
|
||||
if (error) return callback(error);
|
||||
@@ -2643,9 +2689,10 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
|
||||
this.config(function (error, result) {
|
||||
if (error) return callback(error);
|
||||
|
||||
that.getUpdateInfo(function (error, info) { // note: non-admin users may get access denied for this
|
||||
if (!error) result.update = info.update; // attach update information to config object
|
||||
that.getUpdateInfo(function (error, info) {
|
||||
if (error) return callback(error);
|
||||
|
||||
result.update = info.update;
|
||||
that.setConfig(result);
|
||||
callback(null);
|
||||
});
|
||||
@@ -2816,7 +2863,7 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
|
||||
localStorage.setItem('redirectToHash', window.location.hash);
|
||||
|
||||
// start oidc flow
|
||||
window.location.href = this.apiOrigin + '/openid/auth?client_id=' + ('<%= apiOrigin %>' ? TOKEN_TYPES.ID_DEVELOPMENT : TOKEN_TYPES.ID_WEBADMIN) + '&scope=openid email profile&response_type=code token&redirect_uri=' + window.location.origin + '/authcallback.html';
|
||||
window.location.href = this.apiOrigin + '/openid/auth?client_id=' + (window.cloudronApiOrigin ? TOKEN_TYPES.ID_DEVELOPMENT : TOKEN_TYPES.ID_WEBADMIN) + '&scope=openid email profile&response_type=code token&redirect_uri=' + window.location.origin + '/authcallback.html';
|
||||
};
|
||||
|
||||
Client.prototype.logout = function () {
|
||||
@@ -3118,18 +3165,18 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
|
||||
});
|
||||
};
|
||||
|
||||
Client.prototype.getSolrConfig = function (callback) {
|
||||
Client.prototype.getFtsConfig = function (callback) {
|
||||
var config = {};
|
||||
|
||||
get('/api/v1/mailserver/solr_config', config, function (error, data, status) {
|
||||
get('/api/v1/mailserver/fts_config', config, function (error, data, status) {
|
||||
if (error) return callback(error);
|
||||
if (status !== 200) return callback(new ClientError(status, data));
|
||||
callback(null, data);
|
||||
});
|
||||
};
|
||||
|
||||
Client.prototype.setSolrConfig = function (enabled, callback) {
|
||||
post('/api/v1/mailserver/solr_config', { enabled: enabled }, null, function (error, data, status) {
|
||||
Client.prototype.setFtsConfig = function (state, callback) {
|
||||
post('/api/v1/mailserver/fts_config', { enable: state }, null, function (error, data, status) {
|
||||
if (error) return callback(error);
|
||||
if (status !== 200) return callback(new ClientError(status, data));
|
||||
|
||||
@@ -3568,8 +3615,7 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
|
||||
// basically the user has not setup appstore account yet
|
||||
if (!subscription.plan) return window.location.href = '/#/appstore';
|
||||
|
||||
if (subscription.plan.id === 'free') window.open(this.getConfig().consoleServerOrigin + '/#/subscription_setup/' + subscription.cloudronId + '?email=' + subscription.emailEncoded, '_blank');
|
||||
else window.open(this.getConfig().consoleServerOrigin + '/#/cloudron/' + subscription.cloudronId + '?email=' + subscription.emailEncoded, '_blank');
|
||||
window.open(this.getConfig().consoleServerOrigin + '/#/cloudron/' + subscription.cloudronId + '?email=' + subscription.emailEncoded, '_blank');
|
||||
};
|
||||
|
||||
Client.prototype.getAppstoreAppByIdAndVersion = function (appId, version, callback) {
|
||||
@@ -3679,10 +3725,18 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
|
||||
var ACTION_APP_STOP = 'app.stop';
|
||||
var ACTION_APP_RESTART = 'app.restart';
|
||||
|
||||
var ACTION_ARCHIVES_ADD = 'archives.add';
|
||||
var ACTION_ARCHIVES_DEL = 'archives.del';
|
||||
|
||||
var ACTION_BACKUP_FINISH = 'backup.finish';
|
||||
var ACTION_BACKUP_START = 'backup.start';
|
||||
var ACTION_BACKUP_CLEANUP_START = 'backup.cleanup.start';
|
||||
var ACTION_BACKUP_CLEANUP_FINISH = 'backup.cleanup.finish';
|
||||
|
||||
var ACTION_BRANDING_AVATAR = 'branding.avatar';
|
||||
var ACTION_BRANDING_NAME = 'branding.name';
|
||||
var ACTION_BRANDING_FOOTER = 'branding.footer';
|
||||
|
||||
var ACTION_CERTIFICATE_NEW = 'certificate.new';
|
||||
var ACTION_CERTIFICATE_RENEWAL = 'certificate.renew';
|
||||
var ACTION_CERTIFICATE_CLEANUP = 'certificate.cleanup';
|
||||
@@ -3697,6 +3751,11 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
|
||||
|
||||
var ACTION_EXTERNAL_LDAP_CONFIGURE = 'externalldap.configure';
|
||||
|
||||
var ACTION_GROUP_ADD = 'group.add';
|
||||
var ACTION_GROUP_UPDATE = 'group.update';
|
||||
var ACTION_GROUP_REMOVE = 'group.remove';
|
||||
var ACTION_GROUP_MEMBERSHIP = 'group.membership';
|
||||
|
||||
var ACTION_INSTALL_FINISH = 'cloudron.install.finish';
|
||||
|
||||
var ACTION_START = 'cloudron.start';
|
||||
@@ -3924,6 +3983,12 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
|
||||
if (!data.app) return '';
|
||||
return appName('', data.app, 'App') + ' was restarted';
|
||||
|
||||
case ACTION_ARCHIVES_ADD:
|
||||
return 'Backup ' + data.backupId + ' added to archive';
|
||||
|
||||
case ACTION_ARCHIVES_DEL:
|
||||
return 'Backup ' + data.backupId + ' deleted from archive';
|
||||
|
||||
case ACTION_BACKUP_START:
|
||||
return 'Backup started';
|
||||
|
||||
@@ -3940,6 +4005,15 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
|
||||
case ACTION_BACKUP_CLEANUP_FINISH:
|
||||
return data.errorMessage ? 'Backup cleaner errored: ' + data.errorMessage : 'Backup cleaner removed ' + (data.removedBoxBackupPaths ? data.removedBoxBackupPaths.length : '0') + ' backups';
|
||||
|
||||
case ACTION_BRANDING_AVATAR:
|
||||
return 'Cloudron Avatar Changed';
|
||||
|
||||
case ACTION_BRANDING_NAME:
|
||||
return 'Cloudron Name set to ' + data.name;
|
||||
|
||||
case ACTION_BRANDING_FOOTER:
|
||||
return 'Cloudron Footer set to ' + data.footer;
|
||||
|
||||
case ACTION_CERTIFICATE_NEW:
|
||||
return 'Certificate install for ' + data.domain + (errorMessage ? ' failed' : ' succeeded');
|
||||
|
||||
@@ -3975,6 +4049,18 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
|
||||
return 'External Directory set to ' + data.config.url + ' (' + data.config.provider + ')';
|
||||
}
|
||||
|
||||
case ACTION_GROUP_ADD:
|
||||
return 'Group ' + data.name + ' was added';
|
||||
|
||||
case ACTION_GROUP_UPDATE:
|
||||
return 'Group name changed from ' + data.oldName + ' to ' + data.group.name;
|
||||
|
||||
case ACTION_GROUP_REMOVE:
|
||||
return 'Group ' + data.group.name + ' was removed';
|
||||
|
||||
case ACTION_GROUP_MEMBERSHIP:
|
||||
return 'Group membership of ' + data.group.name + ' changed. Now was ' + data.userIds.length + ' member(s).';
|
||||
|
||||
case ACTION_INSTALL_FINISH:
|
||||
return 'Cloudron version ' + data.version + ' installed';
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
/* global angular:false, window, document, localStorage, redirectIfNeeded */
|
||||
/* global $:false */
|
||||
/* global async */
|
||||
/* global $, async, angular, redirectIfNeeded */
|
||||
/* global ERROR,ISTATES,HSTATES,RSTATES,APP_TYPES,NOTIFICATION_TYPES */
|
||||
|
||||
// deal with accessToken in the query, this is passed for example on password reset and account setup upon invite
|
||||
@@ -50,88 +48,88 @@ app.config(['$routeProvider', function ($routeProvider) {
|
||||
redirectTo: '/apps'
|
||||
}).when('/users', {
|
||||
controller: 'UsersController',
|
||||
templateUrl: 'views/users.html?<%= revision %>'
|
||||
}).when('/usersettings', {
|
||||
templateUrl: 'views/users.html?' + window.VITE_CACHE_ID
|
||||
}).when('/user-directory', {
|
||||
controller: 'UserSettingsController',
|
||||
templateUrl: 'views/user-settings.html?<%= revision %>'
|
||||
templateUrl: 'views/user-directory.html?' + window.VITE_CACHE_ID
|
||||
}).when('/app/:appId/:view?', {
|
||||
controller: 'AppController',
|
||||
templateUrl: 'views/app.html?<%= revision %>'
|
||||
templateUrl: 'views/app.html?' + window.VITE_CACHE_ID
|
||||
}).when('/appstore', {
|
||||
controller: 'AppStoreController',
|
||||
templateUrl: 'views/appstore.html?<%= revision %>'
|
||||
templateUrl: 'views/appstore.html?' + window.VITE_CACHE_ID
|
||||
}).when('/appstore/:appId', {
|
||||
controller: 'AppStoreController',
|
||||
templateUrl: 'views/appstore.html?<%= revision %>'
|
||||
templateUrl: 'views/appstore.html?' + window.VITE_CACHE_ID
|
||||
}).when('/apps', {
|
||||
controller: 'AppsController',
|
||||
templateUrl: 'views/apps.html?<%= revision %>'
|
||||
templateUrl: 'views/apps.html?' + window.VITE_CACHE_ID
|
||||
}).when('/profile', {
|
||||
controller: 'ProfileController',
|
||||
templateUrl: 'views/profile.html?<%= revision %>'
|
||||
templateUrl: 'views/profile.html?' + window.VITE_CACHE_ID
|
||||
}).when('/backups', {
|
||||
controller: 'BackupsController',
|
||||
templateUrl: 'views/backups.html?<%= revision %>'
|
||||
templateUrl: 'views/backups.html?' + window.VITE_CACHE_ID
|
||||
}).when('/branding', {
|
||||
controller: 'BrandingController',
|
||||
templateUrl: 'views/branding.html?<%= revision %>'
|
||||
templateUrl: 'views/branding.html?' + window.VITE_CACHE_ID
|
||||
}).when('/network', {
|
||||
controller: 'NetworkController',
|
||||
templateUrl: 'views/network.html?<%= revision %>'
|
||||
templateUrl: 'views/network.html?' + window.VITE_CACHE_ID
|
||||
}).when('/domains', {
|
||||
controller: 'DomainsController',
|
||||
templateUrl: 'views/domains.html?<%= revision %>'
|
||||
templateUrl: 'views/domains.html?' + window.VITE_CACHE_ID
|
||||
}).when('/email', {
|
||||
controller: 'EmailsController',
|
||||
templateUrl: 'views/emails.html?<%= revision %>'
|
||||
templateUrl: 'views/emails.html?' + window.VITE_CACHE_ID
|
||||
}).when('/emails-eventlog', {
|
||||
controller: 'EmailsEventlogController',
|
||||
templateUrl: 'views/emails-eventlog.html?<%= revision %>'
|
||||
templateUrl: 'views/emails-eventlog.html?' + window.VITE_CACHE_ID
|
||||
}).when('/emails-queue', {
|
||||
controller: 'EmailsQueueController',
|
||||
templateUrl: 'views/emails-queue.html?<%= revision %>'
|
||||
templateUrl: 'views/emails-queue.html?' + window.VITE_CACHE_ID
|
||||
}).when('/email/:domain/:view?', {
|
||||
controller: 'EmailController',
|
||||
templateUrl: 'views/email.html?<%= revision %>'
|
||||
templateUrl: 'views/email.html?' + window.VITE_CACHE_ID
|
||||
}).when('/notifications', {
|
||||
controller: 'NotificationsController',
|
||||
templateUrl: 'views/notifications.html?<%= revision %>'
|
||||
templateUrl: 'views/notifications.html?' + window.VITE_CACHE_ID
|
||||
}).when('/oidc', {
|
||||
redirectTo: '/usersettings'
|
||||
redirectTo: '/user-directory'
|
||||
}).when('/settings', {
|
||||
controller: 'SettingsController',
|
||||
templateUrl: 'views/settings.html?<%= revision %>'
|
||||
templateUrl: 'views/settings.html?' + window.VITE_CACHE_ID
|
||||
}).when('/eventlog', {
|
||||
controller: 'EventLogController',
|
||||
templateUrl: 'views/eventlog.html?<%= revision %>'
|
||||
templateUrl: 'views/eventlog.html?' + window.VITE_CACHE_ID
|
||||
}).when('/support', {
|
||||
controller: 'SupportController',
|
||||
templateUrl: 'views/support.html?<%= revision %>'
|
||||
templateUrl: 'views/support.html?' + window.VITE_CACHE_ID
|
||||
}).when('/system', {
|
||||
controller: 'SystemController',
|
||||
templateUrl: 'views/system.html?<%= revision %>'
|
||||
templateUrl: 'views/system.html?' + window.VITE_CACHE_ID
|
||||
}).when('/services', {
|
||||
controller: 'ServicesController',
|
||||
templateUrl: 'views/services.html?<%= revision %>'
|
||||
templateUrl: 'views/services.html?' + window.VITE_CACHE_ID
|
||||
}).when('/volumes', {
|
||||
controller: 'VolumesController',
|
||||
templateUrl: 'views/volumes.html?<%= revision %>'
|
||||
templateUrl: 'views/volumes.html?' + window.VITE_CACHE_ID
|
||||
}).otherwise({ redirectTo: '/'});
|
||||
}]);
|
||||
|
||||
app.filter('notificationTypeToColor', function () {
|
||||
return function (n) {
|
||||
switch (n.type) {
|
||||
case NOTIFICATION_TYPES.ALERT_REBOOT:
|
||||
case NOTIFICATION_TYPES.ALERT_APP_OOM:
|
||||
case NOTIFICATION_TYPES.ALERT_MAIL_STATUS:
|
||||
case NOTIFICATION_TYPES.ALERT_CERTIFICATE_RENEWAL_FAILED:
|
||||
case NOTIFICATION_TYPES.ALERT_DISK_SPACE:
|
||||
case NOTIFICATION_TYPES.ALERT_BACKUP_CONFIG:
|
||||
case NOTIFICATION_TYPES.ALERT_BACKUP_FAILED:
|
||||
case NOTIFICATION_TYPES.REBOOT:
|
||||
case NOTIFICATION_TYPES.APP_OOM:
|
||||
case NOTIFICATION_TYPES.MAIL_STATUS:
|
||||
case NOTIFICATION_TYPES.CERTIFICATE_RENEWAL_FAILED:
|
||||
case NOTIFICATION_TYPES.DISK_SPACE:
|
||||
case NOTIFICATION_TYPES.BACKUP_CONFIG:
|
||||
case NOTIFICATION_TYPES.BACKUP_FAILED:
|
||||
return '#ff4c4c';
|
||||
case NOTIFICATION_TYPES.ALERT_BOX_UPDATE:
|
||||
case NOTIFICATION_TYPES.ALERT_MANUAL_APP_UPDATE:
|
||||
case NOTIFICATION_TYPES.BOX_UPDATE:
|
||||
case NOTIFICATION_TYPES.MANUAL_APP_UPDATE:
|
||||
return '#f0ad4e';
|
||||
default:
|
||||
return '#2196f3';
|
||||
@@ -673,6 +671,10 @@ app.controller('MainController', ['$scope', '$route', '$timeout', '$location', '
|
||||
$scope.hideNavBarActions = $location.path() === '/logs';
|
||||
$scope.backgroundImageUrl = '';
|
||||
|
||||
$scope.closeNavbar = function () {
|
||||
$('.navbar-collapse').collapse('hide');
|
||||
};
|
||||
|
||||
$scope.reboot = {
|
||||
busy: false,
|
||||
|
||||
@@ -59,7 +59,7 @@ app.filter('tr', translateFilterFactory);
|
||||
|
||||
app.controller('PasswordResetController', ['$scope', '$translate', '$http', function ($scope, $translate, $http) {
|
||||
// Stupid angular location provider either wants html5 location mode or not, do the query parsing on my own
|
||||
var search = decodeURIComponent(window.location.search).slice(1).split('&').map(function (item) { return item.indexOf('=') === -1 ? [item, true] : [item.slice(0, item.indexOf('=')), item.slice(item.indexOf('=')+1)]; }).reduce(function (o, k) { o[k[0]] = k[1]; return o; }, {});
|
||||
const search = decodeURIComponent(window.location.search).slice(1).split('&').map(function (item) { return item.indexOf('=') === -1 ? [item, true] : [item.slice(0, item.indexOf('=')), item.slice(item.indexOf('=')+1)]; }).reduce(function (o, k) { o[k[0]] = k[1]; return o; }, {});
|
||||
|
||||
$scope.initialized = false;
|
||||
$scope.mode = '';
|
||||
@@ -72,7 +72,8 @@ app.controller('PasswordResetController', ['$scope', '$translate', '$http', func
|
||||
$scope.passwordResetIdentifier = '';
|
||||
$scope.newPassword = '';
|
||||
$scope.newPasswordRepeat = '';
|
||||
var API_ORIGIN = '<%= apiOrigin %>' || window.location.origin;
|
||||
|
||||
const API_ORIGIN = window.cloudronApiOrigin || window.location.origin;
|
||||
|
||||
$scope.onPasswordReset = function () {
|
||||
$scope.busy = true;
|
||||
@@ -1,7 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
/* global $, angular, SECRET_PLACEHOLDER, STORAGE_PROVIDERS, BACKUP_FORMATS, window, FileReader, document, redirectIfNeeded */
|
||||
/* global REGIONS_S3, REGIONS_WASABI, REGIONS_DIGITALOCEAN, REGIONS_EXOSCALE, REGIONS_SCALEWAY, REGIONS_LINODE, REGIONS_OVH, REGIONS_IONOS, REGIONS_UPCLOUD, REGIONS_VULTR, REGIONS_CONTABO */
|
||||
/* global $, angular, SECRET_PLACEHOLDER, STORAGE_PROVIDERS, BACKUP_FORMATS, redirectIfNeeded */
|
||||
/* global REGIONS_S3, REGIONS_WASABI, REGIONS_DIGITALOCEAN, REGIONS_EXOSCALE, REGIONS_SCALEWAY, REGIONS_LINODE, REGIONS_OVH, REGIONS_IONOS, REGIONS_UPCLOUD, REGIONS_VULTR, REGIONS_CONTABO, REGIONS_HETZNER */
|
||||
|
||||
// create main application module
|
||||
var app = angular.module('Application', ['pascalprecht.translate', 'ngCookies', 'angular-md5', 'ui-notification', 'ui.bootstrap']);
|
||||
@@ -77,6 +77,7 @@ app.controller('RestoreController', ['$scope', 'Client', function ($scope, Clien
|
||||
$scope.s3Regions = REGIONS_S3;
|
||||
$scope.wasabiRegions = REGIONS_WASABI;
|
||||
$scope.doSpacesRegions = REGIONS_DIGITALOCEAN;
|
||||
$scope.hetznerRegions = REGIONS_HETZNER;
|
||||
$scope.exoscaleSosRegions = REGIONS_EXOSCALE;
|
||||
$scope.scalewayRegions = REGIONS_SCALEWAY;
|
||||
$scope.linodeRegions = REGIONS_LINODE;
|
||||
@@ -92,7 +93,7 @@ app.controller('RestoreController', ['$scope', 'Client', function ($scope, Clien
|
||||
|
||||
$scope.s3like = function (provider) {
|
||||
return provider === 's3' || provider === 'minio' || provider === 's3-v4-compat' || provider === 'exoscale-sos'
|
||||
|| provider === 'digitalocean-spaces' || provider === 'wasabi' || provider === 'scaleway-objectstorage'
|
||||
|| provider === 'digitalocean-spaces' || provider === 'wasabi' || provider === 'scaleway-objectstorage' || provider === 'hetzner-objectstorage'
|
||||
|| provider === 'linode-objectstorage' || provider === 'ovh-objectstorage' || provider === 'backblaze-b2' || provider === 'cloudflare-r2'
|
||||
|| provider === 'ionos-objectstorage' || provider === 'vultr-objectstorage' || provider === 'upcloud-objectstorage' || provider === 'idrive-e2'
|
||||
|| provider === 'contabo-objectstorage';
|
||||
@@ -162,6 +163,9 @@ app.controller('RestoreController', ['$scope', 'Client', function ($scope, Clien
|
||||
backupConfig.signatureVersion = 'v4';
|
||||
} else if (backupConfig.provider === 'digitalocean-spaces') {
|
||||
backupConfig.region = 'us-east-1';
|
||||
} else if (backupConfig.provider === 'hetzner-objectstorage') {
|
||||
backupConfig.region = 'us-east-1';
|
||||
backupConfig.signatureVersion = 'v4';
|
||||
}
|
||||
} else if (backupConfig.provider === 'gcs') {
|
||||
backupConfig.bucket = $scope.bucket;
|
||||
@@ -1,6 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
/* global $, angular, Clipboard, ENDPOINTS_OVH, window, FileReader, document, redirectIfNeeded */
|
||||
/* global $, angular, Clipboard, ENDPOINTS_OVH, redirectIfNeeded */
|
||||
|
||||
// create main application module
|
||||
var app = angular.module('Application', ['pascalprecht.translate', 'ngCookies', 'angular-md5', 'ui-notification', 'ui.bootstrap']);
|
||||
@@ -68,6 +68,7 @@ app.controller('SetupDNSController', ['$scope', '$http', '$timeout', 'Client', f
|
||||
{ name: 'GoDaddy', value: 'godaddy' },
|
||||
{ name: 'Google Cloud DNS', value: 'gcdns' },
|
||||
{ name: 'Hetzner', value: 'hetzner' },
|
||||
{ name: 'INWX', value: 'inwx' },
|
||||
{ name: 'Linode', value: 'linode' },
|
||||
{ name: 'Name.com', value: 'namecom' },
|
||||
{ name: 'Namecheap', value: 'namecheap' },
|
||||
@@ -87,6 +88,7 @@ app.controller('SetupDNSController', ['$scope', '$http', '$timeout', 'Client', f
|
||||
gcdnsKey: { keyFileName: '', content: '' },
|
||||
digitalOceanToken: '',
|
||||
gandiApiKey: '',
|
||||
gandiTokenType: 'PAT',
|
||||
cloudflareEmail: '',
|
||||
cloudflareToken: '',
|
||||
cloudflareTokenType: 'GlobalApiKey',
|
||||
@@ -97,6 +99,8 @@ app.controller('SetupDNSController', ['$scope', '$http', '$timeout', 'Client', f
|
||||
bunnyAccessKey: '',
|
||||
dnsimpleAccessToken: '',
|
||||
hetznerToken: '',
|
||||
inwxUsername: '',
|
||||
inwxPassword: '',
|
||||
vultrToken: '',
|
||||
deSecToken: '',
|
||||
nameComUsername: '',
|
||||
@@ -181,6 +185,7 @@ app.controller('SetupDNSController', ['$scope', '$http', '$timeout', 'Client', f
|
||||
config.token = $scope.dnsCredentials.digitalOceanToken;
|
||||
} else if (provider === 'gandi') {
|
||||
config.token = $scope.dnsCredentials.gandiApiKey;
|
||||
config.tokenType = $scope.dnsCredentials.gandiTokenType;
|
||||
} else if (provider === 'godaddy') {
|
||||
config.apiKey = $scope.dnsCredentials.godaddyApiKey;
|
||||
config.apiSecret = $scope.dnsCredentials.godaddyApiSecret;
|
||||
@@ -197,6 +202,9 @@ app.controller('SetupDNSController', ['$scope', '$http', '$timeout', 'Client', f
|
||||
config.accessToken = $scope.dnsCredentials.dnsimpleAccessToken;
|
||||
} else if (provider === 'hetzner') {
|
||||
config.token = $scope.dnsCredentials.hetznerToken;
|
||||
} else if (provider === 'inwx') {
|
||||
config.username = $scope.dnsCredentials.inwxUsername;
|
||||
config.password = $scope.dnsCredentials.inwxPassword;
|
||||
} else if (provider === 'vultr') {
|
||||
config.token = $scope.dnsCredentials.vultrToken;
|
||||
} else if (provider === 'desec') {
|
||||
@@ -62,9 +62,9 @@ app.filter('tr', translateFilterFactory);
|
||||
|
||||
app.controller('SetupAccountController', ['$scope', '$translate', '$http', function ($scope, $translate, $http) {
|
||||
// Stupid angular location provider either wants html5 location mode or not, do the query parsing on my own
|
||||
var search = decodeURIComponent(window.location.search).slice(1).split('&').map(function (item) { return item.indexOf('=') === -1 ? [item, true] : [item.slice(0, item.indexOf('=')), item.slice(item.indexOf('=')+1)]; }).reduce(function (o, k) { o[k[0]] = k[1]; return o; }, {});
|
||||
const search = decodeURIComponent(window.location.search).slice(1).split('&').map(function (item) { return item.indexOf('=') === -1 ? [item, true] : [item.slice(0, item.indexOf('=')), item.slice(item.indexOf('=')+1)]; }).reduce(function (o, k) { o[k[0]] = k[1]; return o; }, {});
|
||||
|
||||
var API_ORIGIN = '<%= apiOrigin %>' || window.location.origin;
|
||||
const API_ORIGIN = window.cloudronApiOrigin || window.location.origin;
|
||||
|
||||
$scope.initialized = false;
|
||||
$scope.busy = false;
|
||||
1
dashboard/public/js/timezones.js
Normal file
@@ -1,5 +1,7 @@
|
||||
/* This file contains helpers which should not be part of client.js */
|
||||
|
||||
/* global angular */
|
||||
|
||||
angular.module('Application').directive('passwordReveal', function () {
|
||||
var svgEye = '<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="eye" class="svg-inline--fa fa-eye fa-w-18" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><path fill="currentColor" d="M572.52 241.4C518.29 135.59 410.93 64 288 64S57.68 135.64 3.48 241.41a32.35 32.35 0 0 0 0 29.19C57.71 376.41 165.07 448 288 448s230.32-71.64 284.52-177.41a32.35 32.35 0 0 0 0-29.19zM288 400a144 144 0 1 1 144-144 143.93 143.93 0 0 1-144 144zm0-240a95.31 95.31 0 0 0-25.31 3.79 47.85 47.85 0 0 1-66.9 66.9A95.78 95.78 0 1 0 288 160z"></path></svg>';
|
||||
var svgEyeSlash = '<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="eye-slash" class="svg-inline--fa fa-eye-slash fa-w-20" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><path fill="currentColor" d="M320 400c-75.85 0-137.25-58.71-142.9-133.11L72.2 185.82c-13.79 17.3-26.48 35.59-36.72 55.59a32.35 32.35 0 0 0 0 29.19C89.71 376.41 197.07 448 320 448c26.91 0 52.87-4 77.89-10.46L346 397.39a144.13 144.13 0 0 1-26 2.61zm313.82 58.1l-110.55-85.44a331.25 331.25 0 0 0 81.25-102.07 32.35 32.35 0 0 0 0-29.19C550.29 135.59 442.93 64 320 64a308.15 308.15 0 0 0-147.32 37.7L45.46 3.37A16 16 0 0 0 23 6.18L3.37 31.45A16 16 0 0 0 6.18 53.9l588.36 454.73a16 16 0 0 0 22.46-2.81l19.64-25.27a16 16 0 0 0-2.82-22.45zm-183.72-142l-39.3-30.38A94.75 94.75 0 0 0 416 256a94.76 94.76 0 0 0-121.31-92.21A47.65 47.65 0 0 1 304 192a46.64 46.64 0 0 1-1.54 10l-73.61-56.89A142.31 142.31 0 0 1 320 112a143.92 143.92 0 0 1 144 144c0 21.63-5.29 41.79-13.9 60.11z"></path></svg>';
|
||||
|
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 7.4 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 6.6 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 192 KiB After Width: | Height: | Size: 192 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |