This commit is contained in:
Andras Bacsai 2021-06-18 21:16:05 +02:00 committed by GitHub
parent d43cd663d2
commit 2ff9c5fed5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 849 additions and 99 deletions

View File

@ -48,11 +48,13 @@ ### Databases
### Services
- [WordPress](https://wordpress.org)
- [Plausible Analytics](https://plausible.io)
- [NocoDB](https://nocodb.com)
- [VSCode Server](https://github.com/cdr/code-server)
- [MinIO](https://min.io)
## Support
- Twitter: [@andrasbacsai](https://twitter.com/andrasbacsai)

View File

@ -1,7 +1,7 @@
{
"name": "coolify",
"description": "An open-source, hassle-free, self-hostable Heroku & Netlify alternative.",
"version": "1.0.19",
"version": "1.0.20",
"license": "AGPL-3.0",
"scripts": {
"dev:docker:start": "docker-compose -f docker-compose-dev.yml up -d",
@ -37,7 +37,6 @@
},
"type": "module",
"dependencies": {
"dotenv-extended": "^2.9.0",
"@iarna/toml": "^2.2.5",
"@zerodevx/svelte-toast": "^0.3.0",
"commander": "^7.2.0",
@ -46,6 +45,7 @@
"cuid": "^2.1.8",
"dayjs": "^1.10.5",
"dockerode": "^3.3.0",
"dotenv-extended": "^2.9.0",
"generate-password": "^1.6.0",
"js-yaml": "^4.1.0",
"jsonwebtoken": "^8.5.1",
@ -53,6 +53,7 @@
"shelljs": "^0.8.4",
"svelte-kit-cookie-session": "^1.0.6",
"svelte-select": "^3.17.0",
"systeminformation": "^5.7.7",
"unique-names-generator": "^4.5.0"
}
}

View File

@ -33,7 +33,8 @@ specifiers:
svelte-kit-cookie-session: ^1.0.6
svelte-preprocess: ^4.7.3
svelte-select: ^3.17.0
tailwindcss: 2.2.0-canary.8
systeminformation: ^5.7.7
tailwindcss: 2.2.0
tslib: ^2.2.0
typescript: ^4.3.2
unique-names-generator: ^4.5.0
@ -56,6 +57,7 @@ dependencies:
shelljs: 0.8.4
svelte-kit-cookie-session: 1.0.6
svelte-select: 3.17.0
systeminformation: 5.7.7
unique-names-generator: 4.5.0
devDependencies:
@ -75,7 +77,7 @@ devDependencies:
prettier-plugin-svelte: 2.3.0_prettier@2.3.1+svelte@3.38.2
svelte: 3.38.2
svelte-preprocess: 4.7.3_ddfd8490a44ef0de606159ff3aef985a
tailwindcss: 2.2.0-canary.8_6daa0ece57b4377652e73c9c66c3b94c
tailwindcss: 2.2.0_6daa0ece57b4377652e73c9c66c3b94c
tslib: 2.2.0
typescript: 4.3.2
vite: 2.3.6
@ -88,10 +90,22 @@ packages:
'@babel/highlight': 7.14.0
dev: true
/@babel/code-frame/7.14.5:
resolution: {integrity: sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==}
engines: {node: '>=6.9.0'}
dependencies:
'@babel/highlight': 7.14.5
dev: true
/@babel/helper-validator-identifier/7.14.0:
resolution: {integrity: sha512-V3ts7zMSu5lfiwWDVWzRDGIN+lnCEUdaXgtVHJgLb1rGaA6jMrtB9EmE7L18foXJIE8Un/A/h6NJfGQp/e1J4A==}
dev: true
/@babel/helper-validator-identifier/7.14.5:
resolution: {integrity: sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==}
engines: {node: '>=6.9.0'}
dev: true
/@babel/highlight/7.14.0:
resolution: {integrity: sha512-YSCOwxvTYEIMSGaBQb5kDDsCopDdiUGsqpatp3fOlI4+2HQSkTmEVWnVuySdAC5EWCqSWWTv0ib63RjR7dTBdg==}
dependencies:
@ -100,6 +114,15 @@ packages:
js-tokens: 4.0.0
dev: true
/@babel/highlight/7.14.5:
resolution: {integrity: sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==}
engines: {node: '>=6.9.0'}
dependencies:
'@babel/helper-validator-identifier': 7.14.5
chalk: 2.4.2
js-tokens: 4.0.0
dev: true
/@eslint/eslintrc/0.4.2:
resolution: {integrity: sha512-8nmGq/4ycLpIwzvhI4tNDmQztZ8sp+hI7cyG8i1nQDhkAbRzHpXPidRAHlNvCZQpJTKw5ItIpMw9RSToGF00mg==}
engines: {node: ^10.12.0 || >=12.0.0}
@ -117,34 +140,37 @@ packages:
- supports-color
dev: true
/@fullhuman/postcss-purgecss/3.1.3:
resolution: {integrity: sha512-kwOXw8fZ0Lt1QmeOOrd+o4Ibvp4UTEBFQbzvWldjlKv5n+G9sXfIPn1hh63IQIL8K8vbvv1oYMJiIUbuy9bGaA==}
/@fullhuman/postcss-purgecss/4.0.3_postcss@8.3.0:
resolution: {integrity: sha512-/EnQ9UDWGGqHkn1UKAwSgh+gJHPKmD+Z+5dQ4gWT4qq2NUyez3zqAfZNwFH3eSgmgO+wjTXfhlLchx2M9/K+7Q==}
peerDependencies:
postcss: ^8.0.0
dependencies:
purgecss: 3.1.3
postcss: 8.3.0
purgecss: 4.0.3
dev: true
/@iarna/toml/2.2.5:
resolution: {integrity: sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==}
dev: false
/@nodelib/fs.scandir/2.1.4:
resolution: {integrity: sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==}
/@nodelib/fs.scandir/2.1.5:
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
engines: {node: '>= 8'}
dependencies:
'@nodelib/fs.stat': 2.0.4
'@nodelib/fs.stat': 2.0.5
run-parallel: 1.2.0
dev: true
/@nodelib/fs.stat/2.0.4:
resolution: {integrity: sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==}
/@nodelib/fs.stat/2.0.5:
resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
engines: {node: '>= 8'}
dev: true
/@nodelib/fs.walk/1.2.6:
resolution: {integrity: sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==}
/@nodelib/fs.walk/1.2.7:
resolution: {integrity: sha512-BTIhocbPBSrRmHxOAJFtR18oLhxTtAFDAvL8hY1S3iU8k+E60W/YFs4jrixGzQjMpF4qPXxIQHcjVD9dz1C2QA==}
engines: {node: '>= 8'}
dependencies:
'@nodelib/fs.scandir': 2.1.4
'@nodelib/fs.scandir': 2.1.5
fastq: 1.11.0
dev: true
@ -433,7 +459,11 @@ packages:
engines: {node: '>= 8'}
dependencies:
normalize-path: 3.0.0
picomatch: 2.2.3
picomatch: 2.3.0
dev: true
/arg/5.0.0:
resolution: {integrity: sha512-4P8Zm2H+BRS+c/xX1LrHw0qKpEhdlZjLCgWy+d78T9vqa2Z2SiD2wMrYuWIAFy5IZUD7nnNXroRttz+0RzlrzQ==}
dev: true
/argparse/1.0.10:
@ -621,8 +651,8 @@ packages:
engines: {node: '>=8'}
dev: true
/chokidar/3.5.1:
resolution: {integrity: sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==}
/chokidar/3.5.2:
resolution: {integrity: sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==}
engines: {node: '>= 8.10.0'}
dependencies:
anymatch: 3.1.2
@ -631,7 +661,7 @@ packages:
is-binary-path: 2.1.0
is-glob: 4.0.1
normalize-path: 3.0.0
readdirp: 3.5.0
readdirp: 3.6.0
optionalDependencies:
fsevents: 2.3.2
dev: true
@ -1213,12 +1243,12 @@ packages:
resolution: {integrity: sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==}
engines: {node: '>=8'}
dependencies:
'@nodelib/fs.stat': 2.0.4
'@nodelib/fs.walk': 1.2.6
'@nodelib/fs.stat': 2.0.5
'@nodelib/fs.walk': 1.2.7
glob-parent: 5.1.2
merge2: 1.4.1
micromatch: 4.0.4
picomatch: 2.2.3
picomatch: 2.3.0
dev: true
/fast-json-stable-stringify/2.1.0:
@ -1305,20 +1335,6 @@ packages:
resolution: {integrity: sha512-YUJTQkApkLT/fru0QdYWP0lVZdPKhF5kXCP24sgI4gR/vFMJFopCj5t1+9FAKIYcML/nxzx2PMkA1ymO1FC+tQ==}
dev: false
/glob-base/0.3.0:
resolution: {integrity: sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=}
engines: {node: '>=0.10.0'}
dependencies:
glob-parent: 2.0.0
is-glob: 2.0.1
dev: true
/glob-parent/2.0.0:
resolution: {integrity: sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=}
dependencies:
is-glob: 2.0.1
dev: true
/glob-parent/5.1.2:
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
engines: {node: '>= 6'}
@ -1326,6 +1342,13 @@ packages:
is-glob: 4.0.1
dev: true
/glob-parent/6.0.0:
resolution: {integrity: sha512-Hdd4287VEJcZXUwv1l8a+vXC1GjOQqXe+VS30w/ypihpcnu9M1n3xeYeJu5CBpeEQj2nAab2xxz28GuA3vp4Ww==}
engines: {node: '>=10.13.0'}
dependencies:
is-glob: 4.0.1
dev: true
/glob/7.1.6:
resolution: {integrity: sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==}
dependencies:
@ -1502,16 +1525,6 @@ packages:
dependencies:
has: 1.0.3
/is-dotfile/1.0.3:
resolution: {integrity: sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=}
engines: {node: '>=0.10.0'}
dev: true
/is-extglob/1.0.0:
resolution: {integrity: sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=}
engines: {node: '>=0.10.0'}
dev: true
/is-extglob/2.1.1:
resolution: {integrity: sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=}
engines: {node: '>=0.10.0'}
@ -1522,13 +1535,6 @@ packages:
engines: {node: '>=8'}
dev: true
/is-glob/2.0.1:
resolution: {integrity: sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=}
engines: {node: '>=0.10.0'}
dependencies:
is-extglob: 1.0.0
dev: true
/is-glob/4.0.1:
resolution: {integrity: sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==}
engines: {node: '>=0.10.0'}
@ -1732,7 +1738,7 @@ packages:
engines: {node: '>=8.6'}
dependencies:
braces: 3.0.2
picomatch: 2.2.3
picomatch: 2.3.0
dev: true
/min-indent/1.0.1:
@ -1935,21 +1941,11 @@ packages:
callsites: 3.1.0
dev: true
/parse-glob/3.0.4:
resolution: {integrity: sha1-ssN2z7EfNVE7rdFz7wu246OIORw=}
engines: {node: '>=0.10.0'}
dependencies:
glob-base: 0.3.0
is-dotfile: 1.0.3
is-extglob: 1.0.0
is-glob: 2.0.1
dev: true
/parse-json/5.2.0:
resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
engines: {node: '>=8'}
dependencies:
'@babel/code-frame': 7.12.11
'@babel/code-frame': 7.14.5
error-ex: 1.3.2
json-parse-even-better-errors: 2.3.1
lines-and-columns: 1.1.6
@ -1963,8 +1959,8 @@ packages:
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
engines: {node: '>=8'}
/path-parse/1.0.6:
resolution: {integrity: sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==}
/path-parse/1.0.7:
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
/path-type/4.0.0:
resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
@ -1976,6 +1972,11 @@ packages:
engines: {node: '>=8.6'}
dev: true
/picomatch/2.3.0:
resolution: {integrity: sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==}
engines: {node: '>=8.6'}
dev: true
/postcss-calc/8.0.0_postcss@8.3.0:
resolution: {integrity: sha512-5NglwDrcbiy8XXfPM11F3HeC6hoT9W7GUH/Zi5U/p7u3Irv4rHhdDcIZwG0llHXV4ftsBjpfWMXAnXNl4lnt8g==}
peerDependencies:
@ -2050,7 +2051,7 @@ packages:
engines: {node: '>=10.0'}
dependencies:
camelcase-css: 2.0.1
postcss: 8.3.0
postcss: 8.3.5
dev: true
/postcss-load-config/3.0.1:
@ -2320,6 +2321,15 @@ packages:
source-map-js: 0.6.2
dev: true
/postcss/8.3.5:
resolution: {integrity: sha512-NxTuJocUhYGsMiMFHDUkmjSKT3EdH4/WbGF6GCi1NDGk+vbcUTun4fpbOqaPtD8IIsztA2ilZm2DhYCuyN58gA==}
engines: {node: ^10 || ^12 || >=14}
dependencies:
colorette: 1.2.2
nanoid: 3.1.23
source-map-js: 0.6.2
dev: true
/prelude-ls/1.2.1:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
engines: {node: '>= 0.8.0'}
@ -2367,13 +2377,13 @@ packages:
engines: {node: '>=6'}
dev: true
/purgecss/3.1.3:
resolution: {integrity: sha512-hRSLN9mguJ2lzlIQtW4qmPS2kh6oMnA9RxdIYK8sz18QYqd6ePp4GNDl18oWHA1f2v2NEQIh51CO8s/E3YGckQ==}
/purgecss/4.0.3:
resolution: {integrity: sha512-PYOIn5ibRIP34PBU9zohUcCI09c7drPJJtTDAc0Q6QlRz2/CHQ8ywGLdE7ZhxU2VTqB7p5wkvj5Qcm05Rz3Jmw==}
hasBin: true
dependencies:
commander: 6.2.1
glob: 7.1.7
postcss: 8.3.0
postcss: 8.3.5
postcss-selector-parser: 6.0.6
dev: true
@ -2407,11 +2417,11 @@ packages:
util-deprecate: 1.0.2
dev: false
/readdirp/3.5.0:
resolution: {integrity: sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==}
/readdirp/3.6.0:
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
engines: {node: '>=8.10.0'}
dependencies:
picomatch: 2.2.3
picomatch: 2.3.0
dev: true
/rechoir/0.6.2:
@ -2460,7 +2470,7 @@ packages:
resolution: {integrity: sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==}
dependencies:
is-core-module: 2.4.0
path-parse: 1.0.6
path-parse: 1.0.7
/reusify/1.0.4:
resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
@ -2792,6 +2802,13 @@ packages:
stable: 0.1.8
dev: true
/systeminformation/5.7.7:
resolution: {integrity: sha512-aQ7MBeVI2MKPYOi3YJAoZ45JVlRkBA7IXoqGgtVBamvtE0I6JLOyJzD/VVc9pnMXDb3yqaMwssAjhwtJax4/Rw==}
engines: {node: '>=4.0.0'}
os: [darwin, linux, win32, freebsd, openbsd, netbsd, sunos]
hasBin: true
dev: false
/table/6.6.0:
resolution: {integrity: sha512-iZMtp5tUvcnAdtHpZTWLPF0M7AgiQsURR2DwmxnJwSy8I3+cY+ozzVvYha3BOLG2TB+L0CqjIz+91htuj6yCXg==}
engines: {node: '>=10.0.0'}
@ -2805,35 +2822,39 @@ packages:
strip-ansi: 6.0.0
dev: true
/tailwindcss/2.2.0-canary.8_6daa0ece57b4377652e73c9c66c3b94c:
resolution: {integrity: sha512-IVgtzCS3HTq4lsK793isUIhbylCoG/WrarYpK8cAlbjOt5TwLJnhfp2GKjfzK3201eM4YawTjuRI+wesEy8XGg==}
/tailwindcss/2.2.0_6daa0ece57b4377652e73c9c66c3b94c:
resolution: {integrity: sha512-vzyictuac60cUfky6R4gFW98glcc/UxpaCH+Mt9dq+LEPdZq2Dpvo5iYpPaemutOIjfeiY0Y8j0ZgJG3wBaFDQ==}
engines: {node: '>=12.13.0'}
hasBin: true
peerDependencies:
autoprefixer: ^10.0.2
postcss: ^8.0.9
dependencies:
'@fullhuman/postcss-purgecss': 3.1.3
'@fullhuman/postcss-purgecss': 4.0.3_postcss@8.3.0
arg: 5.0.0
autoprefixer: 10.2.6_postcss@8.3.0
bytes: 3.1.0
chalk: 4.1.1
chokidar: 3.5.1
chokidar: 3.5.2
color: 3.1.3
cosmiconfig: 7.0.0
detective: 5.2.0
didyoumean: 1.2.1
dlv: 1.1.3
fast-glob: 3.2.5
fs-extra: 10.0.0
glob-parent: 6.0.0
html-tags: 3.1.0
is-glob: 4.0.1
lodash: 4.17.21
lodash.topath: 4.5.2
modern-normalize: 1.1.0
node-emoji: 1.10.0
normalize-path: 3.0.0
object-hash: 2.2.0
parse-glob: 3.0.4
postcss: 8.3.0
postcss-js: 3.0.3
postcss-load-config: 3.0.1
postcss-nested: 5.0.5_postcss@8.3.0
postcss-selector-parser: 6.0.6
postcss-value-parser: 4.1.0
@ -2841,6 +2862,7 @@ packages:
quick-lru: 5.1.1
reduce-css-calc: 2.1.8
resolve: 1.20.0
tmp: 0.2.1
dev: true
/tar-fs/2.0.1:
@ -2871,6 +2893,13 @@ packages:
resolution: {integrity: sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=}
dev: true
/tmp/0.2.1:
resolution: {integrity: sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==}
engines: {node: '>=8.17.0'}
dependencies:
rimraf: 3.0.2
dev: true
/to-regex-range/5.0.1:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}

View File

@ -339,7 +339,7 @@
>
<span class="sr-only">Use setting</span>
<span
class="pointer-events-none relative inline-block h-5 w-5 rounded-full bg-white shadow transition ease-in-out duration-200"
class="pointer-events-none relative inline-block h-5 w-5 rounded-full bg-white shadow transition ease-in-out duration-200 transform"
class:translate-x-5={$application.general.isPreviewDeploymentEnabled}
class:translate-x-0={!$application.general.isPreviewDeploymentEnabled}
>

View File

@ -53,12 +53,13 @@
let upgradeDisabled = false;
let upgradeDone = false;
let showAck = false;
let globalFeatureFlag = browser && localStorage.getItem('globalFeatureFlag')
const options = {
duration: 2000
};
onMount(async () => {
upgradeAvailable = await checkUpgrade();
browser && localStorage.removeItem('token')
browser && localStorage.removeItem('token');
if (!localStorage.getItem('automaticErrorReportsAck')) {
showAck = true;
if (latest?.coolify[branch]?.settings?.sendErrors) {
@ -224,6 +225,31 @@
</div>
</Tooltip>
<div class="flex-1" />
{#if globalFeatureFlag}
<Tooltip position="right" label="Server(s)">
<div
class="p-2 hover:bg-warmGray-700 rounded hover:text-red-500 mb-4 transition-all duration-100 cursor-pointer"
on:click={() => goto('/servers')}
class:text-red-500={$page.path === '/servers' || $page.path.startsWith('/servers')}
class:bg-warmGray-700={$page.path === '/servers' || $page.path.startsWith('/servers')}
>
<svg
class="w-8"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M5 12h14M5 12a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v4a2 2 0 01-2 2M5 12a2 2 0 00-2 2v4a2 2 0 002 2h14a2 2 0 002-2v-4a2 2 0 00-2-2m-2-4h.01M17 16h.01"
/>
</svg>
</div>
</Tooltip>
{/if}
<Tooltip position="right" label="Settings">
<button
class="p-2 hover:bg-warmGray-700 rounded hover:text-yellow-500 transition-all duration-100 cursor-pointer"

View File

@ -0,0 +1,25 @@
import { saveServerLog } from '$lib/api/applications/logging';
import { execShellAsync } from '$lib/api/common';
import type { Request } from '@sveltejs/kit';
export async function post(request: Request) {
try {
const output = await execShellAsync('docker builder prune -af')
return {
status: 200,
body: {
message: 'OK',
output: output.replace(/^(?=\n)$|^\s*|\s*$|\n\n+/gm,"").split('\n').pop()
}
}
} catch (error) {
await saveServerLog(error);
return {
status: 500,
body: {
error: error.message || error
}
};
}
}

View File

@ -0,0 +1,25 @@
import { saveServerLog } from '$lib/api/applications/logging';
import { execShellAsync } from '$lib/api/common';
import type { Request } from '@sveltejs/kit';
export async function post(request: Request) {
try {
const output = await execShellAsync('docker container prune -f')
return {
status: 200,
body: {
message: 'OK',
output: output.replace(/^(?=\n)$|^\s*|\s*$|\n\n+/gm,"").split('\n').pop()
}
}
} catch (error) {
await saveServerLog(error);
return {
status: 500,
body: {
error: error.message || error
}
};
}
}

View File

@ -0,0 +1,25 @@
import { saveServerLog } from '$lib/api/applications/logging';
import { execShellAsync } from '$lib/api/common';
import type { Request } from '@sveltejs/kit';
export async function post(request: Request) {
try {
const output = await execShellAsync('docker image prune -af')
return {
status: 200,
body: {
message: 'OK',
output: output.replace(/^(?=\n)$|^\s*|\s*$|\n\n+/gm,"").split('\n').pop()
}
}
} catch (error) {
await saveServerLog(error);
return {
status: 500,
body: {
error: error.message || error
}
};
}
}

View File

@ -0,0 +1,25 @@
import { saveServerLog } from '$lib/api/applications/logging';
import { execShellAsync } from '$lib/api/common';
import type { Request } from '@sveltejs/kit';
export async function post(request: Request) {
try {
const output = await execShellAsync('docker volume prune -f')
return {
status: 200,
body: {
message: 'OK',
output: output.replace(/^(?=\n)$|^\s*|\s*$|\n\n+/gm,"").split('\n').pop()
}
}
} catch (error) {
await saveServerLog(error);
return {
status: 500,
body: {
error: error.message || error
}
};
}
}

View File

@ -0,0 +1,34 @@
import { saveServerLog } from '$lib/api/applications/logging';
import { execShellAsync } from '$lib/api/common';
import { docker } from '$lib/api/docker';
import type { Request } from '@sveltejs/kit';
import systeminformation from 'systeminformation'
export async function get(request: Request) {
try {
const df = await execShellAsync(
`docker system df --format '{{ json . }}'`
);
const dockerReclaimable = df
.split('\n')
.filter((n) => n)
.map((s) => JSON.parse(s))
return {
status: 200,
body: {
hostname: await (await systeminformation.osInfo()).hostname,
filesystems: await (await systeminformation.fsSize()).filter(fs => !fs.fs.match('/dev/loop') || !fs.fs.match('/var/lib/docker/')),
dockerReclaimable
}
}
} catch (error) {
await saveServerLog(error);
return {
status: 500,
body: {
error: error.message || error
}
};
}
}

View File

@ -0,0 +1,173 @@
import type { Request } from '@sveltejs/kit';
import yaml from 'js-yaml';
import generator from 'generate-password';
import { promises as fs } from 'fs';
import { docker } from '$lib/api/docker';
import { baseServiceConfiguration } from '$lib/api/applications/common';
import { cleanupTmp, execShellAsync } from '$lib/api/common';
export async function post(request: Request) {
let { baseURL, remoteDB, database, wordpressExtraConfiguration } = request.body;
const traefikURL = baseURL;
baseURL = `https://${baseURL}`;
console.log({ baseURL, remoteDB, database, wordpressExtraConfiguration })
const workdir = '/tmp/wordpress';
const deployId = `wp-${generator.generate({ length: 5, numbers: true, strict: true })}`
const defaultDatabaseName = generator.generate({ length: 12, numbers: true, strict: true })
const defaultDatabaseHost = `${deployId}-mysql`
const defaultDatabaseUser = generator.generate({ length: 12, numbers: true, strict: true })
const defaultDatabasePassword = generator.generate({ length: 24, numbers: true, strict: true })
const defaultDatabaseRootPassword = generator.generate({ length: 24, numbers: true, strict: true })
const defaultDatabaseRootUser = generator.generate({ length: 12, numbers: true, strict: true })
let secrets = [
{ name: 'WORDPRESS_DB_HOST', value: defaultDatabaseHost },
{ name: 'WORDPRESS_DB_USER', value: defaultDatabaseUser },
{ name: 'WORDPRESS_DB_PASSWORD', value: defaultDatabasePassword },
{ name: 'WORDPRESS_DB_NAME', value: defaultDatabaseName },
{ name: 'WORDPRESS_CONFIG_EXTRA', value: wordpressExtraConfiguration }
];
const generateEnvsMySQL = {
MYSQL_ROOT_PASSWORD: defaultDatabaseRootPassword,
MYSQL_ROOT_USER: defaultDatabaseRootUser,
MYSQL_USER: defaultDatabaseUser,
MYSQL_PASSWORD: defaultDatabasePassword,
MYSQL_DATABASE: defaultDatabaseName
};
const image = 'bitnami/mysql:8.0';
const volume = `${deployId}-mysql-data:/bitnami/mysql/data`;
if (remoteDB) {
secrets = [
{ name: 'WORDPRESS_DB_HOST', value: database.host },
{ name: 'WORDPRESS_DB_USER', value: database.user },
{ name: 'WORDPRESS_DB_PASSWORD', value: database.password },
{ name: 'WORDPRESS_DB_NAME', value: database.name },
{ name: 'WORDPRESS_TABLE_PREFIX', value: database.tablePrefix },
{ name: 'WORDPRESS_CONFIG_EXTRA', value: wordpressExtraConfiguration }
]
}
const generateEnvsWordpress = {};
for (const secret of secrets) generateEnvsWordpress[secret.name] = secret.value;
let stack = {
version: '3.8',
services: {
[deployId]: {
image: 'wordpress',
networks: [`${docker.network}`],
environment: generateEnvsWordpress,
volumes: [`${deployId}-wordpress-data:/var/www/html`],
deploy: {
...baseServiceConfiguration,
labels: [
'managedBy=coolify',
'type=service',
'serviceName=' + deployId,
'configuration=' +
JSON.stringify({
deployId,
baseURL,
generateEnvsWordpress
}),
'traefik.enable=true',
'traefik.http.services.' + deployId + '.loadbalancer.server.port=80',
'traefik.http.routers.' + deployId + '.entrypoints=websecure',
'traefik.http.routers.' +
deployId +
'.rule=Host(`' +
traefikURL +
'`) && PathPrefix(`/`)',
'traefik.http.routers.' + deployId + '.tls.certresolver=letsencrypt',
'traefik.http.routers.' + deployId + '.middlewares=global-compress'
]
}
},
[`${deployId}-mysql`]: {
image,
networks: [`${docker.network}`],
environment: generateEnvsMySQL,
volumes: [volume],
deploy: {
...baseServiceConfiguration,
labels: [
'managedBy=coolify',
'type=service',
'serviceName=' + deployId,
]
}
}
},
networks: {
[`${docker.network}`]: {
external: true
}
},
volumes: {
[`${deployId}-wordpress-data`]: {
external: true
},
[`${deployId}-mysql-data`]: {
external: true
}
},
};
if (remoteDB) {
stack = {
version: '3.8',
services: {
[deployId]: {
image: 'wordpress',
networks: [`${docker.network}`],
environment: generateEnvsWordpress,
volumes: [`${deployId}-wordpress-data:/var/www/html`],
deploy: {
...baseServiceConfiguration,
labels: [
'managedBy=coolify',
'type=service',
'serviceName=' + deployId,
'configuration=' +
JSON.stringify({
deployId,
baseURL,
generateEnvsWordpress
}),
'traefik.enable=true',
'traefik.http.services.' + deployId + '.loadbalancer.server.port=80',
'traefik.http.routers.' + deployId + '.entrypoints=websecure',
'traefik.http.routers.' +
deployId +
'.rule=Host(`' +
traefikURL +
'`) && PathPrefix(`/`)',
'traefik.http.routers.' + deployId + '.tls.certresolver=letsencrypt',
'traefik.http.routers.' + deployId + '.middlewares=global-compress'
]
}
}
},
networks: {
[`${docker.network}`]: {
external: true
}
},
volumes: {
[`${deployId}-wordpress-data`]: {
external: true
}
},
};
}
console.log(stack)
await execShellAsync(`mkdir -p ${workdir}`);
await fs.writeFile(`${workdir}/stack.yml`, yaml.dump(stack));
await execShellAsync(`docker stack rm ${deployId}`);
await execShellAsync(`cat ${workdir}/stack.yml | docker stack deploy --prune -c - ${deployId}`);
cleanupTmp(workdir);
return {
status: 200,
body: { message: 'OK' }
};
}

View File

@ -2,6 +2,14 @@
import { goto } from '$app/navigation';
import { dashboard } from '$store';
import { fade } from 'svelte/transition';
async function openConfiguration(service) {
if (service.serviceName === 'wordpress') {
goto(`/service/${service.configuration.deployId}/configuration`);
} else {
goto(`/service/${service.serviceName}/configuration`);
}
}
</script>
<div
@ -34,7 +42,7 @@
<div
in:fade={{ duration: 200 }}
class="px-4 pb-4"
on:click={() => goto(`/service/${service.serviceName}/configuration`)}
on:click={() => openConfiguration(service)}
>
<div
class="relative rounded-xl p-6 bg-warmGray-800 border-2 border-dashed border-transparent hover:border-blue-500 text-white shadow-md cursor-pointer ease-in-out hover:scale-105 duration-100 group"
@ -49,7 +57,7 @@
/>
<div class="text-white font-bold">Plausible Analytics</div>
</div>
{:else if service.serviceName == 'nocodb'}
{:else if service.serviceName == 'nocodb'}
<div>
<img
alt="nocodedb"
@ -58,15 +66,27 @@
/>
<div class="text-white font-bold">NocoDB</div>
</div>
{:else if service.serviceName == 'code-server'}
{:else if service.serviceName == 'code-server'}
<div>
<svg class="w-10 absolute top-0 left-0 -m-6" viewBox="0 0 128 128">
<path d="M3.656 45.043s-3.027-2.191.61-5.113l8.468-7.594s2.426-2.559 4.989-.328l78.175 59.328v28.45s-.039 4.468-5.757 3.976zm0 0" fill="#2489ca"></path><path d="M23.809 63.379L3.656 81.742s-2.07 1.543 0 4.305l9.356 8.527s2.222 2.395 5.508-.328l21.359-16.238zm0 0" fill="#1070b3"></path><path d="M59.184 63.531l36.953-28.285-.239-28.297S94.32.773 89.055 3.99L39.879 48.851zm0 0" fill="#0877b9"></path><path d="M90.14 123.797c2.145 2.203 4.747 1.48 4.747 1.48l28.797-14.222c3.687-2.52 3.171-5.645 3.171-5.645V20.465c0-3.735-3.812-5.024-3.812-5.024L98.082 3.38c-5.453-3.379-9.027.61-9.027.61s4.593-3.317 6.843 2.96v112.317c0 .773-.164 1.53-.492 2.214-.656 1.332-2.086 2.57-5.504 2.051zm0 0" fill="#3c99d4"></path>
</svg>
<path
d="M3.656 45.043s-3.027-2.191.61-5.113l8.468-7.594s2.426-2.559 4.989-.328l78.175 59.328v28.45s-.039 4.468-5.757 3.976zm0 0"
fill="#2489ca"
/><path
d="M23.809 63.379L3.656 81.742s-2.07 1.543 0 4.305l9.356 8.527s2.222 2.395 5.508-.328l21.359-16.238zm0 0"
fill="#1070b3"
/><path
d="M59.184 63.531l36.953-28.285-.239-28.297S94.32.773 89.055 3.99L39.879 48.851zm0 0"
fill="#0877b9"
/><path
d="M90.14 123.797c2.145 2.203 4.747 1.48 4.747 1.48l28.797-14.222c3.687-2.52 3.171-5.645 3.171-5.645V20.465c0-3.735-3.812-5.024-3.812-5.024L98.082 3.38c-5.453-3.379-9.027.61-9.027.61s4.593-3.317 6.843 2.96v112.317c0 .773-.164 1.53-.492 2.214-.656 1.332-2.086 2.57-5.504 2.051zm0 0"
fill="#3c99d4"
/>
</svg>
<div class="text-white font-bold">VSCode Server</div>
</div>
{:else if service.serviceName == 'minio'}
{:else if service.serviceName == 'minio'}
<div>
<img
alt="minio"
@ -76,6 +96,21 @@
<div class="text-white font-bold">MinIO</div>
</div>
{:else if service.serviceName.match(/wp-/)}
<svg class="w-10 absolute top-0 left-0 -m-6" viewBox="0 0 128 128">
<path
fill-rule="evenodd"
clip-rule="evenodd"
fill="white"
d="M64.094 126.224c34.275-.052 62.021-27.933 62.021-62.325 0-33.833-27.618-61.697-60.613-62.286C30.85.995 1.894 29.113 1.885 63.21c-.01 35.079 27.612 63.064 62.209 63.014zM63.993 4.63c32.907-.011 59.126 26.725 59.116 60.28-.011 31.679-26.925 58.18-59.092 58.187-32.771.007-59.125-26.563-59.124-59.608.002-32.193 26.766-58.848 59.1-58.859zM39.157 35.896c.538 1.793-.968 2.417-2.569 2.542-1.685.13-3.369.257-5.325.406 6.456 19.234 12.815 38.183 19.325 57.573.464-.759.655-.973.739-1.223 3.574-10.682 7.168-21.357 10.651-32.069.318-.977.16-2.271-.188-3.275-1.843-5.32-4.051-10.524-5.667-15.908-1.105-3.686-2.571-6.071-6.928-5.644-.742.073-1.648-1.524-2.479-2.349 1.005-.6 2.003-1.704 3.017-1.719a849.593 849.593 0 0126.618.008c1.018.017 2.016 1.15 3.021 1.765-.88.804-1.639 2.01-2.668 2.321-1.651.498-3.482.404-5.458.58l19.349 57.56c2.931-9.736 5.658-18.676 8.31-27.639 2.366-8.001.956-15.473-3.322-22.52-1.286-2.119-2.866-4.175-3.595-6.486-.828-2.629-1.516-5.622-1.077-8.259.745-4.469 4.174-6.688 8.814-7.113C74.333.881 34.431 9.317 19.728 34.922c5.66-.261 11.064-.604 16.472-.678 1.022-.013 2.717.851 2.957 1.652zm10.117 77.971c-.118.345-.125.729-.218 1.302 10.943 3.034 21.675 2.815 32.659-.886l-16.78-45.96c-5.37 15.611-10.52 30.575-15.661 45.544zm-8.456-2.078l-25.281-69.35c-11.405 22.278-2.729 56.268 25.281 69.35zm76.428-44.562c.802-10.534-2.832-25.119-5.97-27.125-.35 3.875-.106 8.186-1.218 12.114-2.617 9.255-5.817 18.349-8.899 27.468-3.35 9.912-6.832 19.779-10.257 29.666 16.092-9.539 24.935-23.618 26.344-42.123z"
/>
</svg>
<div class="text-white font-bold text-center">
Wordpress<span
class="flex text-xs items-center justify-center text-warmGray-300 group-hover:text-white"
>({service.configuration.baseURL.replace('https://', '')})</span
>
</div>
{/if}
</div>
</div>

View File

@ -0,0 +1,101 @@
<script context="module">
/**
* @type {import('@sveltejs/kit').Load}
*/
export async function load({ fetch }) {
try {
const { hostname, filesystems,dockerReclaimable } = await (await fetch(`/api/v1/servers`)).json();
return {
props: {
hostname,
filesystems,
dockerReclaimable
}
};
} catch (error) {
return {
props: {
hostname: null,
filesystems: null,
dockerReclaimable: null
}
};
}
}
</script>
<script>
export let hostname;
export let filesystems;
export let dockerReclaimable;
import { browser } from '$app/env';
import { session } from '$app/stores';
import { request } from '$lib/request';
import { toast } from '@zerodevx/svelte-toast';
import { fade } from 'svelte/transition';
async function refetch() {
const data = await request('/api/v1/servers', $session)
filesystems = data.filesystems
dockerReclaimable = data.dockerReclaimable
}
async function cleanupVolumes() {
const { output } = await request('/api/v1/servers/cleanups/volumes', $session, {
body: {}
});
browser && toast.push(output);
await refetch()
}
async function cleanupImages() {
const { output } = await request('/api/v1/servers/cleanups/images', $session, {
body: {}
});
browser && toast.push(output);
await refetch()
}
async function cleanupBuildCache() {
const { output } = await request('/api/v1/servers/cleanups/caches', $session, {
body: {}
});
browser && toast.push(output);
await refetch()
}
async function cleanupContainers() {
const { output } = await request('/api/v1/servers/cleanups/containers', $session, {
body: {}
});
browser && toast.push(output);
await refetch()
}
</script>
<div class="min-h-full text-white" in:fade={{ duration: 100 }}>
<div class="py-5 text-left px-6 text-3xl tracking-tight font-bold flex items-center">
<div>Servers</div>
</div>
</div>
<div in:fade={{ duration: 100 }}>
<div class="max-w-4xl mx-auto px-6 pb-4 h-64 ">
<div class="text-center font-bold text-xl">{hostname}</div>
<div class="font-bold">Filesystem Usage</div>
{#each filesystems as filesystem}
<!-- <div>{JSON.stringify(filesystem)}</div> -->
<div class="text-xs">
{filesystem.mount}: {(filesystem.available / 1024 / 1024).toFixed()}MB ({filesystem.use}%) free of {(filesystem.size /1024 /1024).toFixed()}MB
</div>
{/each}
<div class="font-bold">Docker Reclaimable</div>
{#each dockerReclaimable as reclaimable}
<div class="text-xs">
{reclaimable.Type}: {reclaimable.Reclaimable} of {reclaimable.Size}
</div>
{/each}
<button class="button hover:bg-warmGray-700 bg-warmGray-800 rounded p-2 font-bold" on:click={cleanupVolumes}>Cleanup unused volumes</button>
<button class="button hover:bg-warmGray-700 bg-warmGray-800 rounded p-2 font-bold" on:click={cleanupImages}>Cleanup unused images</button>
<button class="button hover:bg-warmGray-700 bg-warmGray-800 rounded p-2 font-bold" on:click={cleanupBuildCache}>Cleanup build caches</button>
<button class="button hover:bg-warmGray-700 bg-warmGray-800 rounded p-2 font-bold" on:click={cleanupContainers}>Cleanup containers</button>
</div>
</div>

View File

@ -13,6 +13,7 @@
let service = {};
async function loadServiceConfig() {
if ($page.params.name) {
try {
service = await request(`/api/v1/services/${$page.params.name}`, $session);
} catch (error) {
@ -39,6 +40,8 @@
<div>VSCode Server</div>
{:else if $page.params.name === 'minio'}
<div>MinIO</div>
{:else if $page.params.name.match(/wp-/)}
<div>Wordpress<span class="flex text-xs items-center justify-center">({service.config.baseURL.replace('https://','')})</span></div>
{/if}
<div class="px-4">
@ -76,6 +79,15 @@
class="w-7 mx-auto"
src="https://cdn.coollabs.io/assets/coolify/services/minio/MINIO_Bird.png"
/>
{:else if $page.params.name.match(/wp-/)}
<svg class="w-8 mx-auto" viewBox="0 0 128 128">
<path
fill-rule="evenodd"
clip-rule="evenodd"
fill="white"
d="M64.094 126.224c34.275-.052 62.021-27.933 62.021-62.325 0-33.833-27.618-61.697-60.613-62.286C30.85.995 1.894 29.113 1.885 63.21c-.01 35.079 27.612 63.064 62.209 63.014zM63.993 4.63c32.907-.011 59.126 26.725 59.116 60.28-.011 31.679-26.925 58.18-59.092 58.187-32.771.007-59.125-26.563-59.124-59.608.002-32.193 26.766-58.848 59.1-58.859zM39.157 35.896c.538 1.793-.968 2.417-2.569 2.542-1.685.13-3.369.257-5.325.406 6.456 19.234 12.815 38.183 19.325 57.573.464-.759.655-.973.739-1.223 3.574-10.682 7.168-21.357 10.651-32.069.318-.977.16-2.271-.188-3.275-1.843-5.32-4.051-10.524-5.667-15.908-1.105-3.686-2.571-6.071-6.928-5.644-.742.073-1.648-1.524-2.479-2.349 1.005-.6 2.003-1.704 3.017-1.719a849.593 849.593 0 0126.618.008c1.018.017 2.016 1.15 3.021 1.765-.88.804-1.639 2.01-2.668 2.321-1.651.498-3.482.404-5.458.58l19.349 57.56c2.931-9.736 5.658-18.676 8.31-27.639 2.366-8.001.956-15.473-3.322-22.52-1.286-2.119-2.866-4.175-3.595-6.486-.828-2.629-1.516-5.622-1.077-8.259.745-4.469 4.174-6.688 8.814-7.113C74.333.881 34.431 9.317 19.728 34.922c5.66-.261 11.064-.604 16.472-.678 1.022-.013 2.717.851 2.957 1.652zm10.117 77.971c-.118.345-.125.729-.218 1.302 10.943 3.034 21.675 2.815 32.659-.886l-16.78-45.96c-5.37 15.611-10.52 30.575-15.661 45.544zm-8.456-2.078l-25.281-69.35c-11.405 22.278-2.729 56.268 25.281 69.35zm76.428-44.562c.802-10.534-2.832-25.119-5.97-27.125-.35 3.875-.106 8.186-1.218 12.114-2.617 9.255-5.817 18.349-8.899 27.468-3.35 9.912-6.832 19.779-10.257 29.666 16.092-9.539 24.935-23.618 26.344-42.123z"
/>
</svg>
{/if}
</div>
<a target="_blank" class="icon mx-2" href={service.config.baseURL}>
@ -106,6 +118,8 @@
<CodeServer {service} />
{:else if $page.params.name === 'minio'}
<MinIo {service} />
{:else if $page.params.name.match(/wp-/)}
<div class="font-bold">Nothing to show here. Enjoy using WordPress!</div>
{/if}
</div>
</div>

View File

@ -2,7 +2,7 @@
import { fade } from 'svelte/transition';
import { toast } from '@zerodevx/svelte-toast';
import { newService } from '$store';
import { newService, newWordpressService } from '$store';
import { page, session } from '$app/stores';
import { request } from '$lib/request';
import { goto } from '$app/navigation';
@ -25,7 +25,7 @@
$: deployableNocoDB = $newService.baseURL === '' || $newService.baseURL === null;
$: deployableCodeServer = $newService.baseURL === '' || $newService.baseURL === null;
$: deployableMinIO = $newService.baseURL === '' || $newService.baseURL === null;
$: deployableWordpress = false
let loading = false;
async function deployPlausible() {
try {
@ -115,6 +115,28 @@
loading = false;
}
}
async function deployWordpress() {
try {
loading = true;
await request(`/api/v1/services/deploy/${$page.params.type}`, $session, {
body: {
...$newWordpressService
}
});
if (browser) {
toast.push(
'Service deployment queued.<br><br><br>It could take 2-5 minutes to be ready, be patient and grab a coffee/tea!',
{ duration: 4000 }
);
goto(`/dashboard/services`, { replaceState: true });
}
} catch (error) {
console.log(error);
browser && toast.push('Oops something went wrong. See console.log.');
} finally {
loading = false;
}
}
</script>
@ -129,13 +151,15 @@
<span class="text-blue-500 px-2 capitalize">VSCode Server</span>
{:else if $page.params.type === 'minio'}
<span class="text-blue-500 px-2 capitalize">MinIO</span>
{:else if $page.params.type === 'wordpress'}
<span class="text-blue-500 px-2 capitalize">Wordpress</span>
{/if}
</div>
</div>
{#if loading}
<Loading />
{:else if $page.params.type === 'plausible'}
<div class="space-y-2 max-w-4xl mx-auto px-6 flex-col text-center" in:fade={{ duration: 100 }}>
<div class="space-y-2 max-w-xl mx-auto px-6 flex-col text-center" in:fade={{ duration: 100 }}>
<div class="grid grid-flow-row">
<label for="Domain"
>Domain <TooltipInfo
@ -298,4 +322,188 @@
Deploy
</button>
</div>
{:else if $page.params.type === 'wordpress'}
<div class="space-y-2 max-w-xl mx-auto px-6 flex-col text-center" in:fade={{ duration: 100 }}>
<div class="grid grid-flow-row pb-5">
<label for="Domain"
>Domain <TooltipInfo
position="right"
label={`You could reach your Wordpress instance here.`}
/></label
>
<input
id="Domain"
class:border-red-500={$newWordpressService.baseURL == null || $newWordpressService.baseURL == ''}
bind:value={$newWordpressService.baseURL}
placeholder="wordpress.coollabs.io"
/>
</div>
<div class="">
<div class="px-4 sm:px-6">
<ul class="divide-y divide-warmGray-800">
<li class="py-4 flex items-center justify-between text-left">
<div class="flex flex-col">
<p class="text-base font-bold text-warmGray-100">Use remote MySQL database?</p>
<p class="text-sm font-medium text-warmGray-400">
If not, Coolify will create a local database for you.
</p>
</div>
<button
type="button"
on:click={() => ($newWordpressService.remoteDB = !$newWordpressService.remoteDB)}
aria-pressed="true"
class="relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200"
class:bg-green-600={$newWordpressService.remoteDB}
class:bg-warmGray-700={!$newWordpressService.remoteDB}
>
<span class="sr-only">Use setting</span>
<span
class="pointer-events-none relative inline-block h-5 w-5 rounded-full bg-white shadow transition ease-in-out duration-200 transform"
class:translate-x-5={$newWordpressService.remoteDB}
class:translate-x-0={!$newWordpressService.remoteDB}
>
<span
class=" ease-in duration-200 absolute inset-0 h-full w-full flex items-center justify-center transition-opacity"
class:opacity-0={$newWordpressService.remoteDB}
class:opacity-100={!$newWordpressService.remoteDB}
aria-hidden="true"
>
<svg class="bg-white h-3 w-3 text-red-600" fill="none" viewBox="0 0 12 12">
<path
d="M4 8l2-2m0 0l2-2M6 6L4 4m2 2l2 2"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</span>
<span
class="ease-out duration-100 absolute inset-0 h-full w-full flex items-center justify-center transition-opacity"
aria-hidden="true"
class:opacity-100={$newWordpressService.remoteDB}
class:opacity-0={!$newWordpressService.remoteDB}
>
<svg
class="bg-white h-3 w-3 text-green-600"
fill="currentColor"
viewBox="0 0 12 12"
>
<path
d="M3.707 5.293a1 1 0 00-1.414 1.414l1.414-1.414zM5 8l-.707.707a1 1 0 001.414 0L5 8zm4.707-3.293a1 1 0 00-1.414-1.414l1.414 1.414zm-7.414 2l2 2 1.414-1.414-2-2-1.414 1.414zm3.414 2l4-4-1.414-1.414-4 4 1.414 1.414z"
/>
</svg>
</span>
</span>
</button>
</li>
</ul>
</div>
{#if $newWordpressService.remoteDB}
<div class="grid grid-flow-row pb-5">
<label for="database.host"
>DB Host <TooltipInfo
position="right"
label={`IP address of a remote Mysql instance.`}
/></label
>
<input
id="database.host"
class:border-red-500={$newWordpressService.database.host == null ||
$newWordpressService.database.host == ''}
bind:value={$newWordpressService.database.host}
placeholder="10.10.10.10:3306"
/>
</div>
<div class="grid grid-flow-row pb-5">
<label for="database.user"
>DB User <TooltipInfo position="right" label={`Database user.`} /></label
>
<input
id="database.user"
class:border-red-500={$newWordpressService.database.user == null ||
$newWordpressService.database.user == ''}
bind:value={$newWordpressService.database.user}
placeholder="wordpressuser"
/>
</div>
<div class="grid grid-flow-row pb-5">
<label for="database.password"
>DB Password <TooltipInfo
position="right"
label={`Database password for the database user.`}
/></label
>
<input
id="database.password"
class:border-red-500={$newWordpressService.database.password == null ||
$newWordpressService.database.password == ''}
bind:value={$newWordpressService.database.password}
placeholder="supersecretuserpasswordforwordpress"
/>
</div>
<div class="grid grid-flow-row pb-5">
<label for="database.name"
>DB Name<TooltipInfo
position="right"
label={`Database name`}
/></label
>
<input
id="database.name"
class:border-red-500={$newWordpressService.database.name == null ||
$newWordpressService.database.name == ''}
bind:value={$newWordpressService.database.name}
placeholder="wordpress"
/>
</div>
<div class="grid grid-flow-row pb-5">
<label for="database.tablePrefix"
>DB Table Prefix <TooltipInfo
position="right"
label={`Table prefix for wordpress`}
/></label
>
<input
id="database.tablePrefix"
class:border-red-500={$newWordpressService.database.tablePrefix == null ||
$newWordpressService.database.tablePrefix == ''}
bind:value={$newWordpressService.database.tablePrefix}
placeholder="wordpress"
/>
</div>
{/if}
<div class="grid grid-flow-row py-5">
<label for="wordpressExtraConfiguration"
>Wordpress Configuration Extra <TooltipInfo
position="right"
label={`Database password for the database user.`}
/></label
>
<textarea
class="h-32"
id="wordpressExtraConfiguration"
bind:value={$newWordpressService.wordpressExtraConfiguration}
placeholder="// Example Extra Configuration
define('WP_ALLOW_MULTISITE', true );
define('MULTISITE', true);
define('SUBDOMAIN_INSTALL', false);"
/>
</div>
</div>
<button
disabled={deployableWordpress}
class:cursor-not-allowed={deployableWordpress}
class:bg-blue-500={!deployableWordpress}
class:hover:bg-blue-400={!deployableWordpress}
class:hover:bg-transparent={deployableWordpress}
class:text-warmGray-700={deployableWordpress}
class:text-white={!deployableWordpress}
class="button p-2 w-64 bg-blue-500 hover:bg-blue-400 text-white"
on:click={deployWordpress}
>
Deploy
</button>
</div>
{/if}

View File

@ -10,11 +10,11 @@
Select a service
</div>
</div>
<div class="text-center space-y-2 max-w-4xl mx-auto px-6" in:fade={{ duration: 100 }}>
<div class="text-center space-y-2 max-w-7xl mx-auto px-6" in:fade={{ duration: 100 }}>
{#if $page.path === '/service/new'}
<div class="flex justify-center space-x-4 font-bold pb-6">
<div class="flex justify-center font-bold pb-6 flex-wrap">
<div
class="text-center flex-col items-center cursor-pointer ease-in-out hover:scale-105 duration-100 border-2 border-dashed border-transparent hover:border-blue-500 p-2 rounded bg-warmGray-800 w-48"
class="text-center flex-col items-center cursor-pointer ease-in-out hover:scale-105 duration-100 border-2 border-dashed border-transparent hover:border-blue-500 p-2 m-2 rounded bg-warmGray-800 w-48"
on:click={() => goto('/service/new/plausible')}
>
<img
@ -25,7 +25,7 @@
<div class="text-white">Plausible Analytics</div>
</div>
<div
class="text-center flex-col items-center cursor-pointer ease-in-out hover:scale-105 duration-100 border-2 border-dashed border-transparent hover:border-white p-2 rounded bg-warmGray-800 w-48"
class="text-center flex-col items-center cursor-pointer ease-in-out hover:scale-105 duration-100 border-2 border-dashed border-transparent hover:border-blue-500 p-2 m-2 rounded bg-warmGray-800 w-48"
on:click={() => goto('/service/new/nocodb')}
>
<img
@ -37,7 +37,7 @@
<div class="text-white">NocoDB</div>
</div>
<div
class="text-center flex-col items-center cursor-pointer ease-in-out hover:scale-105 duration-100 border-2 border-dashed border-transparent hover:border-green-500 p-2 rounded bg-warmGray-800 w-48"
class="text-center flex-col items-center cursor-pointer ease-in-out hover:scale-105 duration-100 border-2 border-dashed border-transparent hover:border-blue-500 p-2 m-2 rounded bg-warmGray-800 w-48"
on:click={() => goto('/service/new/code-server')}
>
<svg class="w-14 mx-auto pb-2" viewBox="0 0 128 128">
@ -59,7 +59,7 @@
<div class="text-white">VSCode Server</div>
</div>
<div
class="text-center flex-col items-center cursor-pointer ease-in-out hover:scale-105 duration-100 border-2 border-dashed border-transparent hover:border-red-500 p-2 rounded bg-warmGray-800 w-48"
class="text-center flex-col items-center cursor-pointer ease-in-out hover:scale-105 duration-100 border-2 border-dashed border-transparent hover:border-blue-500 p-2 m-2 rounded bg-warmGray-800 w-48"
on:click={() => goto('/service/new/minio')}
>
<img
@ -70,6 +70,21 @@
<div class="flex-1" />
<div class="text-white">MinIO</div>
</div>
<div
class="text-center flex-col items-center cursor-pointer ease-in-out hover:scale-105 duration-100 border-2 border-dashed border-transparent hover:border-blue-500 p-2 m-2 rounded bg-warmGray-800 w-48"
on:click={() => goto('/service/new/wordpress')}
>
<svg class="w-14 mx-auto pb-2" viewBox="0 0 128 128">
<path
fill-rule="evenodd"
clip-rule="evenodd"
fill="white"
d="M64.094 126.224c34.275-.052 62.021-27.933 62.021-62.325 0-33.833-27.618-61.697-60.613-62.286C30.85.995 1.894 29.113 1.885 63.21c-.01 35.079 27.612 63.064 62.209 63.014zM63.993 4.63c32.907-.011 59.126 26.725 59.116 60.28-.011 31.679-26.925 58.18-59.092 58.187-32.771.007-59.125-26.563-59.124-59.608.002-32.193 26.766-58.848 59.1-58.859zM39.157 35.896c.538 1.793-.968 2.417-2.569 2.542-1.685.13-3.369.257-5.325.406 6.456 19.234 12.815 38.183 19.325 57.573.464-.759.655-.973.739-1.223 3.574-10.682 7.168-21.357 10.651-32.069.318-.977.16-2.271-.188-3.275-1.843-5.32-4.051-10.524-5.667-15.908-1.105-3.686-2.571-6.071-6.928-5.644-.742.073-1.648-1.524-2.479-2.349 1.005-.6 2.003-1.704 3.017-1.719a849.593 849.593 0 0126.618.008c1.018.017 2.016 1.15 3.021 1.765-.88.804-1.639 2.01-2.668 2.321-1.651.498-3.482.404-5.458.58l19.349 57.56c2.931-9.736 5.658-18.676 8.31-27.639 2.366-8.001.956-15.473-3.322-22.52-1.286-2.119-2.866-4.175-3.595-6.486-.828-2.629-1.516-5.622-1.077-8.259.745-4.469 4.174-6.688 8.814-7.113C74.333.881 34.431 9.317 19.728 34.922c5.66-.261 11.064-.604 16.472-.678 1.022-.013 2.717.851 2.957 1.652zm10.117 77.971c-.118.345-.125.729-.218 1.302 10.943 3.034 21.675 2.815 32.659-.886l-16.78-45.96c-5.37 15.611-10.52 30.575-15.661 45.544zm-8.456-2.078l-25.281-69.35c-11.405 22.278-2.729 56.268 25.281 69.35zm76.428-44.562c.802-10.534-2.832-25.119-5.97-27.125-.35 3.875-.106 8.186-1.218 12.114-2.617 9.255-5.817 18.349-8.899 27.468-3.35 9.912-6.832 19.779-10.257 29.666 16.092-9.539 24.935-23.618 26.344-42.123z"
/>
</svg>
<div class="flex-1" />
<div class="text-white">Wordpress</div>
</div>
</div>
{/if}
</div>

View File

@ -83,7 +83,7 @@
>
<span class="sr-only">Use setting</span>
<span
class="pointer-events-none relative inline-block h-5 w-5 rounded-full bg-white shadow transition ease-in-out duration-200"
class="pointer-events-none relative inline-block h-5 w-5 rounded-full bg-white shadow transition ease-in-out duration-200 transform"
class:translate-x-5={settings?.allowRegistration}
class:translate-x-0={!settings?.allowRegistration}
>
@ -143,7 +143,7 @@
>
<span class="sr-only">Use setting</span>
<span
class="pointer-events-none relative inline-block h-5 w-5 rounded-full bg-white shadow transition ease-in-out duration-200"
class="pointer-events-none relative inline-block h-5 w-5 rounded-full bg-white shadow transition ease-in-out duration-200 transform"
class:translate-x-5={settings?.sendErrors}
class:translate-x-0={!settings?.sendErrors}
>

View File

@ -167,5 +167,17 @@ export const initialNewService = {
userPasswordAgain: null,
baseURL: null
};
export const newWordpressService = writable({
baseURL: null,
remoteDB: false,
database: {
host: null,
name: 'wordpress',
user: null,
password: null,
tablePrefix: 'wordpress'
},
wordpressExtraConfiguration: null
});
export const isPullRequestPermissionsGranted = writable(false);