mirror of
https://github.com/ershisan99/coolify.git
synced 2025-12-18 20:59:24 +00:00
Compare commits
87 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
79dfc6a660 | ||
|
|
972b0fa811 | ||
|
|
ad51a9ebc8 | ||
|
|
51a40d049d | ||
|
|
8b3113bd92 | ||
|
|
d6b6938555 | ||
|
|
ce52608f19 | ||
|
|
ede37d296b | ||
|
|
6374b1284b | ||
|
|
6ac8dd8907 | ||
|
|
24c655d7ef | ||
|
|
1f087cc29a | ||
|
|
c3684a1650 | ||
|
|
a410fd0776 | ||
|
|
271fb1358d | ||
|
|
a4d53a28eb | ||
|
|
e69e32f6c7 | ||
|
|
650409dde3 | ||
|
|
f3f4bb5105 | ||
|
|
9c02af6b52 | ||
|
|
6a3f4ba171 | ||
|
|
6a6426fe6b | ||
|
|
21256746c3 | ||
|
|
c34d643f95 | ||
|
|
0be402af82 | ||
|
|
b5b0b6524d | ||
|
|
22f1a3c908 | ||
|
|
fa5f439858 | ||
|
|
7cc760eecf | ||
|
|
af0652f6b2 | ||
|
|
9e009bebaa | ||
|
|
8e53ae3484 | ||
|
|
7ceb8f1537 | ||
|
|
b0eae8cfe9 | ||
|
|
febef372b8 | ||
|
|
a18e3659aa | ||
|
|
e2e342851a | ||
|
|
bee3292088 | ||
|
|
f56d4dbbb3 | ||
|
|
eccd7c96d7 | ||
|
|
4046c472ed | ||
|
|
0da4a1024a | ||
|
|
aa2f328640 | ||
|
|
4d22b610b6 | ||
|
|
e91c3eab9c | ||
|
|
2e8fd6f0c7 | ||
|
|
90fde24b40 | ||
|
|
02a1f50776 | ||
|
|
57b97a9204 | ||
|
|
1ec03693d3 | ||
|
|
4246d86694 | ||
|
|
2cce1f8459 | ||
|
|
3937cfec53 | ||
|
|
259aeeb67a | ||
|
|
9d53bc0926 | ||
|
|
1211f3c9fd | ||
|
|
c07d6aa702 | ||
|
|
4f662dbf21 | ||
|
|
a4301c5d23 | ||
|
|
86b7824c78 | ||
|
|
435f063c36 | ||
|
|
902a764ff2 | ||
|
|
4097378847 | ||
|
|
5f3567e808 | ||
|
|
7325353ced | ||
|
|
68f5b32876 | ||
|
|
8d4eaad920 | ||
|
|
4b38865cc9 | ||
|
|
030cb124e5 | ||
|
|
fd363ec017 | ||
|
|
8b813fb07a | ||
|
|
326f0dac1b | ||
|
|
828faaf2b1 | ||
|
|
9582664406 | ||
|
|
ec5474b72b | ||
|
|
62d1011d9f | ||
|
|
0a7ec6bd20 | ||
|
|
b84c37cd8f | ||
|
|
887d65e512 | ||
|
|
3543a9c809 | ||
|
|
40da3ff9fe | ||
|
|
f94e17134e | ||
|
|
40cbee0d75 | ||
|
|
c98ed5338a | ||
|
|
27f1e1d7cd | ||
|
|
8f3f9ebade | ||
|
|
1bd33fea98 |
47
.github/ISSUE_TEMPLATE/--bug-report.yaml
vendored
Normal file
47
.github/ISSUE_TEMPLATE/--bug-report.yaml
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
name: 🐞 Bug report
|
||||
description: Create a bug report to help us improve coolify
|
||||
title: "[Bug]: "
|
||||
labels: [Bug]
|
||||
assignees:
|
||||
- andrasbacsai
|
||||
- vasani-arpit
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for taking the time to fill out this bug report! Please fill the form in English
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Is there an existing issue for this?
|
||||
options:
|
||||
- label: I have searched the existing issues
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Description
|
||||
description: A concise description of what you're experiencing and what you expect.
|
||||
placeholder: |
|
||||
When I do <X>, <Y> happens and I see the error message attached below:
|
||||
```...```
|
||||
What I expect is <Z>
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Steps To Reproduce
|
||||
description: Add steps to reproduce this behaviour, include console / network logs & videos
|
||||
placeholder: |
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: Version
|
||||
description: "The version of your coolify Instance"
|
||||
placeholder: "2.5.2"
|
||||
validations:
|
||||
required: true
|
||||
31
.github/ISSUE_TEMPLATE/--feature-request.yaml
vendored
Normal file
31
.github/ISSUE_TEMPLATE/--feature-request.yaml
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
name: 🛠️ Feature request
|
||||
description: Suggest an idea to improve coolify
|
||||
title: '[Feature]: '
|
||||
labels: [Enhancement]
|
||||
assignees:
|
||||
- andrasbacsai
|
||||
- vasani-arpit
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for taking the time to request a feature for coolify! Please also add your request here to get feedback from the community: https://feedback.coolify.io/!
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Is there an existing issue for this?
|
||||
description: Please search to see if an issue related to this feature request already exists.
|
||||
options:
|
||||
- label: I have searched the existing issues
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Summary
|
||||
description: One paragraph description of the feature.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Why should this be worked on?
|
||||
description: A concise description of the problems or use cases for this feature request.
|
||||
validations:
|
||||
required: true
|
||||
20
.github/ISSUE_TEMPLATE/--task.yaml
vendored
Normal file
20
.github/ISSUE_TEMPLATE/--task.yaml
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
name: 📝 Task
|
||||
description: Create a task for the team to work on
|
||||
title: "[Task]: "
|
||||
labels: [Task]
|
||||
body:
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Is there an existing issue for this?
|
||||
description: Please search to see if an issue related to this already exists.
|
||||
options:
|
||||
- label: I have searched the existing issues
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: SubTasks
|
||||
placeholder: |
|
||||
- Sub Task 1
|
||||
- Sub Task 2
|
||||
validations:
|
||||
required: false
|
||||
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
blank_issues_enabled: true
|
||||
contact_links:
|
||||
- name: 🤔 Questions and Help
|
||||
url: https://discord.com/invite/6rDM4fkymF
|
||||
about: Reach out to us on discord or our github discussions page.
|
||||
39
.github/workflows/github-actions.yml
vendored
Normal file
39
.github/workflows/github-actions.yml
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
name: release-coolify
|
||||
|
||||
on:
|
||||
release:
|
||||
types: published
|
||||
|
||||
jobs:
|
||||
make-it-coolifyed:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
-
|
||||
name: Login to DockerHub
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
-
|
||||
name: Get current package version
|
||||
uses: martinbeentjes/npm-get-version-action@v1.2.3
|
||||
id: package-version
|
||||
-
|
||||
name: Build and push
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: coollabsio/coolify:latest,coollabsio/coolify:${{steps.package-version.outputs.current-version}}
|
||||
cache-from: type=registry,ref=coollabsio/coolify:buildcache
|
||||
cache-to: type=registry,ref=coollabsio/coolify:buildcache,mode=max
|
||||
@@ -8,6 +8,9 @@ https://demo.coolify.io/
|
||||
|
||||
(If it is unresponsive, that means someone overloaded the server. 🙃)
|
||||
|
||||
## Feedback
|
||||
If you have a new service / build pack you would like to add, raise an idea [here](https://feedback.coolify.io/) to get feedback from the community!
|
||||
|
||||
## How to install
|
||||
|
||||
Installation is automated with the following command:
|
||||
@@ -52,10 +55,10 @@ These are the predefined build packs, but with the Docker build pack, you can ho
|
||||
- NuxtJS
|
||||
- NextJS
|
||||
- React/Preact
|
||||
- NextJS
|
||||
- Gatsby
|
||||
- Svelte
|
||||
- PHP
|
||||
- Laravel
|
||||
- Rust
|
||||
- Docker
|
||||
|
||||
@@ -64,6 +67,7 @@ These are the predefined build packs, but with the Docker build pack, you can ho
|
||||
One-click database is ready to be used internally or shared over the internet:
|
||||
|
||||
- MongoDB
|
||||
- MariaDB
|
||||
- MySQL
|
||||
- PostgreSQL
|
||||
- CouchDB
|
||||
@@ -85,6 +89,8 @@ You can host cool open-source services as well:
|
||||
- [Uptime Kuma](https://github.com/louislam/uptime-kuma)
|
||||
- [MeiliSearch](https://github.com/meilisearch/meilisearch)
|
||||
- [Umami](https://github.com/mikecao/umami)
|
||||
- [Fider](https://fider.io)
|
||||
- [Hasura](https://hasura.io)
|
||||
|
||||
## Migration from v1
|
||||
|
||||
|
||||
36
package.json
36
package.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "coolify",
|
||||
"description": "An open-source & self-hostable Heroku / Netlify alternative.",
|
||||
"version": "2.6.0",
|
||||
"version": "2.8.0",
|
||||
"license": "AGPL-3.0",
|
||||
"scripts": {
|
||||
"dev": "docker-compose -f docker-compose-dev.yaml up -d && cross-env NODE_ENV=development & svelte-kit dev --host 0.0.0.0",
|
||||
@@ -30,60 +30,62 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/adapter-node": "1.0.0-next.73",
|
||||
"@sveltejs/kit": "1.0.0-next.316",
|
||||
"@types/js-cookie": "3.0.1",
|
||||
"@sveltejs/kit": "1.0.0-next.326",
|
||||
"@types/js-cookie": "3.0.2",
|
||||
"@types/js-yaml": "4.0.5",
|
||||
"@types/node": "17.0.25",
|
||||
"@types/node-forge": "1.0.1",
|
||||
"@types/node": "17.0.31",
|
||||
"@types/node-forge": "1.0.2",
|
||||
"@typescript-eslint/eslint-plugin": "4.31.1",
|
||||
"@typescript-eslint/parser": "4.31.1",
|
||||
"@zerodevx/svelte-toast": "0.7.1",
|
||||
"autoprefixer": "10.4.4",
|
||||
"autoprefixer": "10.4.7",
|
||||
"cross-env": "7.0.3",
|
||||
"cross-var": "1.1.0",
|
||||
"eslint": "7.32.0",
|
||||
"eslint-config-prettier": "8.5.0",
|
||||
"eslint-plugin-svelte3": "3.4.1",
|
||||
"husky": "7.0.4",
|
||||
"lint-staged": "12.4.0",
|
||||
"postcss": "8.4.12",
|
||||
"lint-staged": "12.4.1",
|
||||
"postcss": "8.4.13",
|
||||
"prettier": "2.6.2",
|
||||
"prettier-plugin-svelte": "2.7.0",
|
||||
"prettier-plugin-tailwindcss": "0.1.10",
|
||||
"prisma": "3.11.1",
|
||||
"svelte": "3.47.0",
|
||||
"svelte": "3.48.0",
|
||||
"svelte-check": "2.7.0",
|
||||
"svelte-preprocess": "4.10.6",
|
||||
"svelte-select": "4.4.7",
|
||||
"sveltekit-i18n": "2.1.2",
|
||||
"sveltekit-i18n": "2.2.1",
|
||||
"tailwindcss": "3.0.24",
|
||||
"ts-node": "10.7.0",
|
||||
"tslib": "2.3.1",
|
||||
"typescript": "4.6.3"
|
||||
"tslib": "2.4.0",
|
||||
"typescript": "4.6.4"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@iarna/toml": "2.2.5",
|
||||
"@prisma/client": "3.11.1",
|
||||
"@sentry/node": "6.19.6",
|
||||
"@sentry/node": "6.19.7",
|
||||
"bcryptjs": "2.4.3",
|
||||
"bullmq": "1.80.4",
|
||||
"bullmq": "1.81.4",
|
||||
"compare-versions": "4.1.3",
|
||||
"cookie": "0.5.0",
|
||||
"cuid": "2.1.8",
|
||||
"dayjs": "1.11.1",
|
||||
"dayjs": "1.11.2",
|
||||
"dockerode": "3.3.1",
|
||||
"dotenv-extended": "2.9.0",
|
||||
"generate-password": "1.7.0",
|
||||
"get-port": "6.1.2",
|
||||
"got": "12.0.3",
|
||||
"got": "12.0.4",
|
||||
"is-ip": "4.0.0",
|
||||
"js-cookie": "3.0.1",
|
||||
"js-yaml": "4.1.0",
|
||||
"jsonwebtoken": "8.5.1",
|
||||
"mustache": "4.2.0",
|
||||
"node-forge": "1.3.1",
|
||||
"node-os-utils": "1.3.6",
|
||||
"p-limit": "4.0.0",
|
||||
"svelte-kit-cookie-session": "2.1.3",
|
||||
"svelte-kit-cookie-session": "2.1.4",
|
||||
"tailwindcss-scrollbar": "0.1.0",
|
||||
"unique-names-generator": "4.7.1"
|
||||
},
|
||||
|
||||
374
pnpm-lock.yaml
generated
374
pnpm-lock.yaml
generated
@@ -1,27 +1,27 @@
|
||||
lockfileVersion: 5.3
|
||||
lockfileVersion: 5.4
|
||||
|
||||
specifiers:
|
||||
'@iarna/toml': 2.2.5
|
||||
'@prisma/client': 3.11.1
|
||||
'@sentry/node': 6.19.6
|
||||
'@sentry/node': 6.19.7
|
||||
'@sveltejs/adapter-node': 1.0.0-next.73
|
||||
'@sveltejs/kit': 1.0.0-next.316
|
||||
'@types/js-cookie': 3.0.1
|
||||
'@sveltejs/kit': 1.0.0-next.326
|
||||
'@types/js-cookie': 3.0.2
|
||||
'@types/js-yaml': 4.0.5
|
||||
'@types/node': 17.0.25
|
||||
'@types/node-forge': 1.0.1
|
||||
'@types/node': 17.0.31
|
||||
'@types/node-forge': 1.0.2
|
||||
'@typescript-eslint/eslint-plugin': 4.31.1
|
||||
'@typescript-eslint/parser': 4.31.1
|
||||
'@zerodevx/svelte-toast': 0.7.1
|
||||
autoprefixer: 10.4.4
|
||||
autoprefixer: 10.4.7
|
||||
bcryptjs: 2.4.3
|
||||
bullmq: 1.80.4
|
||||
bullmq: 1.81.4
|
||||
compare-versions: 4.1.3
|
||||
cookie: 0.5.0
|
||||
cross-env: 7.0.3
|
||||
cross-var: 1.1.0
|
||||
cuid: 2.1.8
|
||||
dayjs: 1.11.1
|
||||
dayjs: 1.11.2
|
||||
dockerode: 3.3.1
|
||||
dotenv-extended: 2.9.0
|
||||
eslint: 7.32.0
|
||||
@@ -29,90 +29,94 @@ specifiers:
|
||||
eslint-plugin-svelte3: 3.4.1
|
||||
generate-password: 1.7.0
|
||||
get-port: 6.1.2
|
||||
got: 12.0.3
|
||||
got: 12.0.4
|
||||
husky: 7.0.4
|
||||
is-ip: 4.0.0
|
||||
js-cookie: 3.0.1
|
||||
js-yaml: 4.1.0
|
||||
jsonwebtoken: 8.5.1
|
||||
lint-staged: 12.4.0
|
||||
lint-staged: 12.4.1
|
||||
mustache: 4.2.0
|
||||
node-forge: 1.3.1
|
||||
node-os-utils: 1.3.6
|
||||
p-limit: 4.0.0
|
||||
postcss: 8.4.12
|
||||
postcss: 8.4.13
|
||||
prettier: 2.6.2
|
||||
prettier-plugin-svelte: 2.7.0
|
||||
prettier-plugin-tailwindcss: 0.1.10
|
||||
prisma: 3.11.1
|
||||
svelte: 3.47.0
|
||||
svelte: 3.48.0
|
||||
svelte-check: 2.7.0
|
||||
svelte-kit-cookie-session: 2.1.3
|
||||
svelte-kit-cookie-session: 2.1.4
|
||||
svelte-preprocess: 4.10.6
|
||||
svelte-select: 4.4.7
|
||||
sveltekit-i18n: 2.1.2
|
||||
sveltekit-i18n: 2.2.1
|
||||
tailwindcss: 3.0.24
|
||||
tailwindcss-scrollbar: 0.1.0
|
||||
ts-node: 10.7.0
|
||||
tslib: 2.3.1
|
||||
typescript: 4.6.3
|
||||
tslib: 2.4.0
|
||||
typescript: 4.6.4
|
||||
unique-names-generator: 4.7.1
|
||||
|
||||
dependencies:
|
||||
'@iarna/toml': 2.2.5
|
||||
'@prisma/client': 3.11.1_prisma@3.11.1
|
||||
'@sentry/node': 6.19.6
|
||||
'@sentry/node': 6.19.7
|
||||
bcryptjs: 2.4.3
|
||||
bullmq: 1.80.4
|
||||
bullmq: 1.81.4
|
||||
compare-versions: 4.1.3
|
||||
cookie: 0.5.0
|
||||
cuid: 2.1.8
|
||||
dayjs: 1.11.1
|
||||
dayjs: 1.11.2
|
||||
dockerode: 3.3.1
|
||||
dotenv-extended: 2.9.0
|
||||
generate-password: 1.7.0
|
||||
get-port: 6.1.2
|
||||
got: 12.0.3
|
||||
got: 12.0.4
|
||||
is-ip: 4.0.0
|
||||
js-cookie: 3.0.1
|
||||
js-yaml: 4.1.0
|
||||
jsonwebtoken: 8.5.1
|
||||
mustache: 4.2.0
|
||||
node-forge: 1.3.1
|
||||
node-os-utils: 1.3.6
|
||||
p-limit: 4.0.0
|
||||
svelte-kit-cookie-session: 2.1.3
|
||||
svelte-kit-cookie-session: 2.1.4
|
||||
tailwindcss-scrollbar: 0.1.0_tailwindcss@3.0.24
|
||||
unique-names-generator: 4.7.1
|
||||
|
||||
devDependencies:
|
||||
'@sveltejs/adapter-node': 1.0.0-next.73
|
||||
'@sveltejs/kit': 1.0.0-next.316_svelte@3.47.0
|
||||
'@types/js-cookie': 3.0.1
|
||||
'@sveltejs/kit': 1.0.0-next.326_svelte@3.48.0
|
||||
'@types/js-cookie': 3.0.2
|
||||
'@types/js-yaml': 4.0.5
|
||||
'@types/node': 17.0.25
|
||||
'@types/node-forge': 1.0.1
|
||||
'@typescript-eslint/eslint-plugin': 4.31.1_8ede7edd7694646e12d33c52460f622c
|
||||
'@typescript-eslint/parser': 4.31.1_eslint@7.32.0+typescript@4.6.3
|
||||
'@types/node': 17.0.31
|
||||
'@types/node-forge': 1.0.2
|
||||
'@typescript-eslint/eslint-plugin': 4.31.1_lii63oz3usekbu5ehvrcuwn5jy
|
||||
'@typescript-eslint/parser': 4.31.1_e4zyhrvfnqudwdx5bevnvkluy4
|
||||
'@zerodevx/svelte-toast': 0.7.1
|
||||
autoprefixer: 10.4.4_postcss@8.4.12
|
||||
autoprefixer: 10.4.7_postcss@8.4.13
|
||||
cross-env: 7.0.3
|
||||
cross-var: 1.1.0
|
||||
eslint: 7.32.0
|
||||
eslint-config-prettier: 8.5.0_eslint@7.32.0
|
||||
eslint-plugin-svelte3: 3.4.1_eslint@7.32.0+svelte@3.47.0
|
||||
eslint-plugin-svelte3: 3.4.1_6wevxxng4y4ff26nzlndg2wnpa
|
||||
husky: 7.0.4
|
||||
lint-staged: 12.4.0
|
||||
postcss: 8.4.12
|
||||
lint-staged: 12.4.1
|
||||
postcss: 8.4.13
|
||||
prettier: 2.6.2
|
||||
prettier-plugin-svelte: 2.7.0_prettier@2.6.2+svelte@3.47.0
|
||||
prettier-plugin-svelte: 2.7.0_kkjbqzpydplecjtkxrgomroeru
|
||||
prettier-plugin-tailwindcss: 0.1.10_prettier@2.6.2
|
||||
prisma: 3.11.1
|
||||
svelte: 3.47.0
|
||||
svelte-check: 2.7.0_postcss@8.4.12+svelte@3.47.0
|
||||
svelte-preprocess: 4.10.6_41810887ae6c6d59323116f47e33fa38
|
||||
svelte: 3.48.0
|
||||
svelte-check: 2.7.0_f2ke6qjyzu5axsjd6yk3u4tn7a
|
||||
svelte-preprocess: 4.10.6_nq4dx2skq5drra53vttuo4lltu
|
||||
svelte-select: 4.4.7
|
||||
sveltekit-i18n: 2.1.2_svelte@3.47.0
|
||||
sveltekit-i18n: 2.2.1_svelte@3.48.0
|
||||
tailwindcss: 3.0.24_ts-node@10.7.0
|
||||
ts-node: 10.7.0_de7c86b0cde507c63a0402da5b982bd3
|
||||
tslib: 2.3.1
|
||||
typescript: 4.6.3
|
||||
ts-node: 10.7.0_l47be6km5p57gglrggidw5gsgm
|
||||
tslib: 2.4.0
|
||||
typescript: 4.6.4
|
||||
|
||||
packages:
|
||||
/@babel/code-frame/7.12.11:
|
||||
@@ -283,55 +287,55 @@ packages:
|
||||
picomatch: 2.3.0
|
||||
dev: true
|
||||
|
||||
/@sentry/core/6.19.6:
|
||||
/@sentry/core/6.19.7:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-biEotGRr44/vBCOegkTfC9rwqaqRKIpFljKGyYU6/NtzMRooktqOhjmjmItNCMRknArdeaQwA8lk2jcZDXX3Og==
|
||||
integrity: sha512-tOfZ/umqB2AcHPGbIrsFLcvApdTm9ggpi/kQZFkej7kMphjT+SGBiQfYtjyg9jcRW+ilAR4JXC9BGKsdEQ+8Vw==
|
||||
}
|
||||
engines: { node: '>=6' }
|
||||
dependencies:
|
||||
'@sentry/hub': 6.19.6
|
||||
'@sentry/minimal': 6.19.6
|
||||
'@sentry/types': 6.19.6
|
||||
'@sentry/utils': 6.19.6
|
||||
'@sentry/hub': 6.19.7
|
||||
'@sentry/minimal': 6.19.7
|
||||
'@sentry/types': 6.19.7
|
||||
'@sentry/utils': 6.19.7
|
||||
tslib: 1.14.1
|
||||
dev: false
|
||||
|
||||
/@sentry/hub/6.19.6:
|
||||
/@sentry/hub/6.19.7:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-PuEOBZxvx3bjxcXmWWZfWXG+orojQiWzv9LQXjIgroVMKM/GG4QtZbnWl1hOckUj7WtKNl4hEGO2g/6PyCV/vA==
|
||||
integrity: sha512-y3OtbYFAqKHCWezF0EGGr5lcyI2KbaXW2Ik7Xp8Mu9TxbSTuwTe4rTntwg8ngPjUQU3SUHzgjqVB8qjiGqFXCA==
|
||||
}
|
||||
engines: { node: '>=6' }
|
||||
dependencies:
|
||||
'@sentry/types': 6.19.6
|
||||
'@sentry/utils': 6.19.6
|
||||
'@sentry/types': 6.19.7
|
||||
'@sentry/utils': 6.19.7
|
||||
tslib: 1.14.1
|
||||
dev: false
|
||||
|
||||
/@sentry/minimal/6.19.6:
|
||||
/@sentry/minimal/6.19.7:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-T1NKcv+HTlmd8EbzUgnGPl4ySQGHWMCyZ8a8kXVMZOPDzphN3fVIzkYzWmSftCWp0rpabXPt9aRF2mfBKU+mAQ==
|
||||
integrity: sha512-wcYmSJOdvk6VAPx8IcmZgN08XTXRwRtB1aOLZm+MVHjIZIhHoBGZJYTVQS/BWjldsamj2cX3YGbGXNunaCfYJQ==
|
||||
}
|
||||
engines: { node: '>=6' }
|
||||
dependencies:
|
||||
'@sentry/hub': 6.19.6
|
||||
'@sentry/types': 6.19.6
|
||||
'@sentry/hub': 6.19.7
|
||||
'@sentry/types': 6.19.7
|
||||
tslib: 1.14.1
|
||||
dev: false
|
||||
|
||||
/@sentry/node/6.19.6:
|
||||
/@sentry/node/6.19.7:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-kHQMfsy40ZxxdS9zMPmXCOOLWOJbQj6/aVSHt/L1QthYcgkAi7NJQNXnQIPWQDe8eP3DfNIWM7dc446coqjXrQ==
|
||||
integrity: sha512-gtmRC4dAXKODMpHXKfrkfvyBL3cI8y64vEi3fDD046uqYcrWdgoQsffuBbxMAizc6Ez1ia+f0Flue6p15Qaltg==
|
||||
}
|
||||
engines: { node: '>=6' }
|
||||
dependencies:
|
||||
'@sentry/core': 6.19.6
|
||||
'@sentry/hub': 6.19.6
|
||||
'@sentry/types': 6.19.6
|
||||
'@sentry/utils': 6.19.6
|
||||
'@sentry/core': 6.19.7
|
||||
'@sentry/hub': 6.19.7
|
||||
'@sentry/types': 6.19.7
|
||||
'@sentry/utils': 6.19.7
|
||||
cookie: 0.4.2
|
||||
https-proxy-agent: 5.0.0
|
||||
lru_map: 0.3.3
|
||||
@@ -340,22 +344,22 @@ packages:
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
/@sentry/types/6.19.6:
|
||||
/@sentry/types/6.19.7:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-QH34LMJidEUPZK78l+Frt3AaVFJhEmIi05Zf8WHd9/iTt+OqvCHBgq49DDr1FWFqyYWm/QgW/3bIoikFpfsXyQ==
|
||||
integrity: sha512-jH84pDYE+hHIbVnab3Hr+ZXr1v8QABfhx39KknxqKWr2l0oEItzepV0URvbEhB446lk/S/59230dlUUIBGsXbg==
|
||||
}
|
||||
engines: { node: '>=6' }
|
||||
dev: false
|
||||
|
||||
/@sentry/utils/6.19.6:
|
||||
/@sentry/utils/6.19.7:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-fAMWcsguL0632eWrROp/vhPgI7sBj/JROWVPzpabwVkm9z3m1rQm6iLFn4qfkZL8Ozy6NVZPXOQ7EXmeU24byg==
|
||||
integrity: sha512-z95ECmE3i9pbWoXQrD/7PgkBAzJYR+iXtPuTkpBjDKs86O3mT+PXOT3BAn79w2wkn7/i3vOGD2xVr1uiMl26dA==
|
||||
}
|
||||
engines: { node: '>=6' }
|
||||
dependencies:
|
||||
'@sentry/types': 6.19.6
|
||||
'@sentry/types': 6.19.7
|
||||
tslib: 1.14.1
|
||||
dev: false
|
||||
|
||||
@@ -376,19 +380,20 @@ packages:
|
||||
tiny-glob: 0.2.9
|
||||
dev: true
|
||||
|
||||
/@sveltejs/kit/1.0.0-next.316_svelte@3.47.0:
|
||||
/@sveltejs/kit/1.0.0-next.326_svelte@3.48.0:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-oLjWOWzjriJD2t210r7ALuH/8ZADrJGsOODzRCRSJvRBCt0Q7VKVLqwKbM/RlZzD1k8Af2uRodQT11kP98hAIA==
|
||||
integrity: sha512-prJqmXZ2H1wmFfnMw7wDujfbkcA8vuubuqUkpVVmXhfh2+SEzQscPTNwxoE5EJxb5sywtLWEvYx3hv1gPS4Lvg==
|
||||
}
|
||||
engines: { node: '>=14.13' }
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
svelte: ^3.44.0
|
||||
dependencies:
|
||||
'@sveltejs/vite-plugin-svelte': 1.0.0-next.33_svelte@3.47.0+vite@2.9.1
|
||||
'@sveltejs/vite-plugin-svelte': 1.0.0-next.33_svelte@3.48.0+vite@2.9.1
|
||||
chokidar: 3.5.3
|
||||
sade: 1.7.4
|
||||
svelte: 3.47.0
|
||||
svelte: 3.48.0
|
||||
vite: 2.9.1
|
||||
transitivePeerDependencies:
|
||||
- diff-match-patch
|
||||
@@ -398,7 +403,7 @@ packages:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/@sveltejs/vite-plugin-svelte/1.0.0-next.33_svelte@3.47.0+vite@2.9.1:
|
||||
/@sveltejs/vite-plugin-svelte/1.0.0-next.33_svelte@3.48.0+vite@2.9.1:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-aj0h2+ZixgT+yoJFIs8dRRw/Cj9tgNu3+hY4CJikpa04mfhR61wXqJFfi2ZEFMUvFda5nCxKYIChFkc6wq5fJA==
|
||||
@@ -417,22 +422,22 @@ packages:
|
||||
kleur: 4.1.4
|
||||
magic-string: 0.25.7
|
||||
require-relative: 0.8.7
|
||||
svelte: 3.47.0
|
||||
svelte-hmr: 0.14.9_svelte@3.47.0
|
||||
svelte: 3.48.0
|
||||
svelte-hmr: 0.14.9_svelte@3.48.0
|
||||
vite: 2.9.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/@sveltekit-i18n/base/1.1.1_svelte@3.47.0:
|
||||
/@sveltekit-i18n/base/1.2.1_svelte@3.48.0:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-J/sMU0OwS3dCLOuilHMBqu8vZHuuXiNV9vFJx8Nb4/b5BlR/KCZ4bCXI8wZR02GHeCOYKZxWus07CM1scxa/jw==
|
||||
integrity: sha512-F8gqG2+KAOeT0o2wYlUrW3TRCX7zaD7rBy/1CEVNw0irfw9TgFf/ODmhubkHHT3+6Zk+SMz8RNgeuffBfAMbJw==
|
||||
}
|
||||
peerDependencies:
|
||||
svelte: ^3.x
|
||||
dependencies:
|
||||
svelte: 3.47.0
|
||||
svelte: 3.48.0
|
||||
optionalDependencies:
|
||||
'@sveltekit-i18n/parser-default': 1.0.3
|
||||
dev: true
|
||||
@@ -490,7 +495,7 @@ packages:
|
||||
dependencies:
|
||||
'@types/http-cache-semantics': 4.0.1
|
||||
'@types/keyv': 3.1.3
|
||||
'@types/node': 17.0.25
|
||||
'@types/node': 17.0.31
|
||||
'@types/responselike': 1.0.0
|
||||
dev: false
|
||||
|
||||
@@ -501,10 +506,10 @@ packages:
|
||||
}
|
||||
dev: false
|
||||
|
||||
/@types/js-cookie/3.0.1:
|
||||
/@types/js-cookie/3.0.2:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-7wg/8gfHltklehP+oyJnZrz9XBuX5ZPP4zB6UsI84utdlkRYLnOm2HfpLXazTwZA+fpGn0ir8tGNgVnMEleBGQ==
|
||||
integrity: sha512-6+0ekgfusHftJNYpihfkMu8BWdeHs9EOJuGcSofErjstGPfPGEu9yTu4t460lTzzAMl2cM5zngQJqPMHbbnvYA==
|
||||
}
|
||||
dev: true
|
||||
|
||||
@@ -528,22 +533,22 @@ packages:
|
||||
integrity: sha512-FXCJgyyN3ivVgRoml4h94G/p3kY+u/B86La+QptcqJaWtBWtmc6TtkNfS40n9bIvyLteHh7zXOtgbobORKPbDg==
|
||||
}
|
||||
dependencies:
|
||||
'@types/node': 17.0.25
|
||||
'@types/node': 17.0.31
|
||||
dev: false
|
||||
|
||||
/@types/node-forge/1.0.1:
|
||||
/@types/node-forge/1.0.2:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-96ELNKv9tQJ19afdBUiM5iDw7OYEc53iUc51gAPR2aGaqRsO1DBROjqgZRjZa1tkPj7TnEOR0EnyAX6iryGkzA==
|
||||
integrity: sha512-J1OkeZGaW0y9Y7xD49Ja8O82B9l5nZDeoYuGWqIOYPAf9LR+xF23k9ILdzv8dH+2H033fx3D5oiA0GlmicI+sg==
|
||||
}
|
||||
dependencies:
|
||||
'@types/node': 17.0.25
|
||||
'@types/node': 17.0.31
|
||||
dev: true
|
||||
|
||||
/@types/node/17.0.25:
|
||||
/@types/node/17.0.31:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-wANk6fBrUwdpY4isjWrKTufkrXdu1D2YHCot2fD/DfWxF5sMrVSA+KN7ydckvaTCh0HiqX9IVl0L5/ZoXg5M7w==
|
||||
integrity: sha512-AR0x5HbXGqkEx9CadRH3EBYx/VkiUgZIhP4wvPn/+5KIsgpNoyFaRlVe0Zlx9gRtg8fA06a9tskE2MSN7TcG4Q==
|
||||
}
|
||||
|
||||
/@types/pug/2.0.5:
|
||||
@@ -559,7 +564,7 @@ packages:
|
||||
integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==
|
||||
}
|
||||
dependencies:
|
||||
'@types/node': 17.0.25
|
||||
'@types/node': 17.0.31
|
||||
dev: false
|
||||
|
||||
/@types/sass/1.16.1:
|
||||
@@ -568,10 +573,10 @@ packages:
|
||||
integrity: sha512-iZUcRrGuz/Tbg3loODpW7vrQJkUtpY2fFSf4ELqqkApcS2TkZ1msk7ie8iZPB86lDOP8QOTTmuvWjc5S0R9OjQ==
|
||||
}
|
||||
dependencies:
|
||||
'@types/node': 17.0.25
|
||||
'@types/node': 17.0.31
|
||||
dev: true
|
||||
|
||||
/@typescript-eslint/eslint-plugin/4.31.1_8ede7edd7694646e12d33c52460f622c:
|
||||
/@typescript-eslint/eslint-plugin/4.31.1_lii63oz3usekbu5ehvrcuwn5jy:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-UDqhWmd5i0TvPLmbK5xY3UZB0zEGseF+DHPghZ37Sb83Qd3p8ujhvAtkU4OF46Ka5Pm5kWvFIx0cCTBFKo0alA==
|
||||
@@ -585,21 +590,21 @@ packages:
|
||||
typescript:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@typescript-eslint/experimental-utils': 4.31.1_eslint@7.32.0+typescript@4.6.3
|
||||
'@typescript-eslint/parser': 4.31.1_eslint@7.32.0+typescript@4.6.3
|
||||
'@typescript-eslint/experimental-utils': 4.31.1_e4zyhrvfnqudwdx5bevnvkluy4
|
||||
'@typescript-eslint/parser': 4.31.1_e4zyhrvfnqudwdx5bevnvkluy4
|
||||
'@typescript-eslint/scope-manager': 4.31.1
|
||||
debug: 4.3.3
|
||||
eslint: 7.32.0
|
||||
functional-red-black-tree: 1.0.1
|
||||
regexpp: 3.2.0
|
||||
semver: 7.3.5
|
||||
tsutils: 3.21.0_typescript@4.6.3
|
||||
typescript: 4.6.3
|
||||
tsutils: 3.21.0_typescript@4.6.4
|
||||
typescript: 4.6.4
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/@typescript-eslint/experimental-utils/4.31.1_eslint@7.32.0+typescript@4.6.3:
|
||||
/@typescript-eslint/experimental-utils/4.31.1_e4zyhrvfnqudwdx5bevnvkluy4:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-NtoPsqmcSsWty0mcL5nTZXMf7Ei0Xr2MT8jWjXMVgRK0/1qeQ2jZzLFUh4QtyJ4+/lPUyMw5cSfeeME+Zrtp9Q==
|
||||
@@ -611,7 +616,7 @@ packages:
|
||||
'@types/json-schema': 7.0.9
|
||||
'@typescript-eslint/scope-manager': 4.31.1
|
||||
'@typescript-eslint/types': 4.31.1
|
||||
'@typescript-eslint/typescript-estree': 4.31.1_typescript@4.6.3
|
||||
'@typescript-eslint/typescript-estree': 4.31.1_typescript@4.6.4
|
||||
eslint: 7.32.0
|
||||
eslint-scope: 5.1.1
|
||||
eslint-utils: 3.0.0_eslint@7.32.0
|
||||
@@ -620,7 +625,7 @@ packages:
|
||||
- typescript
|
||||
dev: true
|
||||
|
||||
/@typescript-eslint/parser/4.31.1_eslint@7.32.0+typescript@4.6.3:
|
||||
/@typescript-eslint/parser/4.31.1_e4zyhrvfnqudwdx5bevnvkluy4:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-dnVZDB6FhpIby6yVbHkwTKkn2ypjVIfAR9nh+kYsA/ZL0JlTsd22BiDjouotisY3Irmd3OW1qlk9EI5R8GrvRQ==
|
||||
@@ -635,10 +640,10 @@ packages:
|
||||
dependencies:
|
||||
'@typescript-eslint/scope-manager': 4.31.1
|
||||
'@typescript-eslint/types': 4.31.1
|
||||
'@typescript-eslint/typescript-estree': 4.31.1_typescript@4.6.3
|
||||
'@typescript-eslint/typescript-estree': 4.31.1_typescript@4.6.4
|
||||
debug: 4.3.3
|
||||
eslint: 7.32.0
|
||||
typescript: 4.6.3
|
||||
typescript: 4.6.4
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
@@ -662,7 +667,7 @@ packages:
|
||||
engines: { node: ^8.10.0 || ^10.13.0 || >=11.10.1 }
|
||||
dev: true
|
||||
|
||||
/@typescript-eslint/typescript-estree/4.31.1_typescript@4.6.3:
|
||||
/@typescript-eslint/typescript-estree/4.31.1_typescript@4.6.4:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-EGHkbsUvjFrvRnusk6yFGqrqMBTue5E5ROnS5puj3laGQPasVUgwhrxfcgkdHNFECHAewpvELE1Gjv0XO3mdWg==
|
||||
@@ -680,8 +685,8 @@ packages:
|
||||
globby: 11.0.4
|
||||
is-glob: 4.0.3
|
||||
semver: 7.3.5
|
||||
tsutils: 3.21.0_typescript@4.6.3
|
||||
typescript: 4.6.3
|
||||
tsutils: 3.21.0_typescript@4.6.4
|
||||
typescript: 4.6.4
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
@@ -954,22 +959,22 @@ packages:
|
||||
typpy: 2.3.11
|
||||
dev: false
|
||||
|
||||
/autoprefixer/10.4.4_postcss@8.4.12:
|
||||
/autoprefixer/10.4.7_postcss@8.4.13:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-Tm8JxsB286VweiZ5F0anmbyGiNI3v3wGv3mz9W+cxEDYB/6jbnj6GM9H9mK3wIL8ftgl+C07Lcwb8PG5PCCPzA==
|
||||
integrity: sha512-ypHju4Y2Oav95SipEcCcI5J7CGPuvz8oat7sUtYj3ClK44bldfvtvcxK6IEK++7rqB7YchDGzweZIBG+SD0ZAA==
|
||||
}
|
||||
engines: { node: ^10 || ^12 || >=14 }
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
postcss: ^8.1.0
|
||||
dependencies:
|
||||
browserslist: 4.20.2
|
||||
caniuse-lite: 1.0.30001320
|
||||
browserslist: 4.20.3
|
||||
caniuse-lite: 1.0.30001338
|
||||
fraction.js: 4.2.0
|
||||
normalize-range: 0.1.2
|
||||
picocolors: 1.0.0
|
||||
postcss: 8.4.12
|
||||
postcss: 8.4.13
|
||||
postcss-value-parser: 4.2.0
|
||||
dev: true
|
||||
|
||||
@@ -1651,18 +1656,18 @@ packages:
|
||||
fill-range: 7.0.1
|
||||
dev: true
|
||||
|
||||
/browserslist/4.20.2:
|
||||
/browserslist/4.20.3:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-CQOBCqp/9pDvDbx3xfMi+86pr4KXIf2FDkTTdeuYw8OxS9t898LA1Khq57gtufFILXpfgsSx5woNgsBgvGjpsA==
|
||||
integrity: sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg==
|
||||
}
|
||||
engines: { node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7 }
|
||||
hasBin: true
|
||||
dependencies:
|
||||
caniuse-lite: 1.0.30001320
|
||||
electron-to-chromium: 1.4.93
|
||||
caniuse-lite: 1.0.30001338
|
||||
electron-to-chromium: 1.4.137
|
||||
escalade: 3.1.1
|
||||
node-releases: 2.0.2
|
||||
node-releases: 2.0.4
|
||||
picocolors: 1.0.0
|
||||
dev: true
|
||||
|
||||
@@ -1684,10 +1689,10 @@ packages:
|
||||
ieee754: 1.2.1
|
||||
dev: false
|
||||
|
||||
/bullmq/1.80.4:
|
||||
/bullmq/1.81.4:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-j3PyjU16gqmb3Md9QjMInJdbMvxIlSJx7mojtoP06LV9MfhzW75DkDrpSuJlF0H+0+u6MViV4hhaGTxky5OJWw==
|
||||
integrity: sha512-sUEWOMKZnWlh1/XNqYAoSwXW6P8nZN7uJiHKZ8XlZCiIxWlEGjFtlugkkiCZ0lsTI2nNRHdxfpn78x9K3L1utQ==
|
||||
}
|
||||
dependencies:
|
||||
cron-parser: 4.2.1
|
||||
@@ -1751,10 +1756,10 @@ packages:
|
||||
engines: { node: '>=6' }
|
||||
dev: false
|
||||
|
||||
/caniuse-lite/1.0.30001320:
|
||||
/caniuse-lite/1.0.30001338:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-MWPzG54AGdo3nWx7zHZTefseM5Y1ccM7hlQKHRqJkPozUaw3hNbBTMmLn16GG2FUzjR13Cr3NPfhIieX5PzXDA==
|
||||
integrity: sha512-1gLHWyfVoRDsHieO+CaeYe7jSo/MT7D7lhaXUiwwbuR5BwQxORs0f1tAwUSQr3YbxRXJvxHM/PA5FfPQRnsPeQ==
|
||||
}
|
||||
dev: true
|
||||
|
||||
@@ -2046,10 +2051,10 @@ packages:
|
||||
}
|
||||
dev: false
|
||||
|
||||
/dayjs/1.11.1:
|
||||
/dayjs/1.11.2:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-ER7EjqVAMkRRsxNCC5YqJ9d9VQYuWdGt7aiH2qA5R5wt8ZmWaP2dLUSIK6y/kVzLMlmh1Tvu5xUf4M/wdGJ5KA==
|
||||
integrity: sha512-F4LXf1OeU9hrSYRPTTj/6FbO4HTjPKXvEIC1P2kcnFurViINCVk3ZV0xAS3XVx9MkMsXbbqlK6hjseaYbgKEHw==
|
||||
}
|
||||
dev: false
|
||||
|
||||
@@ -2265,10 +2270,10 @@ packages:
|
||||
safe-buffer: 5.2.1
|
||||
dev: false
|
||||
|
||||
/electron-to-chromium/1.4.93:
|
||||
/electron-to-chromium/1.4.137:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-ywq9Pc5Gwwpv7NG767CtoU8xF3aAUQJjH9//Wy3MBCg4w5JSLbJUq2L8IsCdzPMjvSgxuue9WcVaTOyyxCL0aQ==
|
||||
integrity: sha512-0Rcpald12O11BUogJagX3HsCN3FE83DSqWjgXoHo5a72KUKMSfI39XBgJpgNNxS9fuGzytaFjE06kZkiVFy2qA==
|
||||
}
|
||||
dev: true
|
||||
|
||||
@@ -2613,7 +2618,7 @@ packages:
|
||||
eslint: 7.32.0
|
||||
dev: true
|
||||
|
||||
/eslint-plugin-svelte3/3.4.1_eslint@7.32.0+svelte@3.47.0:
|
||||
/eslint-plugin-svelte3/3.4.1_6wevxxng4y4ff26nzlndg2wnpa:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-7p59WG8qV8L6wLdl4d/c3mdjkgVglQCdv5XOTk/iNPBKXuuV+Q0eFP5Wa6iJd/G2M1qR3BkLPEzaANOqKAZczw==
|
||||
@@ -2624,7 +2629,7 @@ packages:
|
||||
svelte: ^3.2.0
|
||||
dependencies:
|
||||
eslint: 7.32.0
|
||||
svelte: 3.47.0
|
||||
svelte: 3.48.0
|
||||
dev: true
|
||||
|
||||
/eslint-scope/5.1.1:
|
||||
@@ -3078,10 +3083,10 @@ packages:
|
||||
}
|
||||
dev: true
|
||||
|
||||
/got/12.0.3:
|
||||
/got/12.0.4:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-hmdcXi/S0gcAtDg4P8j/rM7+j3o1Aq6bXhjxkDhRY2ipe7PHpvx/14DgTY2czHOLaGeU8VRvRecidwfu9qdFug==
|
||||
integrity: sha512-2Eyz4iU/ktq7wtMFXxzK7g5p35uNYLLdiZarZ5/Yn3IJlNEpBd5+dCgcAyxN8/8guZLszffwe3wVyw+DEVrpBg==
|
||||
}
|
||||
engines: { node: '>=14.16' }
|
||||
dependencies:
|
||||
@@ -3283,6 +3288,14 @@ packages:
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
/ip-regex/5.0.0:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-fOCG6lhoKKakwv+C6KdsOnGvgXnmgfmp0myi3bcNwj3qfwPAxRKWEuFhvEFF7ceYIz6+1jRZ+yguLFAmUNPEfw==
|
||||
}
|
||||
engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 }
|
||||
dev: false
|
||||
|
||||
/is-binary-path/2.1.0:
|
||||
resolution:
|
||||
{
|
||||
@@ -3341,6 +3354,16 @@ packages:
|
||||
is-extglob: 2.1.1
|
||||
dev: true
|
||||
|
||||
/is-ip/4.0.0:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-4B4XA2HEIm/PY+OSpeMBXr8pGWBYbXuHgjMAqrwbLO3CPTCAd9ArEJzBUKGZtk9viY6+aSfadGnWyjY3ydYZkw==
|
||||
}
|
||||
engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 }
|
||||
dependencies:
|
||||
ip-regex: 5.0.0
|
||||
dev: false
|
||||
|
||||
/is-number/7.0.0:
|
||||
resolution:
|
||||
{
|
||||
@@ -3524,10 +3547,10 @@ packages:
|
||||
engines: { node: '>=10' }
|
||||
dev: true
|
||||
|
||||
/lint-staged/12.4.0:
|
||||
/lint-staged/12.4.1:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-3X7MR0h9b7qf4iXf/1n7RlVAx+EzpAZXoCEMhVSpaBlgKDfH2ewf+QUm7BddFyq29v4dgPP+8+uYpWuSWx035A==
|
||||
integrity: sha512-PTXgzpflrQ+pODQTG116QNB+Q6uUTDg5B5HqGvNhoQSGt8Qy+MA/6zSnR8n38+sxP5TapzeQGTvoKni0KRS8Vg==
|
||||
}
|
||||
engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 }
|
||||
hasBin: true
|
||||
@@ -3864,10 +3887,10 @@ packages:
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/nanoid/3.3.1:
|
||||
/nanoid/3.3.4:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==
|
||||
integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==
|
||||
}
|
||||
engines: { node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1 }
|
||||
hasBin: true
|
||||
@@ -3894,10 +3917,17 @@ packages:
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/node-releases/2.0.2:
|
||||
/node-os-utils/1.3.6:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg==
|
||||
integrity: sha512-WympE9ELtdOzNak/rAuuIV5DwvX/PTJtN0LjyWeGyTTR2Kt0sY56ldLoGbVBnfM1dz46VeO3sHcNZI5BZ+EB+w==
|
||||
}
|
||||
dev: false
|
||||
|
||||
/node-releases/2.0.4:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-gbMzqQtTtDz/00jQzZ21PQzdI9PyLYqUSvD0p3naOhX4odFji0ZxYdnVwPTxmSwkmxhcFImpozceidSG+AgoPQ==
|
||||
}
|
||||
dev: true
|
||||
|
||||
@@ -4090,7 +4120,7 @@ packages:
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/postcss-js/4.0.0_postcss@8.4.12:
|
||||
/postcss-js/4.0.0_postcss@8.4.13:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ==
|
||||
@@ -4100,10 +4130,10 @@ packages:
|
||||
postcss: ^8.3.3
|
||||
dependencies:
|
||||
camelcase-css: 2.0.1
|
||||
postcss: 8.4.12
|
||||
postcss: 8.4.13
|
||||
dev: true
|
||||
|
||||
/postcss-load-config/3.1.4_postcss@8.4.12+ts-node@10.7.0:
|
||||
/postcss-load-config/3.1.4_4jqnslpwnj4ifyjfqbkuebd4fy:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==
|
||||
@@ -4119,12 +4149,12 @@ packages:
|
||||
optional: true
|
||||
dependencies:
|
||||
lilconfig: 2.0.5
|
||||
postcss: 8.4.12
|
||||
ts-node: 10.7.0_de7c86b0cde507c63a0402da5b982bd3
|
||||
postcss: 8.4.13
|
||||
ts-node: 10.7.0_l47be6km5p57gglrggidw5gsgm
|
||||
yaml: 1.10.2
|
||||
dev: true
|
||||
|
||||
/postcss-nested/5.0.6_postcss@8.4.12:
|
||||
/postcss-nested/5.0.6_postcss@8.4.13:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==
|
||||
@@ -4133,7 +4163,7 @@ packages:
|
||||
peerDependencies:
|
||||
postcss: ^8.2.14
|
||||
dependencies:
|
||||
postcss: 8.4.12
|
||||
postcss: 8.4.13
|
||||
postcss-selector-parser: 6.0.10
|
||||
dev: true
|
||||
|
||||
@@ -4155,14 +4185,14 @@ packages:
|
||||
}
|
||||
dev: true
|
||||
|
||||
/postcss/8.4.12:
|
||||
/postcss/8.4.13:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-lg6eITwYe9v6Hr5CncVbK70SoioNQIq81nsaG86ev5hAidQvmOeETBqs7jm43K2F5/Ley3ytDtriImV6TpNiSg==
|
||||
integrity: sha512-jtL6eTBrza5MPzy8oJLFuUscHDXTV5KcLlqAWHl5q5WYRfnNRGSmOZmOZ1T6Gy7A99mOZfqungmZMpMmCVJ8ZA==
|
||||
}
|
||||
engines: { node: ^10 || ^12 || >=14 }
|
||||
dependencies:
|
||||
nanoid: 3.3.1
|
||||
nanoid: 3.3.4
|
||||
picocolors: 1.0.0
|
||||
source-map-js: 1.0.2
|
||||
dev: true
|
||||
@@ -4175,7 +4205,7 @@ packages:
|
||||
engines: { node: '>= 0.8.0' }
|
||||
dev: true
|
||||
|
||||
/prettier-plugin-svelte/2.7.0_prettier@2.6.2+svelte@3.47.0:
|
||||
/prettier-plugin-svelte/2.7.0_kkjbqzpydplecjtkxrgomroeru:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-fQhhZICprZot2IqEyoiUYLTRdumULGRvw0o4dzl5jt0jfzVWdGqeYW27QTWAeXhoupEZJULmNoH3ueJwUWFLIA==
|
||||
@@ -4185,7 +4215,7 @@ packages:
|
||||
svelte: ^3.2.0
|
||||
dependencies:
|
||||
prettier: 2.6.2
|
||||
svelte: 3.47.0
|
||||
svelte: 3.48.0
|
||||
dev: true
|
||||
|
||||
/prettier-plugin-tailwindcss/0.1.10_prettier@2.6.2:
|
||||
@@ -4493,7 +4523,7 @@ packages:
|
||||
integrity: sha512-PwDt186XaL3QN5qXj/H9DGyHhP3/RYYgZZwqBv9Tv8rsAaiwFH1IsJJlcgD37J7UW5a6O67qX0KWKS3/pu0m4w==
|
||||
}
|
||||
dependencies:
|
||||
tslib: 2.3.1
|
||||
tslib: 2.4.0
|
||||
dev: true
|
||||
|
||||
/sade/1.7.4:
|
||||
@@ -4858,7 +4888,7 @@ packages:
|
||||
engines: { node: '>= 0.4' }
|
||||
dev: true
|
||||
|
||||
/svelte-check/2.7.0_postcss@8.4.12+svelte@3.47.0:
|
||||
/svelte-check/2.7.0_f2ke6qjyzu5axsjd6yk3u4tn7a:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-GrvG24j0+i8AOm0k0KyJ6Dqc+TAR2yzB7rtS4nljHStunVxCTr/1KYlv4EsOeoqtHLzeWMOd5D2O6nDdP/yw4A==
|
||||
@@ -4873,9 +4903,9 @@ packages:
|
||||
picocolors: 1.0.0
|
||||
sade: 1.7.4
|
||||
source-map: 0.7.3
|
||||
svelte: 3.47.0
|
||||
svelte-preprocess: 4.10.6_41810887ae6c6d59323116f47e33fa38
|
||||
typescript: 4.6.3
|
||||
svelte: 3.48.0
|
||||
svelte-preprocess: 4.10.6_nq4dx2skq5drra53vttuo4lltu
|
||||
typescript: 4.6.4
|
||||
transitivePeerDependencies:
|
||||
- '@babel/core'
|
||||
- coffeescript
|
||||
@@ -4889,7 +4919,7 @@ packages:
|
||||
- sugarss
|
||||
dev: true
|
||||
|
||||
/svelte-hmr/0.14.9_svelte@3.47.0:
|
||||
/svelte-hmr/0.14.9_svelte@3.48.0:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-bKE9+4qb4sAnA+TKHiYurUl970rjA0XmlP9TEP7K/ncyWz3m81kA4HOgmlZK/7irGK7gzZlaPDI3cmf8fp/+tg==
|
||||
@@ -4897,17 +4927,17 @@ packages:
|
||||
peerDependencies:
|
||||
svelte: '>=3.19.0'
|
||||
dependencies:
|
||||
svelte: 3.47.0
|
||||
svelte: 3.48.0
|
||||
dev: true
|
||||
|
||||
/svelte-kit-cookie-session/2.1.3:
|
||||
/svelte-kit-cookie-session/2.1.4:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-7Xk3CNbpLAi1KodlsV5W5jULQ2NxQunaXtAYqAuzIEXIq2EwC4oDa25kdmHjNe33epV0t4r0WwxZOuSdJPsapg==
|
||||
integrity: sha512-z/ckxHWguYyy66UqfId4Lu+A77ft/3mV5oozbRTI9bnQY0tyJfns/SM0ikdkj7OV5GiI8kq7GSOGvajWwyGeZw==
|
||||
}
|
||||
dev: false
|
||||
|
||||
/svelte-preprocess/4.10.6_41810887ae6c6d59323116f47e33fa38:
|
||||
/svelte-preprocess/4.10.6_nq4dx2skq5drra53vttuo4lltu:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-I2SV1w/AveMvgIQlUF/ZOO3PYVnhxfcpNyGt8pxpUVhPfyfL/CZBkkw/KPfuFix5FJ9TnnNYMhACK3DtSaYVVQ==
|
||||
@@ -4955,11 +4985,11 @@ packages:
|
||||
'@types/sass': 1.16.1
|
||||
detect-indent: 6.1.0
|
||||
magic-string: 0.25.7
|
||||
postcss: 8.4.12
|
||||
postcss: 8.4.13
|
||||
sorcery: 0.10.0
|
||||
strip-indent: 3.0.0
|
||||
svelte: 3.47.0
|
||||
typescript: 4.6.3
|
||||
svelte: 3.48.0
|
||||
typescript: 4.6.4
|
||||
dev: true
|
||||
|
||||
/svelte-select/4.4.7:
|
||||
@@ -4969,25 +4999,25 @@ packages:
|
||||
}
|
||||
dev: true
|
||||
|
||||
/svelte/3.47.0:
|
||||
/svelte/3.48.0:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-4JaJp3HEoTCGARRWZQIZDUanhYv0iyoHikklVHVLH9xFE9db22g4TDv7CPeNA8HD1JgjXI1vlhR1JZvvhaTu2Q==
|
||||
integrity: sha512-fN2YRm/bGumvjUpu6yI3BpvZnpIm9I6A7HR4oUNYd7ggYyIwSA/BX7DJ+UXXffLp6XNcUijyLvttbPVCYa/3xQ==
|
||||
}
|
||||
engines: { node: '>= 8' }
|
||||
dev: true
|
||||
|
||||
/sveltekit-i18n/2.1.2_svelte@3.47.0:
|
||||
/sveltekit-i18n/2.2.1_svelte@3.48.0:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-s5YxcbNd2EWNZaZR1A4Drt8s53E4fpUkN4XIWd3VRpw1pihZVWssqmBW1qkjQ6AB0kiu1Qwule+vt1HkbQOjrg==
|
||||
integrity: sha512-1CyaRN6dBvp467JjBdji+nJf+7pZ3myFu+2YaCuGSAt09Cvt5ndfRbzy+aAd5WJdk6Lu/hnPEE7ZZFauTbDRNw==
|
||||
}
|
||||
peerDependencies:
|
||||
svelte: ^3.x
|
||||
dependencies:
|
||||
'@sveltekit-i18n/base': 1.1.1_svelte@3.47.0
|
||||
'@sveltekit-i18n/base': 1.2.1_svelte@3.48.0
|
||||
'@sveltekit-i18n/parser-default': 1.0.3
|
||||
svelte: 3.47.0
|
||||
svelte: 3.48.0
|
||||
dev: true
|
||||
|
||||
/table/6.7.2:
|
||||
@@ -5037,10 +5067,10 @@ packages:
|
||||
normalize-path: 3.0.0
|
||||
object-hash: 3.0.0
|
||||
picocolors: 1.0.0
|
||||
postcss: 8.4.12
|
||||
postcss-js: 4.0.0_postcss@8.4.12
|
||||
postcss-load-config: 3.1.4_postcss@8.4.12+ts-node@10.7.0
|
||||
postcss-nested: 5.0.6_postcss@8.4.12
|
||||
postcss: 8.4.13
|
||||
postcss-js: 4.0.0_postcss@8.4.13
|
||||
postcss-load-config: 3.1.4_4jqnslpwnj4ifyjfqbkuebd4fy
|
||||
postcss-nested: 5.0.6_postcss@8.4.13
|
||||
postcss-selector-parser: 6.0.10
|
||||
postcss-value-parser: 4.2.0
|
||||
quick-lru: 5.1.1
|
||||
@@ -5113,7 +5143,7 @@ packages:
|
||||
engines: { node: '>=0.10.0' }
|
||||
dev: true
|
||||
|
||||
/ts-node/10.7.0_de7c86b0cde507c63a0402da5b982bd3:
|
||||
/ts-node/10.7.0_l47be6km5p57gglrggidw5gsgm:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-TbIGS4xgJoX2i3do417KSaep1uRAW/Lu+WAL2doDHC0D6ummjirVOXU5/7aiZotbQ5p1Zp9tP7U6cYhA0O7M8A==
|
||||
@@ -5135,14 +5165,14 @@ packages:
|
||||
'@tsconfig/node12': 1.0.9
|
||||
'@tsconfig/node14': 1.0.1
|
||||
'@tsconfig/node16': 1.0.2
|
||||
'@types/node': 17.0.25
|
||||
'@types/node': 17.0.31
|
||||
acorn: 8.5.0
|
||||
acorn-walk: 8.2.0
|
||||
arg: 4.1.3
|
||||
create-require: 1.1.1
|
||||
diff: 4.0.2
|
||||
make-error: 1.3.6
|
||||
typescript: 4.6.3
|
||||
typescript: 4.6.4
|
||||
v8-compile-cache-lib: 3.0.0
|
||||
yn: 3.1.1
|
||||
dev: true
|
||||
@@ -5153,14 +5183,14 @@ packages:
|
||||
integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
|
||||
}
|
||||
|
||||
/tslib/2.3.1:
|
||||
/tslib/2.4.0:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==
|
||||
integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==
|
||||
}
|
||||
dev: true
|
||||
|
||||
/tsutils/3.21.0_typescript@4.6.3:
|
||||
/tsutils/3.21.0_typescript@4.6.4:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==
|
||||
@@ -5170,7 +5200,7 @@ packages:
|
||||
typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta'
|
||||
dependencies:
|
||||
tslib: 1.14.1
|
||||
typescript: 4.6.3
|
||||
typescript: 4.6.4
|
||||
dev: true
|
||||
|
||||
/tweetnacl/0.14.5:
|
||||
@@ -5203,10 +5233,10 @@ packages:
|
||||
engines: { node: '>=10' }
|
||||
dev: true
|
||||
|
||||
/typescript/4.6.3:
|
||||
/typescript/4.6.4:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==
|
||||
integrity: sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==
|
||||
}
|
||||
engines: { node: '>=4.2.0' }
|
||||
hasBin: true
|
||||
@@ -5283,7 +5313,7 @@ packages:
|
||||
optional: true
|
||||
dependencies:
|
||||
esbuild: 0.14.34
|
||||
postcss: 8.4.12
|
||||
postcss: 8.4.13
|
||||
resolve: 1.22.0
|
||||
rollup: 2.61.1
|
||||
optionalDependencies:
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "Application" ADD COLUMN "exposePort" INTEGER;
|
||||
@@ -0,0 +1,2 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "Service" ADD COLUMN "exposePort" INTEGER;
|
||||
@@ -0,0 +1,24 @@
|
||||
-- RedefineTables
|
||||
PRAGMA foreign_keys=OFF;
|
||||
CREATE TABLE "new_PlausibleAnalytics" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"email" TEXT,
|
||||
"username" TEXT,
|
||||
"password" TEXT NOT NULL,
|
||||
"postgresqlUser" TEXT NOT NULL,
|
||||
"postgresqlPassword" TEXT NOT NULL,
|
||||
"postgresqlDatabase" TEXT NOT NULL,
|
||||
"postgresqlPublicPort" INTEGER,
|
||||
"secretKeyBase" TEXT,
|
||||
"scriptName" TEXT NOT NULL DEFAULT 'plausible.js',
|
||||
"serviceId" TEXT NOT NULL,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" DATETIME NOT NULL,
|
||||
CONSTRAINT "PlausibleAnalytics_serviceId_fkey" FOREIGN KEY ("serviceId") REFERENCES "Service" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
);
|
||||
INSERT INTO "new_PlausibleAnalytics" ("createdAt", "email", "id", "password", "postgresqlDatabase", "postgresqlPassword", "postgresqlPublicPort", "postgresqlUser", "secretKeyBase", "serviceId", "updatedAt", "username") SELECT "createdAt", "email", "id", "password", "postgresqlDatabase", "postgresqlPassword", "postgresqlPublicPort", "postgresqlUser", "secretKeyBase", "serviceId", "updatedAt", "username" FROM "PlausibleAnalytics";
|
||||
DROP TABLE "PlausibleAnalytics";
|
||||
ALTER TABLE "new_PlausibleAnalytics" RENAME TO "PlausibleAnalytics";
|
||||
CREATE UNIQUE INDEX "PlausibleAnalytics_serviceId_key" ON "PlausibleAnalytics"("serviceId");
|
||||
PRAGMA foreign_key_check;
|
||||
PRAGMA foreign_keys=ON;
|
||||
@@ -0,0 +1,32 @@
|
||||
-- RedefineTables
|
||||
PRAGMA foreign_keys=OFF;
|
||||
CREATE TABLE "new_Wordpress" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"extraConfig" TEXT,
|
||||
"tablePrefix" TEXT,
|
||||
"ownMysql" BOOLEAN NOT NULL DEFAULT false,
|
||||
"mysqlHost" TEXT,
|
||||
"mysqlPort" INTEGER,
|
||||
"mysqlUser" TEXT NOT NULL,
|
||||
"mysqlPassword" TEXT NOT NULL,
|
||||
"mysqlRootUser" TEXT NOT NULL,
|
||||
"mysqlRootUserPassword" TEXT NOT NULL,
|
||||
"mysqlDatabase" TEXT,
|
||||
"mysqlPublicPort" INTEGER,
|
||||
"ftpEnabled" BOOLEAN NOT NULL DEFAULT false,
|
||||
"ftpUser" TEXT,
|
||||
"ftpPassword" TEXT,
|
||||
"ftpPublicPort" INTEGER,
|
||||
"ftpHostKey" TEXT,
|
||||
"ftpHostKeyPrivate" TEXT,
|
||||
"serviceId" TEXT NOT NULL,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" DATETIME NOT NULL,
|
||||
CONSTRAINT "Wordpress_serviceId_fkey" FOREIGN KEY ("serviceId") REFERENCES "Service" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
);
|
||||
INSERT INTO "new_Wordpress" ("createdAt", "extraConfig", "ftpEnabled", "ftpHostKey", "ftpHostKeyPrivate", "ftpPassword", "ftpPublicPort", "ftpUser", "id", "mysqlDatabase", "mysqlPassword", "mysqlPublicPort", "mysqlRootUser", "mysqlRootUserPassword", "mysqlUser", "serviceId", "tablePrefix", "updatedAt") SELECT "createdAt", "extraConfig", "ftpEnabled", "ftpHostKey", "ftpHostKeyPrivate", "ftpPassword", "ftpPublicPort", "ftpUser", "id", "mysqlDatabase", "mysqlPassword", "mysqlPublicPort", "mysqlRootUser", "mysqlRootUserPassword", "mysqlUser", "serviceId", "tablePrefix", "updatedAt" FROM "Wordpress";
|
||||
DROP TABLE "Wordpress";
|
||||
ALTER TABLE "new_Wordpress" RENAME TO "Wordpress";
|
||||
CREATE UNIQUE INDEX "Wordpress_serviceId_key" ON "Wordpress"("serviceId");
|
||||
PRAGMA foreign_key_check;
|
||||
PRAGMA foreign_keys=ON;
|
||||
@@ -84,6 +84,7 @@ model Application {
|
||||
buildPack String?
|
||||
projectId Int?
|
||||
port Int?
|
||||
exposePort Int?
|
||||
installCommand String?
|
||||
buildCommand String?
|
||||
startCommand String?
|
||||
@@ -289,6 +290,7 @@ model Service {
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
fqdn String?
|
||||
exposePort Int?
|
||||
dualCerts Boolean @default(false)
|
||||
type String?
|
||||
version String?
|
||||
@@ -320,6 +322,7 @@ model PlausibleAnalytics {
|
||||
postgresqlDatabase String
|
||||
postgresqlPublicPort Int?
|
||||
secretKeyBase String?
|
||||
scriptName String @default("plausible.js")
|
||||
serviceId String @unique
|
||||
service Service @relation(fields: [serviceId], references: [id])
|
||||
createdAt DateTime @default(now())
|
||||
@@ -350,6 +353,9 @@ model Wordpress {
|
||||
id String @id @default(cuid())
|
||||
extraConfig String?
|
||||
tablePrefix String?
|
||||
ownMysql Boolean @default(false)
|
||||
mysqlHost String?
|
||||
mysqlPort Int?
|
||||
mysqlUser String
|
||||
mysqlPassword String
|
||||
mysqlRootUser String
|
||||
|
||||
@@ -114,5 +114,5 @@ export const getSession: GetSession = function ({ locals }) {
|
||||
};
|
||||
|
||||
export async function handleError({ error, event }) {
|
||||
if (!dev) sentry.captureException(error, event);
|
||||
// if (!dev) sentry.captureException(error, event);
|
||||
}
|
||||
|
||||
@@ -8,14 +8,16 @@ import { staticDeployments } from '$lib/components/common';
|
||||
const staticApps = ['static', 'react', 'vuejs', 'svelte', 'gatsby', 'astro', 'eleventy'];
|
||||
const nodeBased = [
|
||||
'react',
|
||||
'preact',
|
||||
'vuejs',
|
||||
'svelte',
|
||||
'gatsby',
|
||||
'php',
|
||||
'astro',
|
||||
'eleventy',
|
||||
'node',
|
||||
'nestjs'
|
||||
'nestjs',
|
||||
'nuxtjs',
|
||||
'nextjs'
|
||||
];
|
||||
|
||||
export function makeLabelForStandaloneApplication({
|
||||
@@ -403,7 +405,68 @@ export function setDefaultBaseImage(buildPack) {
|
||||
label: 'webdevops/php-nginx:7.1-alpine'
|
||||
}
|
||||
];
|
||||
|
||||
const pythonVersions = [
|
||||
{
|
||||
value: 'python:3.10-buster',
|
||||
label: 'python:3.10-buster'
|
||||
},
|
||||
{
|
||||
value: 'python:3.10-bullseye',
|
||||
label: 'python:3.10-bullseye'
|
||||
},
|
||||
{
|
||||
value: 'python:3.10-slim-bullseye',
|
||||
label: 'python:3.10-slim-bullseye'
|
||||
},
|
||||
{
|
||||
value: 'python:3.9-alpine',
|
||||
label: 'python:3.9-alpine'
|
||||
},
|
||||
{
|
||||
value: 'python:3.9-buster',
|
||||
label: 'python:3.9-buster'
|
||||
},
|
||||
{
|
||||
value: 'python:3.9-bullseye',
|
||||
label: 'python:3.9-bullseye'
|
||||
},
|
||||
{
|
||||
value: 'python:3.9-slim-bullseye',
|
||||
label: 'python:3.9-slim-bullseye'
|
||||
},
|
||||
{
|
||||
value: 'python:3.8-alpine',
|
||||
label: 'python:3.8-alpine'
|
||||
},
|
||||
{
|
||||
value: 'python:3.8-buster',
|
||||
label: 'python:3.8-buster'
|
||||
},
|
||||
{
|
||||
value: 'python:3.8-bullseye',
|
||||
label: 'python:3.8-bullseye'
|
||||
},
|
||||
{
|
||||
value: 'python:3.8-slim-bullseye',
|
||||
label: 'python:3.8-slim-bullseye'
|
||||
},
|
||||
{
|
||||
value: 'python:3.7-alpine',
|
||||
label: 'python:3.7-alpine'
|
||||
},
|
||||
{
|
||||
value: 'python:3.7-buster',
|
||||
label: 'python:3.7-buster'
|
||||
},
|
||||
{
|
||||
value: 'python:3.7-bullseye',
|
||||
label: 'python:3.7-bullseye'
|
||||
},
|
||||
{
|
||||
value: 'python:3.7-slim-bullseye',
|
||||
label: 'python:3.7-slim-bullseye'
|
||||
}
|
||||
];
|
||||
let payload = {
|
||||
baseImage: null,
|
||||
baseBuildImage: null,
|
||||
@@ -424,6 +487,7 @@ export function setDefaultBaseImage(buildPack) {
|
||||
}
|
||||
if (buildPack === 'python') {
|
||||
payload.baseImage = 'python:3-alpine';
|
||||
payload.baseImages = pythonVersions;
|
||||
}
|
||||
if (buildPack === 'rust') {
|
||||
payload.baseImage = 'rust:latest';
|
||||
|
||||
@@ -2,7 +2,7 @@ import { buildCacheImageWithNode, buildImage } from '$lib/docker';
|
||||
import { promises as fs } from 'fs';
|
||||
|
||||
const createDockerfile = async (data, imageforBuild): Promise<void> => {
|
||||
const { applicationId, tag, workdir, publishDirectory, baseImage, buildId } = data;
|
||||
const { applicationId, tag, workdir, publishDirectory, baseImage, buildId, port } = data;
|
||||
const Dockerfile: Array<string> = [];
|
||||
|
||||
Dockerfile.push(`FROM ${imageforBuild}`);
|
||||
@@ -12,7 +12,7 @@ const createDockerfile = async (data, imageforBuild): Promise<void> => {
|
||||
if (baseImage.includes('nginx')) {
|
||||
Dockerfile.push(`COPY /nginx.conf /etc/nginx/nginx.conf`);
|
||||
}
|
||||
Dockerfile.push(`EXPOSE 80`);
|
||||
Dockerfile.push(`EXPOSE ${port}`);
|
||||
await fs.writeFile(`${workdir}/Dockerfile`, Dockerfile.join('\n'));
|
||||
};
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { buildCacheImageForLaravel, buildImage } from '$lib/docker';
|
||||
import { promises as fs } from 'fs';
|
||||
|
||||
const createDockerfile = async (data, image): Promise<void> => {
|
||||
const { workdir, applicationId, tag, buildId } = data;
|
||||
const { workdir, applicationId, tag, buildId, port } = data;
|
||||
const Dockerfile: Array<string> = [];
|
||||
|
||||
Dockerfile.push(`FROM ${image}`);
|
||||
@@ -24,7 +24,7 @@ const createDockerfile = async (data, image): Promise<void> => {
|
||||
`COPY --chown=application:application --from=${applicationId}:${tag}-cache /app/mix-manifest.json /app/public/mix-manifest.json`
|
||||
);
|
||||
Dockerfile.push(`COPY --chown=application:application . ./`);
|
||||
Dockerfile.push(`EXPOSE 80`);
|
||||
Dockerfile.push(`EXPOSE ${port}`);
|
||||
await fs.writeFile(`${workdir}/Dockerfile`, Dockerfile.join('\n'));
|
||||
};
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { buildImage } from '$lib/docker';
|
||||
import { promises as fs } from 'fs';
|
||||
|
||||
const createDockerfile = async (data, image, htaccessFound): Promise<void> => {
|
||||
const { workdir, baseDirectory, buildId } = data;
|
||||
const { workdir, baseDirectory, buildId, port } = data;
|
||||
const Dockerfile: Array<string> = [];
|
||||
let composerFound = false;
|
||||
try {
|
||||
@@ -22,7 +22,7 @@ const createDockerfile = async (data, image, htaccessFound): Promise<void> => {
|
||||
}
|
||||
|
||||
Dockerfile.push(`COPY /entrypoint.sh /opt/docker/provision/entrypoint.d/30-entrypoint.sh`);
|
||||
Dockerfile.push(`EXPOSE 80`);
|
||||
Dockerfile.push(`EXPOSE ${port}`);
|
||||
await fs.writeFile(`${workdir}/Dockerfile`, Dockerfile.join('\n'));
|
||||
};
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { buildCacheImageWithNode, buildImage } from '$lib/docker';
|
||||
import { promises as fs } from 'fs';
|
||||
|
||||
const createDockerfile = async (data, image): Promise<void> => {
|
||||
const { applicationId, tag, workdir, publishDirectory, baseImage, buildId } = data;
|
||||
const { applicationId, tag, workdir, publishDirectory, baseImage, buildId, port } = data;
|
||||
const Dockerfile: Array<string> = [];
|
||||
|
||||
Dockerfile.push(`FROM ${image}`);
|
||||
@@ -12,7 +12,7 @@ const createDockerfile = async (data, image): Promise<void> => {
|
||||
if (baseImage.includes('nginx')) {
|
||||
Dockerfile.push(`COPY /nginx.conf /etc/nginx/nginx.conf`);
|
||||
}
|
||||
Dockerfile.push(`EXPOSE 80`);
|
||||
Dockerfile.push(`EXPOSE ${port}`);
|
||||
await fs.writeFile(`${workdir}/Dockerfile`, Dockerfile.join('\n'));
|
||||
};
|
||||
|
||||
|
||||
@@ -12,7 +12,8 @@ const createDockerfile = async (data, image): Promise<void> => {
|
||||
secrets,
|
||||
pullmergeRequestId,
|
||||
baseImage,
|
||||
buildId
|
||||
buildId,
|
||||
port
|
||||
} = data;
|
||||
const Dockerfile: Array<string> = [];
|
||||
|
||||
@@ -42,7 +43,7 @@ const createDockerfile = async (data, image): Promise<void> => {
|
||||
if (baseImage.includes('nginx')) {
|
||||
Dockerfile.push(`COPY /nginx.conf /etc/nginx/nginx.conf`);
|
||||
}
|
||||
Dockerfile.push(`EXPOSE 80`);
|
||||
Dockerfile.push(`EXPOSE ${port}`);
|
||||
await fs.writeFile(`${workdir}/Dockerfile`, Dockerfile.join('\n'));
|
||||
};
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { buildCacheImageWithNode, buildImage } from '$lib/docker';
|
||||
import { promises as fs } from 'fs';
|
||||
|
||||
const createDockerfile = async (data, image): Promise<void> => {
|
||||
const { applicationId, tag, workdir, publishDirectory, baseImage, buildId } = data;
|
||||
const { applicationId, tag, workdir, publishDirectory, baseImage, buildId, port } = data;
|
||||
const Dockerfile: Array<string> = [];
|
||||
|
||||
Dockerfile.push(`FROM ${image}`);
|
||||
@@ -12,7 +12,7 @@ const createDockerfile = async (data, image): Promise<void> => {
|
||||
if (baseImage.includes('nginx')) {
|
||||
Dockerfile.push(`COPY /nginx.conf /etc/nginx/nginx.conf`);
|
||||
}
|
||||
Dockerfile.push(`EXPOSE 80`);
|
||||
Dockerfile.push(`EXPOSE ${port}`);
|
||||
await fs.writeFile(`${workdir}/Dockerfile`, Dockerfile.join('\n'));
|
||||
};
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { buildCacheImageWithNode, buildImage } from '$lib/docker';
|
||||
import { promises as fs } from 'fs';
|
||||
|
||||
const createDockerfile = async (data, image): Promise<void> => {
|
||||
const { applicationId, tag, workdir, publishDirectory, baseImage, buildId } = data;
|
||||
const { applicationId, tag, workdir, publishDirectory, baseImage, buildId, port } = data;
|
||||
const Dockerfile: Array<string> = [];
|
||||
|
||||
Dockerfile.push(`FROM ${image}`);
|
||||
@@ -12,7 +12,7 @@ const createDockerfile = async (data, image): Promise<void> => {
|
||||
if (baseImage.includes('nginx')) {
|
||||
Dockerfile.push(`COPY /nginx.conf /etc/nginx/nginx.conf`);
|
||||
}
|
||||
Dockerfile.push(`EXPOSE 80`);
|
||||
Dockerfile.push(`EXPOSE ${port}`);
|
||||
await fs.writeFile(`${workdir}/Dockerfile`, Dockerfile.join('\n'));
|
||||
};
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@ import { dev } from '$app/env';
|
||||
import * as Sentry from '@sentry/node';
|
||||
import { uniqueNamesGenerator, adjectives, colors, animals } from 'unique-names-generator';
|
||||
import type { Config } from 'unique-names-generator';
|
||||
import { promises as dns } from 'dns';
|
||||
import { isIP } from 'is-ip';
|
||||
|
||||
import * as db from '$lib/database';
|
||||
import { buildLogQueue } from './queues';
|
||||
@@ -14,24 +16,25 @@ import Cookie from 'cookie';
|
||||
import os from 'os';
|
||||
import type { RequestEvent } from '@sveltejs/kit/types/internal';
|
||||
import type { Job } from 'bullmq';
|
||||
import { t } from './translations';
|
||||
|
||||
try {
|
||||
if (!dev) {
|
||||
Sentry.init({
|
||||
dsn: process.env['COOLIFY_SENTRY_DSN'],
|
||||
tracesSampleRate: 0,
|
||||
environment: 'production',
|
||||
debug: true,
|
||||
release: currentVersion,
|
||||
initialScope: {
|
||||
tags: {
|
||||
appId: process.env['COOLIFY_APP_ID'],
|
||||
'os.arch': getOsArch(),
|
||||
'os.platform': os.platform(),
|
||||
'os.release': os.release()
|
||||
}
|
||||
}
|
||||
});
|
||||
// Sentry.init({
|
||||
// dsn: process.env['COOLIFY_SENTRY_DSN'],
|
||||
// tracesSampleRate: 0,
|
||||
// environment: 'production',
|
||||
// debug: true,
|
||||
// release: currentVersion,
|
||||
// initialScope: {
|
||||
// tags: {
|
||||
// appId: process.env['COOLIFY_APP_ID'],
|
||||
// 'os.arch': getOsArch(),
|
||||
// 'os.platform': os.platform(),
|
||||
// 'os.release': os.release()
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('Could not initialize Sentry, no worries.');
|
||||
@@ -179,3 +182,97 @@ export function getDomain(domain: string): string {
|
||||
export function getOsArch() {
|
||||
return os.arch();
|
||||
}
|
||||
|
||||
export async function isDNSValid(event: any, domain: string): Promise<any> {
|
||||
let resolves = [];
|
||||
try {
|
||||
if (isIP(event.url.hostname)) {
|
||||
resolves = [event.url.hostname];
|
||||
} else {
|
||||
resolves = await dns.resolve4(event.url.hostname);
|
||||
}
|
||||
} catch (error) {
|
||||
throw {
|
||||
message: t.get('application.dns_not_set_error', { domain })
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
let ipDomainFound = false;
|
||||
dns.setServers(['1.1.1.1', '8.8.8.8']);
|
||||
const dnsResolve = await dns.resolve4(domain);
|
||||
if (dnsResolve.length > 0) {
|
||||
for (const ip of dnsResolve) {
|
||||
if (resolves.includes(ip)) {
|
||||
ipDomainFound = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!ipDomainFound) throw false;
|
||||
} catch (error) {
|
||||
throw {
|
||||
message: t.get('application.domain_not_valid')
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export async function checkDomainsIsValidInDNS({ event, fqdn, dualCerts }): Promise<any> {
|
||||
const domain = getDomain(fqdn);
|
||||
const domainDualCert = domain.includes('www.') ? domain.replace('www.', '') : `www.${domain}`;
|
||||
dns.setServers(['1.1.1.1', '8.8.8.8']);
|
||||
let resolves = [];
|
||||
try {
|
||||
if (isIP(event.url.hostname)) {
|
||||
resolves = [event.url.hostname];
|
||||
} else {
|
||||
resolves = await dns.resolve4(event.url.hostname);
|
||||
}
|
||||
} catch (error) {
|
||||
throw {
|
||||
message: t.get('application.dns_not_set_error', { domain })
|
||||
};
|
||||
}
|
||||
|
||||
if (dualCerts) {
|
||||
try {
|
||||
const ipDomain = await dns.resolve4(domain);
|
||||
const ipDomainDualCert = await dns.resolve4(domainDualCert);
|
||||
|
||||
let ipDomainFound = false;
|
||||
let ipDomainDualCertFound = false;
|
||||
|
||||
for (const ip of ipDomain) {
|
||||
if (resolves.includes(ip)) {
|
||||
ipDomainFound = true;
|
||||
}
|
||||
}
|
||||
for (const ip of ipDomainDualCert) {
|
||||
if (resolves.includes(ip)) {
|
||||
ipDomainDualCertFound = true;
|
||||
}
|
||||
}
|
||||
if (ipDomainFound && ipDomainDualCertFound) return { status: 200 };
|
||||
throw false;
|
||||
} catch (error) {
|
||||
throw {
|
||||
message: t.get('application.dns_not_set_error', { domain })
|
||||
};
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
const ipDomain = await dns.resolve4(domain);
|
||||
let ipDomainFound = false;
|
||||
for (const ip of ipDomain) {
|
||||
if (resolves.includes(ip)) {
|
||||
ipDomainFound = true;
|
||||
}
|
||||
}
|
||||
if (ipDomainFound) return { status: 200 };
|
||||
throw false;
|
||||
} catch (error) {
|
||||
throw {
|
||||
message: t.get('application.dns_not_set_error', { domain })
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import Clickhouse from './svg/databases/Clickhouse.svelte';
|
||||
import CouchDb from './svg/databases/CouchDB.svelte';
|
||||
import MongoDb from './svg/databases/MongoDB.svelte';
|
||||
import MariaDb from './svg/databases/MariaDB.svelte';
|
||||
import MySql from './svg/databases/MySQL.svelte';
|
||||
import PostgreSql from './svg/databases/PostgreSQL.svelte';
|
||||
import Redis from './svg/databases/Redis.svelte';
|
||||
@@ -17,6 +18,8 @@
|
||||
<MongoDb />
|
||||
{:else if database.type === 'mysql'}
|
||||
<MySql />
|
||||
{:else if database.type === 'mariadb'}
|
||||
<MariaDb />
|
||||
{:else if database.type === 'postgresql'}
|
||||
<PostgreSql />
|
||||
{:else if database.type === 'redis'}
|
||||
|
||||
@@ -52,6 +52,12 @@ export const supportedDatabaseTypesAndVersions = [
|
||||
versions: ['5.0', '4.4', '4.2']
|
||||
},
|
||||
{ name: 'mysql', fancyName: 'MySQL', baseImage: 'bitnami/mysql', versions: ['8.0', '5.7'] },
|
||||
{
|
||||
name: 'mariadb',
|
||||
fancyName: 'MariaDB',
|
||||
baseImage: 'bitnami/mariadb',
|
||||
versions: ['10.7', '10.6', '10.5', '10.4', '10.3', '10.2']
|
||||
},
|
||||
{
|
||||
name: 'postgresql',
|
||||
fancyName: 'PostgreSQL',
|
||||
@@ -215,3 +221,11 @@ export const supportedServiceTypesAndVersions = [
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
export const getServiceMainPort = (service: string) => {
|
||||
const serviceType = supportedServiceTypesAndVersions.find((s) => s.name === service);
|
||||
if (serviceType) {
|
||||
return serviceType.ports.main;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
24
src/lib/components/svg/databases/MariaDB.svelte
Normal file
24
src/lib/components/svg/databases/MariaDB.svelte
Normal file
@@ -0,0 +1,24 @@
|
||||
<script lang="ts">
|
||||
export let isAbsolute = false;
|
||||
</script>
|
||||
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
id="Layer_1"
|
||||
data-name="Layer 1"
|
||||
viewBox="0 0 309.88 252.72"
|
||||
class={isAbsolute ? 'absolute top-0 left-0 -m-5 h-12 w-12 ' : 'mx-auto w-8 h-8'}
|
||||
>
|
||||
<defs>
|
||||
<style>
|
||||
.cls-1 {
|
||||
fill: #fff;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<path
|
||||
class="cls-1"
|
||||
d="M316,10.05a4.2,4.2,0,0,0-2.84-1c-2.84,0-6.5,1.92-8.46,3l-.79.4a26.81,26.81,0,0,1-10.57,2.66c-3.76.12-7,.34-11.22.77-25,2.58-36.15,21.74-46.89,40.27-5.84,10.08-11.88,20.5-20.16,28.57a55.71,55.71,0,0,1-5.46,4.63c-8.57,6.39-19.33,10.9-27.74,14.12-8.07,3.08-16.86,5.85-25.37,8.53-7.78,2.45-15.14,4.76-21.9,7.28-3.05,1.13-5.64,2-7.93,2.76-6.15,2-10.6,3.53-17.08,8-2.53,1.73-5.07,3.6-6.8,5a71.26,71.26,0,0,0-13.54,14.27A84.81,84.81,0,0,1,77.88,163c-1.36,1.34-3.8,2-7.43,2-4.27,0-9.43-.88-14.91-1.81s-11.46-2-16.46-2c-4.07,0-7.17.66-9.5,2,0,0-3.9,2.28-5.56,5.23l1.62.73a33.56,33.56,0,0,1,6.93,5,33.68,33.68,0,0,0,7.19,5.12A6.37,6.37,0,0,1,42,180.72c-.69,1-1.69,2.29-2.74,3.67-5.77,7.55-9.13,12.32-7.2,14.92a6,6,0,0,0,3,.68c12.59,0,19.34-3.27,27.9-7.41,2.47-1.2,5-2.44,8-3.7,5-2.17,10.38-5.63,16.08-9.29,7.55-4.85,15.36-9.87,22.92-12.3a62.3,62.3,0,0,1,19.23-2.7c8,0,16.42,1.07,24.54,2.11,6.06.78,12.32,1.58,18.47,2,2.39.14,4.6.21,6.76.21a78.48,78.48,0,0,0,8.61-.45l.68-.24c4.32-2.65,6.34-8.34,8.29-13.84,1.26-3.54,2.32-6.72,4-8.74a2.06,2.06,0,0,1,.33-.27.4.4,0,0,1,.49.08.25.25,0,0,1,0,.16c-1,21.51-9.67,35.16-18.42,47.3L177,199.14s8.18,0,12.84-1.8c17-5.08,29.84-16.28,39.18-34.14a144.39,144.39,0,0,0,6.16-14.09c.16-.4,1.64-1.14,1.49.93,0,.61-.08,1.29-.13,2h0c0,.42-.06.85-.08,1.28-.25,3-1,9.34-1,9.34l5.25-2.81c12.66-8,22.42-24.14,29.82-49.25,3.09-10.46,5.34-20.85,7.33-30,2.38-11,4.43-20.43,6.78-24.09,3.69-5.74,9.32-9.62,14.77-13.39.75-.51,1.49-1,2.22-1.54,6.86-4.81,13.67-10.36,15.16-20.71l0-.23C317.93,12.92,317,11,316,10.05Z"
|
||||
transform="translate(-7.45 -9.1)"
|
||||
/>
|
||||
</svg>
|
||||
@@ -3,31 +3,88 @@
|
||||
</script>
|
||||
|
||||
<svg
|
||||
class={isAbsolute ? 'absolute top-0 left-0 -m-5 h-10 w-10' : 'mx-auto w-8 h-8'}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
id="Layer_1"
|
||||
data-name="Layer 1"
|
||||
viewBox="0 0 216.56 448.5"
|
||||
><defs
|
||||
><style>
|
||||
.cls-1 {
|
||||
fill: #10aa50;
|
||||
}
|
||||
.cls-2 {
|
||||
fill: #b8c4c2;
|
||||
}
|
||||
.cls-3 {
|
||||
fill: #12924f;
|
||||
}
|
||||
</style></defs
|
||||
><path
|
||||
class="cls-1"
|
||||
d="M202.8,179.68c-23-101.47-71-128.49-83.18-147.59C113,21.7,106.25,5.91,106.25,5.91c-.66,9-1.83,14.7-9.51,21.54C81.36,41.16,16,94.42,10.51,209.72c-5.12,107.5,79,173.8,90.18,180.65,8.54,4.2,19,.08,24-3.77,40.54-27.84,96-102.07,78.06-206.92"
|
||||
viewBox="0 0 128 128"
|
||||
class={isAbsolute ? 'absolute top-0 left-0 -m-4 h-10 w-10' : 'mx-auto w-8 h-8'}
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
fill="#439934"
|
||||
d="M88.038 42.812c1.605 4.643 2.761 9.383 3.141 14.296.472 6.095.256 12.147-1.029 18.142-.035.165-.109.32-.164.48-.403.001-.814-.049-1.208.012-3.329.523-6.655 1.065-9.981 1.604-3.438.557-6.881 1.092-10.313 1.687-1.216.21-2.721-.041-3.212 1.641-.014.046-.154.054-.235.08l.166-10.051-.169-24.252 1.602-.275c2.62-.429 5.24-.864 7.862-1.281 3.129-.497 6.261-.98 9.392-1.465 1.381-.215 2.764-.412 4.148-.618z"
|
||||
/><path
|
||||
class="cls-2"
|
||||
d="M109.73,333.11c-2.11,26.62-3.63,42.11-9,57.29,0,0,3.54,25.33,6,52.17l8.77,0a488.62,488.62,0,0,1,9.57-56.2C113.71,380.8,110.16,356.46,109.73,333.11Z"
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
fill="#45A538"
|
||||
d="M61.729 110.054c-1.69-1.453-3.439-2.842-5.059-4.37-8.717-8.222-15.093-17.899-18.233-29.566-.865-3.211-1.442-6.474-1.627-9.792-.13-2.322-.318-4.665-.154-6.975.437-6.144 1.325-12.229 3.127-18.147l.099-.138c.175.233.427.439.516.702 1.759 5.18 3.505 10.364 5.242 15.551 5.458 16.3 10.909 32.604 16.376 48.9.107.318.384.579.583.866l-.87 2.969z"
|
||||
/><path
|
||||
class="cls-3"
|
||||
d="M125.06,386.39h0c-11.48-5.3-14.8-30.13-15.31-53.28A1090.8,1090.8,0,0,0,112.2,218.4c-.6-20.07.3-185.92-4.94-210.2,2.12,4.75,7.24,15.91,12.36,23.88,12.23,19.11,60.19,46.13,83.17,147.61C220.7,284.27,165.57,358.37,125.06,386.39Z"
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
fill="#46A037"
|
||||
d="M88.038 42.812c-1.384.206-2.768.403-4.149.616-3.131.485-6.263.968-9.392 1.465-2.622.417-5.242.852-7.862 1.281l-1.602.275-.012-1.045c-.053-.859-.144-1.717-.154-2.576-.069-5.478-.112-10.956-.18-16.434-.042-3.429-.105-6.857-.175-10.285-.043-2.13-.089-4.261-.185-6.388-.052-1.143-.236-2.28-.311-3.423-.042-.657.016-1.319.029-1.979.817 1.583 1.616 3.178 2.456 4.749 1.327 2.484 3.441 4.314 5.344 6.311 7.523 7.892 12.864 17.068 16.193 27.433z"
|
||||
/><path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
fill="#409433"
|
||||
d="M65.036 80.753c.081-.026.222-.034.235-.08.491-1.682 1.996-1.431 3.212-1.641 3.432-.594 6.875-1.13 10.313-1.687 3.326-.539 6.652-1.081 9.981-1.604.394-.062.805-.011 1.208-.012-.622 2.22-1.112 4.488-1.901 6.647-.896 2.449-1.98 4.839-3.131 7.182a49.142 49.142 0 01-6.353 9.763c-1.919 2.308-4.058 4.441-6.202 6.548-1.185 1.165-2.582 2.114-3.882 3.161l-.337-.23-1.214-1.038-1.256-2.753a41.402 41.402 0 01-1.394-9.838l.023-.561.171-2.426c.057-.828.133-1.655.168-2.485.129-2.982.241-5.964.359-8.946z"
|
||||
/><path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
fill="#4FAA41"
|
||||
d="M65.036 80.753c-.118 2.982-.23 5.964-.357 8.947-.035.83-.111 1.657-.168 2.485l-.765.289c-1.699-5.002-3.399-9.951-5.062-14.913-2.75-8.209-5.467-16.431-8.213-24.642a4498.887 4498.887 0 00-6.7-19.867c-.105-.31-.407-.552-.617-.826l4.896-9.002c.168.292.39.565.496.879a6167.476 6167.476 0 016.768 20.118c2.916 8.73 5.814 17.467 8.728 26.198.116.349.308.671.491 1.062l.67-.78-.167 10.052z"
|
||||
/><path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
fill="#4AA73C"
|
||||
d="M43.155 32.227c.21.274.511.516.617.826a4498.887 4498.887 0 016.7 19.867c2.746 8.211 5.463 16.433 8.213 24.642 1.662 4.961 3.362 9.911 5.062 14.913l.765-.289-.171 2.426-.155.559c-.266 2.656-.49 5.318-.814 7.968-.163 1.328-.509 2.632-.772 3.947-.198-.287-.476-.548-.583-.866-5.467-16.297-10.918-32.6-16.376-48.9a3888.972 3888.972 0 00-5.242-15.551c-.089-.263-.34-.469-.516-.702l3.272-8.84z"
|
||||
/><path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
fill="#57AE47"
|
||||
d="M65.202 70.702l-.67.78c-.183-.391-.375-.714-.491-1.062-2.913-8.731-5.812-17.468-8.728-26.198a6167.476 6167.476 0 00-6.768-20.118c-.105-.314-.327-.588-.496-.879l6.055-7.965c.191.255.463.482.562.769 1.681 4.921 3.347 9.848 5.003 14.778 1.547 4.604 3.071 9.215 4.636 13.813.105.308.47.526.714.786l.012 1.045c.058 8.082.115 16.167.171 24.251z"
|
||||
/><path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
fill="#60B24F"
|
||||
d="M65.021 45.404c-.244-.26-.609-.478-.714-.786-1.565-4.598-3.089-9.209-4.636-13.813-1.656-4.93-3.322-9.856-5.003-14.778-.099-.287-.371-.514-.562-.769 1.969-1.928 3.877-3.925 5.925-5.764 1.821-1.634 3.285-3.386 3.352-5.968.003-.107.059-.214.145-.514l.519 1.306c-.013.661-.072 1.322-.029 1.979.075 1.143.259 2.28.311 3.423.096 2.127.142 4.258.185 6.388.069 3.428.132 6.856.175 10.285.067 5.478.111 10.956.18 16.434.008.861.098 1.718.152 2.577z"
|
||||
/><path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
fill="#A9AA88"
|
||||
d="M62.598 107.085c.263-1.315.609-2.62.772-3.947.325-2.649.548-5.312.814-7.968l.066-.01.066.011a41.402 41.402 0 001.394 9.838c-.176.232-.425.439-.518.701-.727 2.05-1.412 4.116-2.143 6.166-.1.28-.378.498-.574.744l-.747-2.566.87-2.969z"
|
||||
/><path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
fill="#B6B598"
|
||||
d="M62.476 112.621c.196-.246.475-.464.574-.744.731-2.05 1.417-4.115 2.143-6.166.093-.262.341-.469.518-.701l1.255 2.754c-.248.352-.59.669-.728 1.061l-2.404 7.059c-.099.283-.437.483-.663.722l-.695-3.985z"
|
||||
/><path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
fill="#C2C1A7"
|
||||
d="M63.171 116.605c.227-.238.564-.439.663-.722l2.404-7.059c.137-.391.48-.709.728-1.061l1.215 1.037c-.587.58-.913 1.25-.717 2.097l-.369 1.208c-.168.207-.411.387-.494.624-.839 2.403-1.64 4.819-2.485 7.222-.107.305-.404.544-.614.812-.109-1.387-.22-2.771-.331-4.158z"
|
||||
/><path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
fill="#CECDB7"
|
||||
d="M63.503 120.763c.209-.269.506-.508.614-.812.845-2.402 1.646-4.818 2.485-7.222.083-.236.325-.417.494-.624l-.509 5.545c-.136.157-.333.294-.398.477-.575 1.614-1.117 3.24-1.694 4.854-.119.333-.347.627-.525.938-.158-.207-.441-.407-.454-.623-.051-.841-.016-1.688-.013-2.533z"
|
||||
/><path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
fill="#DBDAC7"
|
||||
d="M63.969 123.919c.178-.312.406-.606.525-.938.578-1.613 1.119-3.239 1.694-4.854.065-.183.263-.319.398-.477l.012 3.64-1.218 3.124-1.411-.495z"
|
||||
/><path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
fill="#EBE9DC"
|
||||
d="M65.38 124.415l1.218-3.124.251 3.696-1.469-.572z"
|
||||
/><path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
fill="#CECDB7"
|
||||
d="M67.464 110.898c-.196-.847.129-1.518.717-2.097l.337.23-1.054 1.867z"
|
||||
/><path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
fill="#4FAA41"
|
||||
d="M64.316 95.172l-.066-.011-.066.01.155-.559-.023.56z"
|
||||
/>
|
||||
</svg>
|
||||
|
||||
@@ -4,6 +4,6 @@
|
||||
|
||||
<img
|
||||
alt="plausible logo"
|
||||
class={isAbsolute ? 'w-10 absolute top-0 left-0 -m-5' : 'w-6 mx-auto'}
|
||||
class={isAbsolute ? 'w-9 absolute top-0 left-0 -m-4' : 'w-6 mx-auto'}
|
||||
src="/plausible.png"
|
||||
/>
|
||||
|
||||
@@ -128,9 +128,7 @@ export function findBuildPack(pack, packageManager = 'npm') {
|
||||
if (pack === 'astro') {
|
||||
return {
|
||||
...metaData,
|
||||
installCommand: `yarn install`,
|
||||
buildCommand: `yarn build`,
|
||||
startCommand: null,
|
||||
...defaultBuildAndDeploy(packageManager),
|
||||
publishDirectory: `dist`,
|
||||
port: 80
|
||||
};
|
||||
@@ -138,9 +136,7 @@ export function findBuildPack(pack, packageManager = 'npm') {
|
||||
if (pack === 'eleventy') {
|
||||
return {
|
||||
...metaData,
|
||||
installCommand: `yarn install`,
|
||||
buildCommand: `yarn build`,
|
||||
startCommand: null,
|
||||
...defaultBuildAndDeploy(packageManager),
|
||||
publishDirectory: `_site`,
|
||||
port: 80
|
||||
};
|
||||
|
||||
@@ -138,7 +138,18 @@ export async function getApplicationWebhook({
|
||||
return s;
|
||||
});
|
||||
}
|
||||
return { ...application };
|
||||
const { baseImage, baseBuildImage, baseBuildImages, baseImages } = setDefaultBaseImage(
|
||||
application.buildPack
|
||||
);
|
||||
|
||||
// Set default build images
|
||||
if (!application.baseImage) {
|
||||
application.baseImage = baseImage;
|
||||
}
|
||||
if (!application.baseBuildImage) {
|
||||
application.baseBuildImage = baseBuildImage;
|
||||
}
|
||||
return { ...application, baseBuildImages, baseImages };
|
||||
} catch (e) {
|
||||
throw { status: 404, body: { message: e.message } };
|
||||
}
|
||||
@@ -267,6 +278,7 @@ export async function configureApplication({
|
||||
name,
|
||||
fqdn,
|
||||
port,
|
||||
exposePort,
|
||||
installCommand,
|
||||
buildCommand,
|
||||
startCommand,
|
||||
@@ -286,6 +298,7 @@ export async function configureApplication({
|
||||
name: string;
|
||||
fqdn: string;
|
||||
port: number;
|
||||
exposePort: number;
|
||||
installCommand: string;
|
||||
buildCommand: string;
|
||||
startCommand: string;
|
||||
@@ -307,6 +320,7 @@ export async function configureApplication({
|
||||
buildPack,
|
||||
fqdn,
|
||||
port,
|
||||
exposePort,
|
||||
installCommand,
|
||||
buildCommand,
|
||||
startCommand,
|
||||
|
||||
@@ -28,7 +28,7 @@ if (!dev) {
|
||||
}
|
||||
|
||||
export const prisma = new PrismaClient({
|
||||
errorFormat: 'pretty',
|
||||
errorFormat: 'minimal',
|
||||
rejectOnNotFound: false
|
||||
});
|
||||
|
||||
@@ -58,7 +58,7 @@ export function ErrorHandler(e: {
|
||||
truncatedError.message = 'git clone failed';
|
||||
}
|
||||
if (!e.message?.includes('Coolify Proxy is not running')) {
|
||||
sentry.captureException(truncatedError);
|
||||
// sentry.captureException(truncatedError);
|
||||
}
|
||||
const payload = {
|
||||
status: truncatedError.status || 500,
|
||||
@@ -149,6 +149,19 @@ export function generateDatabaseConfiguration(database: Database & { settings: D
|
||||
MONGODB_ROOT_PASSWORD: string;
|
||||
};
|
||||
}
|
||||
| {
|
||||
volume: string;
|
||||
image: string;
|
||||
ulimits: Record<string, unknown>;
|
||||
privatePort: number;
|
||||
environmentVariables: {
|
||||
MARIADB_ROOT_USER: string;
|
||||
MARIADB_ROOT_PASSWORD: string;
|
||||
MARIADB_USER: string;
|
||||
MARIADB_PASSWORD: string;
|
||||
MARIADB_DATABASE: string;
|
||||
};
|
||||
}
|
||||
| {
|
||||
volume: string;
|
||||
image: string;
|
||||
@@ -207,6 +220,20 @@ export function generateDatabaseConfiguration(database: Database & { settings: D
|
||||
volume: `${id}-${type}-data:/bitnami/mysql/data`,
|
||||
ulimits: {}
|
||||
};
|
||||
} else if (type === 'mariadb') {
|
||||
return {
|
||||
privatePort: 3306,
|
||||
environmentVariables: {
|
||||
MARIADB_ROOT_USER: rootUser,
|
||||
MARIADB_ROOT_PASSWORD: rootUserPassword,
|
||||
MARIADB_USER: dbUser,
|
||||
MARIADB_PASSWORD: dbUserPassword,
|
||||
MARIADB_DATABASE: defaultDatabase
|
||||
},
|
||||
image: `${baseImage}:${version}`,
|
||||
volume: `${id}-${type}-data:/bitnami/mariadb`,
|
||||
ulimits: {}
|
||||
};
|
||||
} else if (type === 'mongodb') {
|
||||
return {
|
||||
privatePort: 27017,
|
||||
|
||||
@@ -184,6 +184,10 @@ export async function updatePasswordInDb(database, user, newPassword, isRoot) {
|
||||
await asyncExecShell(
|
||||
`DOCKER_HOST=${host} docker exec ${id} mysql -u ${rootUser} -p${rootUserPassword} -e \"ALTER USER '${user}'@'%' IDENTIFIED WITH caching_sha2_password BY '${newPassword}';\"`
|
||||
);
|
||||
} else if (type === 'mariadb') {
|
||||
await asyncExecShell(
|
||||
`DOCKER_HOST=${host} docker exec ${id} mysql -u ${rootUser} -p${rootUserPassword} -e \"SET PASSWORD FOR '${user}'@'%' = PASSWORD('${newPassword}');\"`
|
||||
);
|
||||
} else if (type === 'postgresql') {
|
||||
if (isRoot) {
|
||||
await asyncExecShell(
|
||||
|
||||
@@ -327,35 +327,45 @@ export async function updatePlausibleAnalyticsService({
|
||||
id,
|
||||
fqdn,
|
||||
email,
|
||||
exposePort,
|
||||
username,
|
||||
name
|
||||
name,
|
||||
scriptName
|
||||
}: {
|
||||
id: string;
|
||||
fqdn: string;
|
||||
exposePort?: number;
|
||||
name: string;
|
||||
email: string;
|
||||
username: string;
|
||||
scriptName: string;
|
||||
}): Promise<void> {
|
||||
await prisma.plausibleAnalytics.update({ where: { serviceId: id }, data: { email, username } });
|
||||
await prisma.service.update({ where: { id }, data: { name, fqdn } });
|
||||
await prisma.plausibleAnalytics.update({
|
||||
where: { serviceId: id },
|
||||
data: { email, username, scriptName }
|
||||
});
|
||||
await prisma.service.update({ where: { id }, data: { name, fqdn, exposePort } });
|
||||
}
|
||||
|
||||
export async function updateService({
|
||||
id,
|
||||
fqdn,
|
||||
exposePort,
|
||||
name
|
||||
}: {
|
||||
id: string;
|
||||
fqdn: string;
|
||||
exposePort?: number;
|
||||
name: string;
|
||||
}): Promise<Service> {
|
||||
return await prisma.service.update({ where: { id }, data: { fqdn, name } });
|
||||
return await prisma.service.update({ where: { id }, data: { fqdn, name, exposePort } });
|
||||
}
|
||||
|
||||
export async function updateFiderService({
|
||||
id,
|
||||
fqdn,
|
||||
name,
|
||||
exposePort,
|
||||
emailNoreply,
|
||||
emailMailgunApiKey,
|
||||
emailMailgunDomain,
|
||||
@@ -368,6 +378,7 @@ export async function updateFiderService({
|
||||
}: {
|
||||
id: string;
|
||||
fqdn: string;
|
||||
exposePort?: number;
|
||||
name: string;
|
||||
emailNoreply: string;
|
||||
emailMailgunApiKey: string;
|
||||
@@ -384,6 +395,7 @@ export async function updateFiderService({
|
||||
data: {
|
||||
fqdn,
|
||||
name,
|
||||
exposePort,
|
||||
fider: {
|
||||
update: {
|
||||
emailNoreply,
|
||||
@@ -405,18 +417,36 @@ export async function updateWordpress({
|
||||
id,
|
||||
fqdn,
|
||||
name,
|
||||
exposePort,
|
||||
mysqlDatabase,
|
||||
extraConfig
|
||||
extraConfig,
|
||||
mysqlHost,
|
||||
mysqlPort
|
||||
}: {
|
||||
id: string;
|
||||
fqdn: string;
|
||||
name: string;
|
||||
exposePort?: number;
|
||||
mysqlDatabase: string;
|
||||
extraConfig: string;
|
||||
mysqlHost?: string;
|
||||
mysqlPort?: number;
|
||||
}): Promise<Service> {
|
||||
return await prisma.service.update({
|
||||
where: { id },
|
||||
data: { fqdn, name, wordpress: { update: { mysqlDatabase, extraConfig } } }
|
||||
data: {
|
||||
fqdn,
|
||||
name,
|
||||
exposePort,
|
||||
wordpress: {
|
||||
update: {
|
||||
mysqlDatabase,
|
||||
extraConfig,
|
||||
mysqlHost,
|
||||
mysqlPort
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -434,16 +464,18 @@ export async function updateGhostService({
|
||||
id,
|
||||
fqdn,
|
||||
name,
|
||||
exposePort,
|
||||
mariadbDatabase
|
||||
}: {
|
||||
id: string;
|
||||
fqdn: string;
|
||||
name: string;
|
||||
exposePort?: number;
|
||||
mariadbDatabase: string;
|
||||
}): Promise<Service> {
|
||||
return await prisma.service.update({
|
||||
where: { id },
|
||||
data: { fqdn, name, ghost: { update: { mariadbDatabase } } }
|
||||
data: { fqdn, name, exposePort, ghost: { update: { mariadbDatabase } } }
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,9 @@ frontend http
|
||||
http-request redirect location {{{redirectValue}}} code ${
|
||||
dev ? 302 : 301
|
||||
} if { req.hdr(host) -i {{redirectTo}} }
|
||||
{{#scriptName}}
|
||||
http-request set-path /js/plausible.js if { hdr(host) -i {{domain}} } { path_beg -i /js/{{scriptName}} }
|
||||
{{/scriptName}}
|
||||
{{/services}}
|
||||
|
||||
{{#coolify}}
|
||||
@@ -218,7 +221,15 @@ export async function configureHAProxy(): Promise<void> {
|
||||
const services = await listServicesWithIncludes();
|
||||
|
||||
for (const service of services) {
|
||||
const { fqdn, id, type, destinationDocker, destinationDockerId, updatedAt } = service;
|
||||
const {
|
||||
fqdn,
|
||||
id,
|
||||
type,
|
||||
destinationDocker,
|
||||
destinationDockerId,
|
||||
updatedAt,
|
||||
plausibleAnalytics
|
||||
} = service;
|
||||
if (destinationDockerId) {
|
||||
const { engine } = destinationDocker;
|
||||
const found = supportedServiceTypesAndVersions.find((a) => a.name === type);
|
||||
@@ -232,6 +243,12 @@ export async function configureHAProxy(): Promise<void> {
|
||||
const isWWW = fqdn.includes('www.');
|
||||
const redirectValue = `${isHttps ? 'https://' : 'http://'}${domain}%[capture.req.uri]`;
|
||||
if (isRunning) {
|
||||
// Plausible Analytics custom script
|
||||
let scriptName = false;
|
||||
if (type === 'plausibleanalytics' && plausibleAnalytics.scriptName !== 'plausible.js') {
|
||||
scriptName = plausibleAnalytics.scriptName;
|
||||
}
|
||||
|
||||
data.services.push({
|
||||
id,
|
||||
port,
|
||||
@@ -241,7 +258,8 @@ export async function configureHAProxy(): Promise<void> {
|
||||
isHttps,
|
||||
redirectValue,
|
||||
redirectTo: isWWW ? domain.replace('www.', '') : 'www.' + domain,
|
||||
updatedAt: updatedAt.getTime()
|
||||
updatedAt: updatedAt.getTime(),
|
||||
scriptName
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -290,3 +290,30 @@ export async function generateSSLCerts(): Promise<void> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function renewSSLCerts(): Promise<void> {
|
||||
if (!dev) {
|
||||
const host = 'unix:///var/run/docker.sock';
|
||||
await asyncExecShell(`docker pull alpine:latest`);
|
||||
const certbotImage =
|
||||
process.arch === 'x64' ? 'certbot/certbot' : 'certbot/certbot:arm64v8-latest';
|
||||
|
||||
const { stdout: certificates } = await asyncExecShell(
|
||||
`DOCKER_HOST=${host} docker run --rm -v "coolify-letsencrypt:/etc/letsencrypt" -v "coolify-ssl-certs:/app/ssl" alpine:latest sh -c "ls -1 /etc/letsencrypt/live/ | grep -v README"`
|
||||
);
|
||||
|
||||
for (const certificate of certificates.trim().split('\n')) {
|
||||
try {
|
||||
await asyncExecShell(
|
||||
`DOCKER_HOST=${host} docker run --rm --name certbot-renewal -p 9080:9080 -v "coolify-letsencrypt:/etc/letsencrypt" ${certbotImage} --cert-name ${certificate} --logs-dir /etc/letsencrypt/logs renew --standalone --preferred-challenges http --http-01-address 0.0.0.0 --http-01-port 9080`
|
||||
);
|
||||
await asyncExecShell(
|
||||
`DOCKER_HOST=${host} docker run --rm -v "coolify-letsencrypt:/etc/letsencrypt" -v "coolify-ssl-certs:/app/ssl" alpine:latest sh -c "test -d /etc/letsencrypt/live/${certificate}/ && cat /etc/letsencrypt/live/${certificate}/fullchain.pem /etc/letsencrypt/live/${certificate}/privkey.pem > /app/ssl/${certificate}.pem"`
|
||||
);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
await reloadHaproxy('unix:///var/run/docker.sock');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,13 +178,15 @@
|
||||
"delete_application": "Delete application",
|
||||
"permission_denied_delete_application": "You do not have permission to delete this application",
|
||||
"domain_already_in_use": "Domain {{domain}} is already used.",
|
||||
"dns_not_set_error": "DNS not set or propogated for {{domain}}.<br><br>Please check your DNS settings.",
|
||||
"dns_not_set_error": "DNS not set correctly or propogated for {{domain}}.<br><br>Please check your DNS settings.",
|
||||
"domain_required": "Domain is required.",
|
||||
"settings_saved": "Settings saved.",
|
||||
"dns_not_set_partial_error": "DNS not set",
|
||||
"domain_not_valid": "Could not resolve domain or it's not pointing to the server IP address.<br><br>Please check your DNS configuration and try again.",
|
||||
"git_source": "Git Source",
|
||||
"git_repository": "Git Repository",
|
||||
"build_pack": "Build Pack",
|
||||
"base_image": "Deplyoment Image",
|
||||
"base_image": "Deployment Image",
|
||||
"base_image_explainer": "Image that will be used for the deployment.",
|
||||
"base_build_image": "Build Image",
|
||||
"base_build_image_explainer": "Image that will be used during the build process.",
|
||||
@@ -204,6 +206,7 @@
|
||||
"enable_automatic_deployment": "Enable Automatic Deployment",
|
||||
"enable_auto_deploy_webhooks": "Enable automatic deployment through webhooks.",
|
||||
"enable_mr_pr_previews": "Enable MR/PR Previews",
|
||||
"expose_a_port": "Expose a port",
|
||||
"enable_preview_deploy_mr_pr_requests": "Enable preview deployments from pull or merge requests.",
|
||||
"debug_logs": "Debug Logs",
|
||||
"enable_debug_log_during_build": "Enable debug logs during build phase.<br><span class='text-red-500 font-bold'>Sensitive information</span> could be visible and saved in logs.",
|
||||
@@ -311,7 +314,7 @@
|
||||
"credential_stat_explainer": "Credentials for <a class=\"text-white font-bold\" href=\"{{link}}\" target=\"_blank\">stats</a> page.",
|
||||
"auto_update_enabled": "Auto update enabled?",
|
||||
"auto_update_enabled_explainer": "Enable automatic updates for Coolify. It will be done automatically behind the scenes, if there is no build process running.",
|
||||
"generate_www_non_www_ssl": "It will generate certificates for both www and non-www. <br>You need to have <span class='font-bold text-yellow-500'>both DNS entries</span> set in advance.<br><br>Service needs to be restarted.",
|
||||
"generate_www_non_www_ssl": "It will generate certificates for both www and non-www. <br>You need to have <span class='font-bold text-yellow-500'>both DNS entries</span> set in advance.",
|
||||
"is_dns_check_enabled": "DNS check enabled?",
|
||||
"is_dns_check_enabled_explainer": "You can disable DNS check before creating SSL certificates.<br><br>Turning it off is useful when Coolify is behind a reverse proxy or tunnel."
|
||||
},
|
||||
|
||||
@@ -61,6 +61,7 @@
|
||||
"enable_debug_log_during_build": "Activez les journaux de débogage pendant la phase de build.<br><span class='text-red-500 font-bold'>Les informations sensibles</span> peuvent être visibles et enregistrées dans les journaux.",
|
||||
"enable_mr_pr_previews": "Activer les aperçus MR/PR",
|
||||
"enable_preview_deploy_mr_pr_requests": "Activez les déploiements de prévisualisation à partir de demandes d'extraction ou de fusion.",
|
||||
"expose_a_port": "Exposer un port",
|
||||
"features": "Caractéristiques",
|
||||
"git_repository": "Dépôt Git",
|
||||
"git_source": "Source Git",
|
||||
|
||||
@@ -48,6 +48,7 @@ export default async function (job: Job<BuilderJob, void, string>): Promise<void
|
||||
pythonModule,
|
||||
pythonVariable,
|
||||
denoOptions,
|
||||
exposePort,
|
||||
baseImage,
|
||||
baseBuildImage
|
||||
} = job.data;
|
||||
@@ -152,6 +153,7 @@ export default async function (job: Job<BuilderJob, void, string>): Promise<void
|
||||
JSON.stringify({
|
||||
buildPack,
|
||||
port,
|
||||
exposePort,
|
||||
installCommand,
|
||||
buildCommand,
|
||||
startCommand,
|
||||
@@ -207,7 +209,7 @@ export default async function (job: Job<BuilderJob, void, string>): Promise<void
|
||||
tag,
|
||||
workdir,
|
||||
docker,
|
||||
port,
|
||||
port: exposePort ? `${exposePort}:${port}` : port,
|
||||
installCommand,
|
||||
buildCommand,
|
||||
startCommand,
|
||||
@@ -263,7 +265,7 @@ export default async function (job: Job<BuilderJob, void, string>): Promise<void
|
||||
repository,
|
||||
branch,
|
||||
projectId,
|
||||
port,
|
||||
port: exposePort ? `${exposePort}:${port}` : port,
|
||||
commit,
|
||||
installCommand,
|
||||
buildCommand,
|
||||
@@ -298,6 +300,7 @@ export default async function (job: Job<BuilderJob, void, string>): Promise<void
|
||||
labels,
|
||||
depends_on: [],
|
||||
restart: 'always',
|
||||
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
||||
// logging: {
|
||||
// driver: 'fluentd',
|
||||
// },
|
||||
@@ -325,7 +328,7 @@ export default async function (job: Job<BuilderJob, void, string>): Promise<void
|
||||
await saveBuildLog({ line: 'Deployment successful!', buildId, applicationId });
|
||||
} catch (error) {
|
||||
await saveBuildLog({ line: error, buildId, applicationId });
|
||||
sentry.captureException(error);
|
||||
// sentry.captureException(error);
|
||||
throw new Error(error);
|
||||
}
|
||||
await saveBuildLog({ line: 'Proxy will be updated shortly.', buildId, applicationId });
|
||||
|
||||
@@ -41,7 +41,6 @@ export default async function (): Promise<void> {
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
console.log(`Is LowDiskSpace detected? ${lowDiskSpace}`);
|
||||
if (lowDiskSpace) {
|
||||
// Cleanup old coolify images
|
||||
try {
|
||||
|
||||
@@ -116,8 +116,8 @@ const cron = async (): Promise<void> => {
|
||||
await queue.proxyTcpHttp.add('proxyTcpHttp', {}, { repeat: { every: 10000 } });
|
||||
await queue.ssl.add('ssl', {}, { repeat: { every: dev ? 10000 : 60000 } });
|
||||
if (!dev) await queue.cleanup.add('cleanup', {}, { repeat: { every: 300000 } });
|
||||
await queue.sslRenew.add('sslRenew', {}, { repeat: { every: 1800000 } });
|
||||
await queue.autoUpdater.add('autoUpdater', {}, { repeat: { every: 60000 } });
|
||||
if (!dev) await queue.sslRenew.add('sslRenew', {}, { repeat: { every: 1800000 } });
|
||||
if (!dev) await queue.autoUpdater.add('autoUpdater', {}, { repeat: { every: 60000 } });
|
||||
};
|
||||
cron().catch((error) => {
|
||||
console.log('cron failed to start');
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { asyncExecShell } from '$lib/common';
|
||||
import { reloadHaproxy } from '$lib/haproxy';
|
||||
import { renewSSLCerts } from '$lib/letsencrypt';
|
||||
|
||||
export default async function (): Promise<void> {
|
||||
await asyncExecShell(
|
||||
`docker run --rm --name certbot-renewal -v "coolify-letsencrypt:/etc/letsencrypt" certbot/certbot --logs-dir /etc/letsencrypt/logs renew`
|
||||
);
|
||||
await reloadHaproxy('unix:///var/run/docker.sock');
|
||||
try {
|
||||
return await renewSSLCerts();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ export type BuilderJob = {
|
||||
buildPack: BuildPackName;
|
||||
projectId: number;
|
||||
port: number;
|
||||
exposePort?: number;
|
||||
installCommand: string;
|
||||
buildCommand?: string;
|
||||
startCommand?: string;
|
||||
|
||||
@@ -18,6 +18,7 @@ export type ComposeFileService = {
|
||||
restart: ComposeFileRestartOption;
|
||||
depends_on?: string[];
|
||||
command?: string;
|
||||
ports?: string[];
|
||||
build?: {
|
||||
context: string;
|
||||
dockerfile: string;
|
||||
|
||||
39
src/routes/_Trend.svelte
Normal file
39
src/routes/_Trend.svelte
Normal file
@@ -0,0 +1,39 @@
|
||||
<script lang="ts">
|
||||
export let trend;
|
||||
</script>
|
||||
|
||||
{#if trend === 'up'}
|
||||
<span class="-mt-1 inline-flex px-2 text-green-500">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-8 w-8"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<line x1="17" y1="7" x2="7" y2="17" />
|
||||
<polyline points="8 7 17 7 17 16" />
|
||||
</svg></span
|
||||
>
|
||||
{:else if trend === 'down'}
|
||||
<span class="text-red-500 px-2 inline-flex -mt-1">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="w-8 h-8"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<line x1="7" y1="7" x2="17" y2="17" />
|
||||
<polyline points="17 8 17 17 8 17" />
|
||||
</svg>
|
||||
</span>
|
||||
{/if}
|
||||
@@ -78,6 +78,7 @@
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
async function logout() {
|
||||
try {
|
||||
await del(`/logout.json`, {});
|
||||
@@ -137,7 +138,7 @@
|
||||
{#if !$session.whiteLabeled}
|
||||
<div class="my-4 h-10 w-10"><img src="/favicon.png" alt="coolLabs logo" /></div>
|
||||
{/if}
|
||||
<div class="flex flex-col space-y-4 py-2" class:mt-2={$session.whiteLabeled}>
|
||||
<div class="flex flex-col space-y-2 py-2" class:mt-2={$session.whiteLabeled}>
|
||||
<a
|
||||
sveltekit:prefetch
|
||||
href="/"
|
||||
@@ -222,7 +223,6 @@
|
||||
<polyline points="10 15 13 18 10 21" />
|
||||
</svg>
|
||||
</a>
|
||||
<div class="border-t border-stone-700" />
|
||||
<a
|
||||
sveltekit:prefetch
|
||||
href="/destinations"
|
||||
@@ -284,7 +284,6 @@
|
||||
<path d="M4 12v6a8 3 0 0 0 16 0v-6" />
|
||||
</svg>
|
||||
</a>
|
||||
<div class="border-t border-stone-700" />
|
||||
<a
|
||||
sveltekit:prefetch
|
||||
href="/services"
|
||||
@@ -423,7 +422,7 @@
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
<div class="flex flex-col space-y-4 py-2">
|
||||
<div class="flex flex-col space-y-2 py-2">
|
||||
<a
|
||||
sveltekit:prefetch
|
||||
href="/iam"
|
||||
|
||||
@@ -3,6 +3,61 @@ import { buildQueue } from '$lib/queues';
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
import * as db from '$lib/database';
|
||||
|
||||
async function cleanupDB(buildId: string) {
|
||||
const data = await db.prisma.build.findUnique({ where: { id: buildId } });
|
||||
if (data?.status === 'queued' || data?.status === 'running') {
|
||||
await db.prisma.build.update({ where: { id: buildId }, data: { status: 'failed' } });
|
||||
}
|
||||
}
|
||||
|
||||
async function stopBuild(buildId, applicationId) {
|
||||
let count = 0;
|
||||
await new Promise<void>(async (resolve, reject) => {
|
||||
const job = await buildQueue.getJob(buildId);
|
||||
if (!job) {
|
||||
await cleanupDB(buildId);
|
||||
return resolve();
|
||||
}
|
||||
const {
|
||||
destinationDocker: { engine }
|
||||
} = job?.data;
|
||||
const host = getEngine(engine);
|
||||
let interval = setInterval(async () => {
|
||||
try {
|
||||
const data = await db.prisma.build.findUnique({ where: { id: buildId } });
|
||||
if (data?.status === 'failed') {
|
||||
clearInterval(interval);
|
||||
return resolve();
|
||||
}
|
||||
if (count > 100) {
|
||||
clearInterval(interval);
|
||||
return reject(new Error('Build canceled'));
|
||||
}
|
||||
|
||||
const { stdout: buildContainers } = await asyncExecShell(
|
||||
`DOCKER_HOST=${host} docker container ls --filter "label=coolify.buildId=${buildId}" --format '{{json .}}'`
|
||||
);
|
||||
if (buildContainers) {
|
||||
const containersArray = buildContainers.trim().split('\n');
|
||||
for (const container of containersArray) {
|
||||
const containerObj = JSON.parse(container);
|
||||
const id = containerObj.ID;
|
||||
if (!containerObj.Names.startsWith(`${applicationId}`)) {
|
||||
await removeDestinationDocker({ id, engine });
|
||||
clearInterval(interval);
|
||||
await saveBuildLog({
|
||||
line: 'Canceled by user!',
|
||||
buildId: job.data.build_id,
|
||||
applicationId: job.data.id
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
count++;
|
||||
} catch (error) {}
|
||||
}, 100);
|
||||
});
|
||||
}
|
||||
export const post: RequestHandler = async (event) => {
|
||||
const { buildId, applicationId } = await event.request.json();
|
||||
if (!buildId) {
|
||||
@@ -14,50 +69,7 @@ export const post: RequestHandler = async (event) => {
|
||||
};
|
||||
}
|
||||
try {
|
||||
let count = 0;
|
||||
await new Promise<void>(async (resolve, reject) => {
|
||||
const job = await buildQueue.getJob(buildId);
|
||||
const {
|
||||
destinationDocker: { engine }
|
||||
} = job.data;
|
||||
const host = getEngine(engine);
|
||||
let interval = setInterval(async () => {
|
||||
const { status } = await db.prisma.build.findUnique({ where: { id: buildId } });
|
||||
if (status === 'failed') {
|
||||
clearInterval(interval);
|
||||
return resolve();
|
||||
}
|
||||
if (count > 1200) {
|
||||
clearInterval(interval);
|
||||
reject(new Error('Could not cancel build.'));
|
||||
}
|
||||
try {
|
||||
const { stdout: buildContainers } = await asyncExecShell(
|
||||
`DOCKER_HOST=${host} docker container ls --filter "label=coolify.buildId=${buildId}" --format '{{json .}}'`
|
||||
);
|
||||
if (buildContainers) {
|
||||
const containersArray = buildContainers.trim().split('\n');
|
||||
for (const container of containersArray) {
|
||||
const containerObj = JSON.parse(container);
|
||||
const id = containerObj.ID;
|
||||
if (!containerObj.Names.startsWith(`${applicationId}`)) {
|
||||
await removeDestinationDocker({ id, engine });
|
||||
clearInterval(interval);
|
||||
await saveBuildLog({
|
||||
line: 'Canceled by user!',
|
||||
buildId: job.data.build_id,
|
||||
applicationId: job.data.id
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
count++;
|
||||
} catch (error) {}
|
||||
}, 100);
|
||||
|
||||
resolve();
|
||||
});
|
||||
|
||||
await stopBuild(buildId, applicationId);
|
||||
return {
|
||||
status: 200,
|
||||
body: {
|
||||
|
||||
@@ -1,21 +1,44 @@
|
||||
import { dev } from '$app/env';
|
||||
import { getDomain, getUserDetails } from '$lib/common';
|
||||
import { checkDomainsIsValidInDNS, getDomain, getUserDetails, isDNSValid } from '$lib/common';
|
||||
import * as db from '$lib/database';
|
||||
import { ErrorHandler } from '$lib/database';
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
import { promises as dns } from 'dns';
|
||||
import getPort from 'get-port';
|
||||
import { t } from '$lib/translations';
|
||||
|
||||
export const get: RequestHandler = async (event) => {
|
||||
const { status, body } = await getUserDetails(event);
|
||||
if (status === 401) return { status, body };
|
||||
const domain = event.url.searchParams.get('domain');
|
||||
if (!domain) {
|
||||
return {
|
||||
status: 500,
|
||||
body: {
|
||||
message: t.get('application.domain_required')
|
||||
}
|
||||
};
|
||||
}
|
||||
try {
|
||||
await isDNSValid(event, domain);
|
||||
return {
|
||||
status: 200
|
||||
};
|
||||
} catch (error) {
|
||||
return ErrorHandler(error);
|
||||
}
|
||||
};
|
||||
|
||||
export const post: RequestHandler = async (event) => {
|
||||
const { status, body } = await getUserDetails(event);
|
||||
if (status === 401) return { status, body };
|
||||
|
||||
const { id } = event.params;
|
||||
let { fqdn, forceSave } = await event.request.json();
|
||||
let { exposePort, fqdn, forceSave, dualCerts } = await event.request.json();
|
||||
fqdn = fqdn.toLowerCase();
|
||||
|
||||
try {
|
||||
const domain = getDomain(fqdn);
|
||||
const { isDNSCheckEnabled } = await db.prisma.setting.findFirst({});
|
||||
const found = await db.isDomainConfigured({ id, fqdn });
|
||||
if (found) {
|
||||
throw {
|
||||
@@ -24,25 +47,22 @@ export const post: RequestHandler = async (event) => {
|
||||
})
|
||||
};
|
||||
}
|
||||
if (!dev && !forceSave) {
|
||||
let ip = [];
|
||||
let localIp = [];
|
||||
dns.setServers(['1.1.1.1', '8.8.8.8']);
|
||||
|
||||
try {
|
||||
localIp = await dns.resolve4(event.url.hostname);
|
||||
} catch (error) {}
|
||||
try {
|
||||
ip = await dns.resolve4(domain);
|
||||
} catch (error) {}
|
||||
if (exposePort) {
|
||||
exposePort = Number(exposePort);
|
||||
|
||||
if (localIp?.length > 0) {
|
||||
if (ip?.length === 0 || !ip.includes(localIp[0])) {
|
||||
throw {
|
||||
message: t.get('application.dns_not_set_error', { domain: domain })
|
||||
};
|
||||
}
|
||||
if (exposePort < 1024 || exposePort > 65535) {
|
||||
throw { message: `Expose Port needs to be between 1024 and 65535.` };
|
||||
}
|
||||
|
||||
const publicPort = await getPort({ port: exposePort });
|
||||
if (publicPort !== exposePort) {
|
||||
throw { message: `Port ${exposePort} is already in use.` };
|
||||
}
|
||||
}
|
||||
|
||||
if (isDNSCheckEnabled && !dev && !forceSave) {
|
||||
return await checkDomainsIsValidInDNS({ event, fqdn, dualCerts });
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -22,6 +22,7 @@ export const post: RequestHandler = async (event) => {
|
||||
JSON.stringify({
|
||||
buildPack: applicationFound.buildPack,
|
||||
port: applicationFound.port,
|
||||
exposePort: applicationFound.exposePort,
|
||||
installCommand: applicationFound.installCommand,
|
||||
buildCommand: applicationFound.buildCommand,
|
||||
startCommand: applicationFound.startCommand
|
||||
|
||||
@@ -3,8 +3,6 @@ import * as db from '$lib/database';
|
||||
import { ErrorHandler } from '$lib/database';
|
||||
import { checkContainer, isContainerExited } from '$lib/haproxy';
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
import jsonwebtoken from 'jsonwebtoken';
|
||||
import { get as getRequest } from '$lib/api';
|
||||
import { setDefaultConfiguration } from '$lib/buildPacks/common';
|
||||
|
||||
export const get: RequestHandler = async (event) => {
|
||||
@@ -52,6 +50,7 @@ export const post: RequestHandler = async (event) => {
|
||||
buildPack,
|
||||
fqdn,
|
||||
port,
|
||||
exposePort,
|
||||
installCommand,
|
||||
buildCommand,
|
||||
startCommand,
|
||||
@@ -67,6 +66,9 @@ export const post: RequestHandler = async (event) => {
|
||||
baseBuildImage
|
||||
} = await event.request.json();
|
||||
if (port) port = Number(port);
|
||||
if (exposePort) {
|
||||
exposePort = Number(exposePort);
|
||||
}
|
||||
if (denoOptions) denoOptions = denoOptions.trim();
|
||||
|
||||
try {
|
||||
@@ -87,6 +89,7 @@ export const post: RequestHandler = async (event) => {
|
||||
name,
|
||||
fqdn,
|
||||
port,
|
||||
exposePort,
|
||||
installCommand,
|
||||
buildCommand,
|
||||
startCommand,
|
||||
|
||||
@@ -45,9 +45,9 @@
|
||||
import Explainer from '$lib/components/Explainer.svelte';
|
||||
import Setting from '$lib/components/Setting.svelte';
|
||||
import type Prisma from '@prisma/client';
|
||||
import { notNodeDeployments, staticDeployments } from '$lib/components/common';
|
||||
import { getDomain, notNodeDeployments, staticDeployments } from '$lib/components/common';
|
||||
import { toast } from '@zerodevx/svelte-toast';
|
||||
import { post } from '$lib/api';
|
||||
import { get, post } from '$lib/api';
|
||||
import cuid from 'cuid';
|
||||
import { browser } from '$app/env';
|
||||
import { disabledButton } from '$lib/store';
|
||||
@@ -63,6 +63,10 @@
|
||||
let dualCerts = application.settings.dualCerts;
|
||||
let autodeploy = application.settings.autodeploy;
|
||||
|
||||
let nonWWWDomain = application.fqdn && getDomain(application.fqdn).replace(/^www\./, '');
|
||||
let isNonWWWDomainOK = false;
|
||||
let isWWWDomainOK = false;
|
||||
|
||||
let wsgis = [
|
||||
{
|
||||
value: 'None',
|
||||
@@ -127,13 +131,31 @@
|
||||
async function handleSubmit() {
|
||||
loading = true;
|
||||
try {
|
||||
await post(`/applications/${id}/check.json`, { fqdn: application.fqdn, forceSave });
|
||||
nonWWWDomain = application.fqdn && getDomain(application.fqdn).replace(/^www\./, '');
|
||||
await post(`/applications/${id}/check.json`, {
|
||||
fqdn: application.fqdn,
|
||||
forceSave,
|
||||
dualCerts,
|
||||
exposePort: application.exposePort
|
||||
});
|
||||
await post(`/applications/${id}.json`, { ...application });
|
||||
$disabledButton = false;
|
||||
forceSave = false;
|
||||
return toast.push('Configurations saved.');
|
||||
} catch ({ error }) {
|
||||
if (error?.startsWith($t('application.dns_not_set_partial_error'))) {
|
||||
forceSave = true;
|
||||
if (dualCerts) {
|
||||
isNonWWWDomainOK = await isDNSValid(getDomain(nonWWWDomain), false);
|
||||
isWWWDomainOK = await isDNSValid(getDomain(`www.${nonWWWDomain}`), true);
|
||||
} else {
|
||||
const isWWW = getDomain(application.fqdn).includes('www.');
|
||||
if (isWWW) {
|
||||
isWWWDomainOK = await isDNSValid(getDomain(`www.${nonWWWDomain}`), true);
|
||||
} else {
|
||||
isNonWWWDomainOK = await isDNSValid(getDomain(nonWWWDomain), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
return errorNotification(error);
|
||||
} finally {
|
||||
@@ -151,6 +173,19 @@
|
||||
application.baseBuildImage = event.detail.value;
|
||||
await handleSubmit();
|
||||
}
|
||||
|
||||
async function isDNSValid(domain, isWWW) {
|
||||
try {
|
||||
await get(`/applications/${id}/check.json?domain=${domain}`);
|
||||
toast.push('DNS configuration is valid.');
|
||||
isWWW ? (isWWWDomainOK = true) : (isNonWWWDomainOK = true);
|
||||
return true;
|
||||
} catch ({ error }) {
|
||||
errorNotification(error);
|
||||
isWWW ? (isWWWDomainOK = false) : (isNonWWWDomainOK = false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="flex items-center space-x-2 p-5 px-6 font-bold">
|
||||
@@ -323,24 +358,26 @@
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="baseImage" class="text-base font-bold text-stone-100"
|
||||
>{$t('application.base_image')}</label
|
||||
>
|
||||
<div class="custom-select-wrapper">
|
||||
<Select
|
||||
isDisabled={!$session.isAdmin || isRunning}
|
||||
containerClasses={containerClass()}
|
||||
id="baseImages"
|
||||
showIndicator={!isRunning}
|
||||
items={application.baseImages}
|
||||
on:select={selectBaseImage}
|
||||
value={application.baseImage}
|
||||
isClearable={false}
|
||||
/>
|
||||
{#if application.buildPack !== 'docker'}
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="baseImage" class="text-base font-bold text-stone-100"
|
||||
>{$t('application.base_image')}</label
|
||||
>
|
||||
<div class="custom-select-wrapper">
|
||||
<Select
|
||||
isDisabled={!$session.isAdmin || isRunning}
|
||||
containerClasses={containerClass()}
|
||||
id="baseImages"
|
||||
showIndicator={!isRunning}
|
||||
items={application.baseImages}
|
||||
on:select={selectBaseImage}
|
||||
value={application.baseImage}
|
||||
isClearable={false}
|
||||
/>
|
||||
</div>
|
||||
<Explainer text={$t('application.base_image_explainer')} />
|
||||
</div>
|
||||
<Explainer text={$t('application.base_image_explainer')} />
|
||||
</div>
|
||||
{/if}
|
||||
{#if application.buildCommand || application.buildPack === 'rust' || application.buildPack === 'laravel'}
|
||||
<div class="grid grid-cols-2 items-center pb-8">
|
||||
<label for="baseBuildImage" class="text-base font-bold text-stone-100"
|
||||
@@ -383,17 +420,52 @@
|
||||
{/if}
|
||||
<Explainer text={$t('application.https_explainer')} />
|
||||
</div>
|
||||
<input
|
||||
readonly={!$session.isAdmin || isRunning}
|
||||
disabled={!$session.isAdmin || isRunning}
|
||||
bind:this={domainEl}
|
||||
name="fqdn"
|
||||
id="fqdn"
|
||||
bind:value={application.fqdn}
|
||||
pattern="^https?://([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{'{'}2,{'}'}$"
|
||||
placeholder="eg: https://coollabs.io"
|
||||
required
|
||||
/>
|
||||
<div>
|
||||
<input
|
||||
readonly={!$session.isAdmin || isRunning}
|
||||
disabled={!$session.isAdmin || isRunning}
|
||||
bind:this={domainEl}
|
||||
name="fqdn"
|
||||
id="fqdn"
|
||||
bind:value={application.fqdn}
|
||||
pattern="^https?://([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{'{'}2,{'}'}$"
|
||||
placeholder="eg: https://coollabs.io"
|
||||
/>
|
||||
{#if forceSave}
|
||||
<div class="flex-col space-y-2 pt-4 text-center">
|
||||
{#if isNonWWWDomainOK}
|
||||
<button
|
||||
class="bg-green-600 hover:bg-green-500"
|
||||
on:click|preventDefault={() => isDNSValid(getDomain(nonWWWDomain), false)}
|
||||
>DNS settings for {nonWWWDomain} is OK, click to recheck.</button
|
||||
>
|
||||
{:else}
|
||||
<button
|
||||
class="bg-red-600 hover:bg-red-500"
|
||||
on:click|preventDefault={() => isDNSValid(getDomain(nonWWWDomain), false)}
|
||||
>DNS settings for {nonWWWDomain} is invalid, click to recheck.</button
|
||||
>
|
||||
{/if}
|
||||
{#if dualCerts}
|
||||
{#if isWWWDomainOK}
|
||||
<button
|
||||
class="bg-green-600 hover:bg-green-500"
|
||||
on:click|preventDefault={() =>
|
||||
isDNSValid(getDomain(`www.${nonWWWDomain}`), true)}
|
||||
>DNS settings for www.{nonWWWDomain} is OK, click to recheck.</button
|
||||
>
|
||||
{:else}
|
||||
<button
|
||||
class="bg-red-600 hover:bg-red-500"
|
||||
on:click|preventDefault={() =>
|
||||
isDNSValid(getDomain(`www.${nonWWWDomain}`), true)}
|
||||
>DNS settings for www.{nonWWWDomain} is invalid, click to recheck.</button
|
||||
>
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center pb-8">
|
||||
<Setting
|
||||
@@ -451,9 +523,24 @@
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if !notNodeDeployments.includes(application.buildPack)}
|
||||
{#if application.buildPack !== 'docker'}
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="exposePort" class="text-base font-bold text-stone-100">Exposed Port</label>
|
||||
<input
|
||||
readonly={!$session.isAdmin && !isRunning}
|
||||
disabled={!$session.isAdmin || isRunning}
|
||||
name="exposePort"
|
||||
id="exposePort"
|
||||
bind:value={application.exposePort}
|
||||
placeholder="12345"
|
||||
/>
|
||||
<Explainer
|
||||
text={'You can expose your application to a port on the host system.<br><br>Useful if you would like to use your own reverse proxy or tunnel and also in development mode. Otherwise leave empty.'}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
{#if !notNodeDeployments.includes(application.buildPack)}
|
||||
<div class="grid grid-cols-2 items-center pt-4">
|
||||
<label for="installCommand" class="text-base font-bold text-stone-100"
|
||||
>{$t('application.install_command')}</label
|
||||
>
|
||||
@@ -491,7 +578,7 @@
|
||||
</div>
|
||||
{/if}
|
||||
{#if application.buildPack === 'docker'}
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<div class="grid grid-cols-2 items-center pt-4">
|
||||
<label for="dockerFileLocation" class="text-base font-bold text-stone-100"
|
||||
>Dockerfile Location</label
|
||||
>
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
<div class="lds-ripple absolute left-0">
|
||||
<script>
|
||||
export let position = 'absolute';
|
||||
</script>
|
||||
|
||||
<div class="lds-ripple {position} left-0">
|
||||
<div />
|
||||
<div />
|
||||
</div>
|
||||
|
||||
@@ -129,23 +129,28 @@
|
||||
{#if currentStatus === 'running'}
|
||||
<button
|
||||
on:click={cancelBuild}
|
||||
class:animation-spin={cancelInprogress}
|
||||
class="bg-transparent hover:text-red-500 hover:bg-coolgray-500"
|
||||
data-tooltip="Cancel build"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="w-6 h-6"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<circle cx="12" cy="12" r="9" />
|
||||
<path d="M10 10l4 4m0 -4l-4 4" />
|
||||
</svg>
|
||||
{#if cancelInprogress}
|
||||
Cancelling...
|
||||
{:else}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="w-6 h-6"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<circle cx="12" cy="12" r="9" />
|
||||
<path d="M10 10l4 4m0 -4l-4 4" />
|
||||
</svg>
|
||||
{/if}
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="flex flex-col flex-wrap justify-center">
|
||||
<div class="flex justify-center">
|
||||
{#if !applications || ownApplications.length === 0}
|
||||
<div class="flex-col">
|
||||
<div class="text-center text-xl font-bold">{$t('application.no_applications_found')}</div>
|
||||
|
||||
@@ -2,45 +2,67 @@ import { getUserDetails } from '$lib/common';
|
||||
import * as db from '$lib/database';
|
||||
import { ErrorHandler } from '$lib/database';
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
import os from 'node:os';
|
||||
import osu from 'node-os-utils';
|
||||
|
||||
export const get: RequestHandler = async (event) => {
|
||||
const { userId, teamId, status, body } = await getUserDetails(event);
|
||||
if (status === 401) return { status, body };
|
||||
|
||||
try {
|
||||
const applicationsCount = await db.prisma.application.count({
|
||||
where: { teams: { some: { id: teamId === '0' ? undefined : teamId } } }
|
||||
});
|
||||
const sourcesCount = await db.prisma.gitSource.count({
|
||||
where: { teams: { some: { id: teamId === '0' ? undefined : teamId } } }
|
||||
});
|
||||
const destinationsCount = await db.prisma.destinationDocker.count({
|
||||
where: { teams: { some: { id: teamId === '0' ? undefined : teamId } } }
|
||||
});
|
||||
const teamsCount = await db.prisma.permission.count({ where: { userId } });
|
||||
const databasesCount = await db.prisma.database.count({
|
||||
where: { teams: { some: { id: teamId === '0' ? undefined : teamId } } }
|
||||
});
|
||||
const servicesCount = await db.prisma.service.count({
|
||||
where: { teams: { some: { id: teamId === '0' ? undefined : teamId } } }
|
||||
});
|
||||
const teams = await db.prisma.permission.findMany({
|
||||
where: { userId },
|
||||
include: { team: { include: { _count: { select: { users: true } } } } }
|
||||
});
|
||||
return {
|
||||
body: {
|
||||
teams,
|
||||
applicationsCount,
|
||||
sourcesCount,
|
||||
destinationsCount,
|
||||
teamsCount,
|
||||
databasesCount,
|
||||
servicesCount
|
||||
}
|
||||
};
|
||||
} catch (error) {
|
||||
return ErrorHandler(error);
|
||||
const usage = event.url.searchParams.get('usage');
|
||||
if (usage) {
|
||||
try {
|
||||
return {
|
||||
status: 200,
|
||||
body: {
|
||||
uptime: os.uptime(),
|
||||
memory: await osu.mem.info(),
|
||||
cpu: {
|
||||
load: os.loadavg(),
|
||||
usage: await osu.cpu.usage(),
|
||||
count: os.cpus().length
|
||||
},
|
||||
disk: await osu.drive.info()
|
||||
}
|
||||
};
|
||||
} catch (error) {
|
||||
return ErrorHandler(error);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
const applicationsCount = await db.prisma.application.count({
|
||||
where: { teams: { some: { id: teamId === '0' ? undefined : teamId } } }
|
||||
});
|
||||
const sourcesCount = await db.prisma.gitSource.count({
|
||||
where: { teams: { some: { id: teamId === '0' ? undefined : teamId } } }
|
||||
});
|
||||
const destinationsCount = await db.prisma.destinationDocker.count({
|
||||
where: { teams: { some: { id: teamId === '0' ? undefined : teamId } } }
|
||||
});
|
||||
const teamsCount = await db.prisma.permission.count({ where: { userId } });
|
||||
const databasesCount = await db.prisma.database.count({
|
||||
where: { teams: { some: { id: teamId === '0' ? undefined : teamId } } }
|
||||
});
|
||||
const servicesCount = await db.prisma.service.count({
|
||||
where: { teams: { some: { id: teamId === '0' ? undefined : teamId } } }
|
||||
});
|
||||
const teams = await db.prisma.permission.findMany({
|
||||
where: { userId },
|
||||
include: { team: { include: { _count: { select: { users: true } } } } }
|
||||
});
|
||||
return {
|
||||
body: {
|
||||
teams,
|
||||
applicationsCount,
|
||||
sourcesCount,
|
||||
destinationsCount,
|
||||
teamsCount,
|
||||
databasesCount,
|
||||
servicesCount
|
||||
}
|
||||
};
|
||||
} catch (error) {
|
||||
return ErrorHandler(error);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
import MySql from './_MySQL.svelte';
|
||||
import MongoDb from './_MongoDB.svelte';
|
||||
import MariaDb from './_MariaDB.svelte';
|
||||
import PostgreSql from './_PostgreSQL.svelte';
|
||||
import Redis from './_Redis.svelte';
|
||||
import CouchDb from './_CouchDb.svelte';
|
||||
@@ -190,6 +191,8 @@
|
||||
<PostgreSql bind:database {isRunning} />
|
||||
{:else if database.type === 'mongodb'}
|
||||
<MongoDb bind:database {isRunning} />
|
||||
{:else if database.type === 'mariadb'}
|
||||
<MariaDb bind:database {isRunning} />
|
||||
{:else if database.type === 'redis'}
|
||||
<Redis bind:database {isRunning} />
|
||||
{:else if database.type === 'couchdb'}
|
||||
|
||||
79
src/routes/databases/[id]/_Databases/_MariaDB.svelte
Normal file
79
src/routes/databases/[id]/_Databases/_MariaDB.svelte
Normal file
@@ -0,0 +1,79 @@
|
||||
<script>
|
||||
export let database;
|
||||
export let isRunning;
|
||||
import CopyPasswordField from '$lib/components/CopyPasswordField.svelte';
|
||||
import Explainer from '$lib/components/Explainer.svelte';
|
||||
import { t } from '$lib/translations';
|
||||
</script>
|
||||
|
||||
<div class="flex space-x-1 py-5 font-bold">
|
||||
<div class="title">MariaDB</div>
|
||||
</div>
|
||||
<div class="space-y-2 px-10">
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="defaultDatabase" class="text-base font-bold text-stone-100"
|
||||
>{$t('database.default_database')}</label
|
||||
>
|
||||
<CopyPasswordField
|
||||
required
|
||||
readonly={database.defaultDatabase}
|
||||
disabled={database.defaultDatabase}
|
||||
placeholder="{$t('forms.eg')}: mydb"
|
||||
id="defaultDatabase"
|
||||
name="defaultDatabase"
|
||||
bind:value={database.defaultDatabase}
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="dbUser" class="text-base font-bold text-stone-100">{$t('forms.user')}</label>
|
||||
<CopyPasswordField
|
||||
readonly
|
||||
disabled
|
||||
placeholder={$t('forms.generated_automatically_after_start')}
|
||||
id="dbUser"
|
||||
name="dbUser"
|
||||
value={database.dbUser}
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="dbUserPassword" class="text-base font-bold text-stone-100"
|
||||
>{$t('forms.password')}</label
|
||||
>
|
||||
<CopyPasswordField
|
||||
disabled={!isRunning}
|
||||
readonly={!isRunning}
|
||||
placeholder={$t('forms.generated_automatically_after_start')}
|
||||
isPasswordField
|
||||
id="dbUserPassword"
|
||||
name="dbUserPassword"
|
||||
bind:value={database.dbUserPassword}
|
||||
/>
|
||||
<Explainer text="Could be changed while the database is running." />
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="rootUser" class="text-base font-bold text-stone-100">{$t('forms.root_user')}</label>
|
||||
<CopyPasswordField
|
||||
readonly
|
||||
disabled
|
||||
placeholder={$t('forms.generated_automatically_after_start')}
|
||||
id="rootUser"
|
||||
name="rootUser"
|
||||
value={database.rootUser}
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="rootUserPassword" class="text-base font-bold text-stone-100"
|
||||
>{$t('forms.roots_password')}</label
|
||||
>
|
||||
<CopyPasswordField
|
||||
disabled={!isRunning}
|
||||
readonly={!isRunning}
|
||||
placeholder={$t('forms.generated_automatically_after_start')}
|
||||
isPasswordField
|
||||
id="rootUserPassword"
|
||||
name="rootUserPassword"
|
||||
bind:value={database.rootUserPassword}
|
||||
/>
|
||||
<Explainer text="Could be changed while the database is running." />
|
||||
</div>
|
||||
</div>
|
||||
@@ -37,6 +37,7 @@
|
||||
import Clickhouse from '$lib/components/svg/databases/Clickhouse.svelte';
|
||||
import CouchDB from '$lib/components/svg/databases/CouchDB.svelte';
|
||||
import MongoDB from '$lib/components/svg/databases/MongoDB.svelte';
|
||||
import MariaDB from '$lib/components/svg/databases/MariaDB.svelte';
|
||||
import MySQL from '$lib/components/svg/databases/MySQL.svelte';
|
||||
import PostgreSQL from '$lib/components/svg/databases/PostgreSQL.svelte';
|
||||
import Redis from '$lib/components/svg/databases/Redis.svelte';
|
||||
@@ -68,6 +69,8 @@
|
||||
<CouchDB isAbsolute />
|
||||
{:else if type.name === 'mongodb'}
|
||||
<MongoDB isAbsolute />
|
||||
{:else if type.name === 'mariadb'}
|
||||
<MariaDB isAbsolute />
|
||||
{:else if type.name === 'mysql'}
|
||||
<MySQL isAbsolute />
|
||||
{:else if type.name === 'postgresql'}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import Clickhouse from '$lib/components/svg/databases/Clickhouse.svelte';
|
||||
import CouchDB from '$lib/components/svg/databases/CouchDB.svelte';
|
||||
import MongoDB from '$lib/components/svg/databases/MongoDB.svelte';
|
||||
import MariaDB from '$lib/components/svg/databases/MariaDB.svelte';
|
||||
import MySQL from '$lib/components/svg/databases/MySQL.svelte';
|
||||
import PostgreSQL from '$lib/components/svg/databases/PostgreSQL.svelte';
|
||||
import Redis from '$lib/components/svg/databases/Redis.svelte';
|
||||
@@ -46,7 +47,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col flex-wrap justify-center">
|
||||
<div class="flex justify-center">
|
||||
{#if !databases || ownDatabases.length === 0}
|
||||
<div class="flex-col">
|
||||
<div class="text-center text-xl font-bold">{$t('database.no_databases_found')}</div>
|
||||
@@ -66,6 +67,8 @@
|
||||
<MongoDB isAbsolute />
|
||||
{:else if database.type === 'mysql'}
|
||||
<MySQL isAbsolute />
|
||||
{:else if database.type === 'mariadb'}
|
||||
<MariaDB isAbsolute />
|
||||
{:else if database.type === 'postgresql'}
|
||||
<PostgreSQL isAbsolute />
|
||||
{:else if database.type === 'redis'}
|
||||
@@ -98,6 +101,8 @@
|
||||
<CouchDB isAbsolute />
|
||||
{:else if database.type === 'mongodb'}
|
||||
<MongoDB isAbsolute />
|
||||
{:else if database.type === 'mariadb'}
|
||||
<MariaDB isAbsolute />
|
||||
{:else if database.type === 'mysql'}
|
||||
<MySQL isAbsolute />
|
||||
{:else if database.type === 'postgresql'}
|
||||
|
||||
@@ -39,10 +39,13 @@
|
||||
import { t } from '$lib/translations';
|
||||
</script>
|
||||
|
||||
<div class="flex space-x-1 p-6 text-2xl font-bold">
|
||||
<div class="tracking-tight">{$t('application.destination')}</div>
|
||||
<span class="arrow-right-applications px-1">></span>
|
||||
<span class="pr-2">{destination.name}</span>
|
||||
<div class="flex h-20 items-center space-x-2 p-5 px-6 font-bold">
|
||||
<div class="-mb-5 flex-col">
|
||||
<div class="md:max-w-64 truncate text-base tracking-tight md:text-2xl lg:block">
|
||||
Configuration
|
||||
</div>
|
||||
<span class="text-xs">{destination.name}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mx-auto max-w-4xl px-6">
|
||||
|
||||
@@ -21,6 +21,11 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { t } from '$lib/translations';
|
||||
import { get } from '$lib/api';
|
||||
import { onDestroy, onMount } from 'svelte';
|
||||
import Loading from './applications/[id]/logs/_Loading.svelte';
|
||||
import Trend from './_Trend.svelte';
|
||||
import { session } from '$app/stores';
|
||||
|
||||
export let applicationsCount: number;
|
||||
export let sourcesCount: number;
|
||||
@@ -28,89 +33,261 @@
|
||||
export let teamsCount: number;
|
||||
export let databasesCount: number;
|
||||
export let servicesCount: number;
|
||||
let loading = {
|
||||
usage: false
|
||||
};
|
||||
let usageInterval = null;
|
||||
let memoryWarning = false;
|
||||
let cpuWarning = false;
|
||||
let diskWarning = false;
|
||||
|
||||
let trends = {
|
||||
memory: 'stable',
|
||||
cpu: 'stable',
|
||||
disk: 'stable'
|
||||
};
|
||||
let usage = {
|
||||
cpu: {
|
||||
load: [0, 0, 0],
|
||||
count: 0,
|
||||
usage: 0
|
||||
},
|
||||
memory: {
|
||||
totalMemMb: 0,
|
||||
freeMemMb: 0,
|
||||
usedMemMb: 0,
|
||||
freeMemPercentage: 0
|
||||
},
|
||||
disk: {
|
||||
freePercentage: 0,
|
||||
totalGb: 0,
|
||||
usedGb: 0
|
||||
}
|
||||
};
|
||||
async function getStatus() {
|
||||
if (loading.usage) return;
|
||||
try {
|
||||
loading.usage = true;
|
||||
const data = await get(`/dashboard.json?usage=true`);
|
||||
if (data.memory.freeMemPercentage === usage.memory.freeMemPercentage) {
|
||||
trends.memory = 'stable';
|
||||
} else {
|
||||
if (data.memory.freeMemPercentage > usage.memory.freeMemPercentage) {
|
||||
trends.memory = 'up';
|
||||
} else {
|
||||
trends.memory = 'down';
|
||||
}
|
||||
}
|
||||
if (data.cpu.usage === usage.cpu.usage) {
|
||||
trends.cpu = 'stable';
|
||||
} else {
|
||||
if (data.cpu.usage > usage.cpu.usage) {
|
||||
trends.cpu = 'up';
|
||||
} else {
|
||||
trends.cpu = 'down';
|
||||
}
|
||||
}
|
||||
|
||||
if (data.disk.freePercentage === usage.disk.freePercentage) {
|
||||
trends.disk = 'stable';
|
||||
} else {
|
||||
if (data.disk.freePercentage > usage.disk.freePercentage) {
|
||||
trends.disk = 'up';
|
||||
} else {
|
||||
trends.disk = 'down';
|
||||
}
|
||||
}
|
||||
|
||||
usage = data;
|
||||
if (usage.memory.freeMemPercentage < 15) {
|
||||
memoryWarning = true;
|
||||
} else {
|
||||
memoryWarning = false;
|
||||
}
|
||||
if (usage.cpu.usage > 90) {
|
||||
cpuWarning = true;
|
||||
} else {
|
||||
cpuWarning = false;
|
||||
}
|
||||
if (usage.disk.freePercentage < 10) {
|
||||
diskWarning = true;
|
||||
} else {
|
||||
diskWarning = false;
|
||||
}
|
||||
} catch (error) {
|
||||
} finally {
|
||||
loading.usage = false;
|
||||
}
|
||||
}
|
||||
onDestroy(() => {
|
||||
clearInterval(usageInterval);
|
||||
});
|
||||
onMount(async () => {
|
||||
if ($session.teamId === '0') {
|
||||
await getStatus();
|
||||
usageInterval = setInterval(async () => {
|
||||
await getStatus();
|
||||
}, 1000);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="flex space-x-1 p-6 font-bold">
|
||||
<div class="mr-4 text-2xl tracking-tight">{$t('index.dashboard')}</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-10 pb-12 tracking-tight sm:pb-16">
|
||||
<div class="relative">
|
||||
<div class="absolute inset-0 h-1/2" />
|
||||
<div class="relative mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="mx-auto max-w-4xl">
|
||||
<dl class="gap-5 gap-y-16 sm:grid sm:grid-cols-3">
|
||||
<a
|
||||
href="/applications"
|
||||
sveltekit:prefetch
|
||||
class="flex cursor-pointer flex-col rounded p-6 text-center text-green-500 no-underline transition duration-150 hover:bg-green-500 hover:text-white"
|
||||
>
|
||||
<dt class="order-2 mt-2 text-sm font-bold uppercase leading-6 text-white">
|
||||
{$t('index.applications')}
|
||||
</dt>
|
||||
<dd class="order-1 text-5xl font-extrabold ">
|
||||
{applicationsCount}
|
||||
</dd>
|
||||
</a>
|
||||
<a
|
||||
href="/destinations"
|
||||
sveltekit:prefetch
|
||||
class="flex cursor-pointer flex-col rounded p-6 text-center text-sky-500 no-underline transition duration-150 hover:bg-sky-500 hover:text-white"
|
||||
>
|
||||
<dt class="order-2 mt-2 text-sm font-bold uppercase leading-6 text-white">
|
||||
{$t('index.destinations')}
|
||||
</dt>
|
||||
<dd class="order-1 text-5xl font-extrabold ">
|
||||
{destinationsCount}
|
||||
</dd>
|
||||
</a>
|
||||
<a
|
||||
href="/sources"
|
||||
sveltekit:prefetch
|
||||
class="flex cursor-pointer flex-col rounded p-6 text-center text-orange-500 no-underline transition duration-150 hover:bg-orange-500 hover:text-white"
|
||||
>
|
||||
<dt class="order-2 mt-2 text-sm font-bold uppercase leading-6 text-white">
|
||||
{$t('index.git_sources')}
|
||||
</dt>
|
||||
<dd class="order-1 text-5xl font-extrabold ">
|
||||
{sourcesCount}
|
||||
</dd>
|
||||
</a>
|
||||
<a
|
||||
href="/databases"
|
||||
sveltekit:prefetch
|
||||
class="flex cursor-pointer flex-col rounded p-6 text-center text-purple-500 no-underline transition duration-150 hover:bg-purple-500 hover:text-white"
|
||||
>
|
||||
<dt class="order-2 mt-2 text-sm font-bold uppercase leading-6 text-white">
|
||||
{$t('index.databases')}
|
||||
</dt>
|
||||
<dd class="order-1 text-5xl font-extrabold ">{databasesCount}</dd>
|
||||
</a>
|
||||
<a
|
||||
href="/services"
|
||||
sveltekit:prefetch
|
||||
class="flex cursor-pointer flex-col rounded p-6 text-center text-pink-500 no-underline transition duration-150 hover:bg-pink-500 hover:text-white"
|
||||
>
|
||||
<dt class="order-2 mt-2 text-sm font-bold uppercase leading-6 text-white">
|
||||
{$t('index.services')}
|
||||
</dt>
|
||||
<dd class="order-1 text-5xl font-extrabold ">{servicesCount}</dd>
|
||||
</a>
|
||||
<div class="mx-auto max-w-4xl">
|
||||
{#if $session.teamId === '0'}
|
||||
<div class="px-6 text-2xl font-bold">Server Usage</div>
|
||||
<dl class="relative mt-5 grid grid-cols-1 gap-5 sm:grid-cols-3">
|
||||
<Loading />
|
||||
<div class="overflow-hidden rounded px-4 py-5 text-center sm:p-6 sm:text-left">
|
||||
<dt class="truncate text-sm font-medium text-white">Total Memory</dt>
|
||||
<dd class="mt-1 text-3xl font-semibold text-white">
|
||||
{(usage?.memory.totalMemMb).toFixed(0)}<span class="text-sm">MB</span>
|
||||
</dd>
|
||||
</div>
|
||||
|
||||
<a
|
||||
href="/iam"
|
||||
sveltekit:prefetch
|
||||
class="flex cursor-pointer flex-col rounded p-6 text-center text-cyan-500 no-underline transition duration-150 hover:bg-cyan-500 hover:text-white"
|
||||
>
|
||||
<dt class="order-2 mt-2 text-sm font-bold uppercase leading-6 text-white">
|
||||
{$t('index.teams')}
|
||||
</dt>
|
||||
<dd class="order-1 text-5xl font-extrabold ">
|
||||
{teamsCount}
|
||||
</dd>
|
||||
</a>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
<div class="overflow-hidden rounded px-4 py-5 text-center sm:p-6 sm:text-left">
|
||||
<dt class="truncate text-sm font-medium text-white">Used Memory</dt>
|
||||
<dd class="mt-1 text-3xl font-semibold text-white ">
|
||||
{(usage?.memory.usedMemMb).toFixed(0)}<span class="text-sm">MB</span>
|
||||
</dd>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="overflow-hidden rounded px-4 py-5 text-center sm:p-6 sm:text-left"
|
||||
class:bg-red-500={memoryWarning}
|
||||
>
|
||||
<dt class="truncate text-sm font-medium text-white">Free Memory</dt>
|
||||
<dd class="mt-1 text-3xl font-semibold text-white">
|
||||
{usage?.memory.freeMemPercentage}<span class="text-sm">%</span>
|
||||
{#if !memoryWarning}
|
||||
<Trend trend={trends.memory} />
|
||||
{/if}
|
||||
</dd>
|
||||
</div>
|
||||
</dl>
|
||||
<dl class="relative mt-5 grid grid-cols-1 gap-5 sm:grid-cols-3">
|
||||
<div class="overflow-hidden rounded px-4 py-5 text-center sm:p-6 sm:text-left">
|
||||
<dt class="truncate text-sm font-medium text-white">Total CPUs</dt>
|
||||
<dd class="mt-1 text-3xl font-semibold text-white">
|
||||
{usage?.cpu.count}
|
||||
</dd>
|
||||
</div>
|
||||
<div class="overflow-hidden rounded px-4 py-5 text-center sm:p-6 sm:text-left">
|
||||
<dt class="truncate text-sm font-medium text-white">Load Average (5/10/30mins)</dt>
|
||||
<dd class="mt-1 text-3xl font-semibold text-white">
|
||||
{usage?.cpu.load.join('/')}
|
||||
</dd>
|
||||
</div>
|
||||
<div
|
||||
class="overflow-hidden rounded px-4 py-5 text-center sm:p-6 sm:text-left"
|
||||
class:bg-red-500={cpuWarning}
|
||||
>
|
||||
<dt class="truncate text-sm font-medium text-white">CPU Usage</dt>
|
||||
<dd class="mt-1 text-3xl font-semibold text-white">
|
||||
{usage?.cpu.usage}<span class="text-sm">%</span>
|
||||
{#if !cpuWarning}
|
||||
<Trend trend={trends.cpu} />
|
||||
{/if}
|
||||
</dd>
|
||||
</div>
|
||||
</dl>
|
||||
<dl class="relative mt-5 grid grid-cols-1 gap-5 sm:grid-cols-3">
|
||||
<div class="overflow-hidden rounded px-4 py-5 text-center sm:p-6 sm:text-left">
|
||||
<dt class="truncate text-sm font-medium text-white">Total Disk</dt>
|
||||
<dd class="mt-1 text-3xl font-semibold text-white">
|
||||
{usage?.disk.totalGb}<span class="text-sm">GB</span>
|
||||
</dd>
|
||||
</div>
|
||||
<div class="overflow-hidden rounded px-4 py-5 text-center sm:p-6 sm:text-left">
|
||||
<dt class="truncate text-sm font-medium text-white">Used Disk</dt>
|
||||
<dd class="mt-1 text-3xl font-semibold text-white">
|
||||
{usage?.disk.usedGb}<span class="text-sm">GB</span>
|
||||
</dd>
|
||||
</div>
|
||||
<div
|
||||
class="overflow-hidden rounded px-4 py-5 text-center sm:p-6 sm:text-left"
|
||||
class:bg-red-500={diskWarning}
|
||||
>
|
||||
<dt class="truncate text-sm font-medium text-white">Free Disk</dt>
|
||||
<dd class="mt-1 text-3xl font-semibold text-white">
|
||||
{usage?.disk.freePercentage}<span class="text-sm">%</span>
|
||||
{#if !diskWarning}
|
||||
<Trend trend={trends.disk} />
|
||||
{/if}
|
||||
</dd>
|
||||
</div>
|
||||
</dl>
|
||||
<div class="px-6 pt-20 text-2xl font-bold">Resources</div>
|
||||
{/if}
|
||||
<dl class="mt-5 grid grid-cols-1 gap-5 px-2 sm:grid-cols-3">
|
||||
<a
|
||||
href="/applications"
|
||||
sveltekit:prefetch
|
||||
class="overflow-hidden rounded px-4 py-5 text-center text-green-500 no-underline transition-all duration-100 hover:bg-green-500 hover:text-white sm:p-6 sm:text-left"
|
||||
>
|
||||
<dt class="truncate text-sm font-medium text-white">{$t('index.applications')}</dt>
|
||||
<dd class="mt-1 text-3xl font-semibold ">
|
||||
{applicationsCount}
|
||||
</dd>
|
||||
</a>
|
||||
<a
|
||||
href="/destinations"
|
||||
sveltekit:prefetch
|
||||
class="overflow-hidden rounded px-4 py-5 text-center text-sky-500 no-underline transition-all duration-100 hover:bg-sky-500 hover:text-white sm:p-6 sm:text-left"
|
||||
>
|
||||
<dt class="truncate text-sm font-medium text-white">{$t('index.destinations')}</dt>
|
||||
<dd class="mt-1 text-3xl font-semibold ">
|
||||
{destinationsCount}
|
||||
</dd>
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="/sources"
|
||||
sveltekit:prefetch
|
||||
class="overflow-hidden rounded px-4 py-5 text-center text-orange-500 no-underline transition-all duration-100 hover:bg-orange-500 hover:text-white sm:p-6 sm:text-left"
|
||||
>
|
||||
<dt class="truncate text-sm font-medium text-white">{$t('index.git_sources')}</dt>
|
||||
<dd class="mt-1 text-3xl font-semibold">
|
||||
{sourcesCount}
|
||||
</dd>
|
||||
</a>
|
||||
</dl>
|
||||
<dl class="mt-5 grid grid-cols-1 gap-5 sm:grid-cols-3">
|
||||
<a
|
||||
href="/databases"
|
||||
sveltekit:prefetch
|
||||
class="overflow-hidden rounded px-4 py-5 text-center text-purple-500 no-underline transition-all duration-100 hover:bg-purple-500 hover:text-white sm:p-6 sm:text-left"
|
||||
>
|
||||
<dt class="truncate text-sm font-medium text-white">{$t('index.databases')}</dt>
|
||||
<dd class="mt-1 text-3xl font-semibold ">
|
||||
{databasesCount}
|
||||
</dd>
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="/services"
|
||||
sveltekit:prefetch
|
||||
class="overflow-hidden rounded px-4 py-5 text-center text-pink-500 no-underline transition-all duration-100 hover:bg-pink-500 hover:text-white sm:p-6 sm:text-left"
|
||||
>
|
||||
<dt class="truncate text-sm font-medium text-white">{$t('index.services')}</dt>
|
||||
<dd class="mt-1 text-3xl font-semibold ">
|
||||
{servicesCount}
|
||||
</dd>
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="/iam"
|
||||
sveltekit:prefetch
|
||||
class="overflow-hidden rounded px-4 py-5 text-center text-cyan-500 no-underline transition-all duration-100 hover:bg-cyan-500 hover:text-white sm:p-6 sm:text-left"
|
||||
>
|
||||
<dt class="truncate text-sm font-medium text-white">{$t('index.teams')}</dt>
|
||||
<dd class="mt-1 text-3xl font-semibold ">
|
||||
{teamsCount}
|
||||
</dd>
|
||||
</a>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,13 +1,32 @@
|
||||
<script lang="ts">
|
||||
import { session } from '$app/stores';
|
||||
|
||||
import CopyPasswordField from '$lib/components/CopyPasswordField.svelte';
|
||||
import Explainer from '$lib/components/Explainer.svelte';
|
||||
import { t } from '$lib/translations';
|
||||
export let service;
|
||||
export let readOnly;
|
||||
export let isRunning;
|
||||
</script>
|
||||
|
||||
<div class="flex space-x-1 py-5 font-bold">
|
||||
<div class="title">Plausible Analytics</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="scriptName">Script Name</label>
|
||||
<input
|
||||
name="scriptName"
|
||||
id="scriptName"
|
||||
readonly={!$session.isAdmin && !isRunning}
|
||||
disabled={!$session.isAdmin || isRunning}
|
||||
placeholder="plausible.js"
|
||||
bind:value={service.plausibleAnalytics.scriptName}
|
||||
required
|
||||
/>
|
||||
<Explainer
|
||||
text="Useful if you would like to rename the collector script to prevent it blocked by AdBlockers."
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="email">{$t('forms.email')}</label>
|
||||
<input
|
||||
@@ -77,16 +96,3 @@
|
||||
disabled
|
||||
/>
|
||||
</div>
|
||||
<!-- <div class="grid grid-cols-3 items-center">
|
||||
<label for="postgresqlPublicPort">Public Port</label>
|
||||
<div class="col-span-2 ">
|
||||
<CopyPasswordField
|
||||
placeholder="{ $t('forms.generated_automatically_after_start') }"
|
||||
readonly
|
||||
disabled
|
||||
id="postgresqlPublicPort"
|
||||
name="postgresqlPublicPort"
|
||||
value={service.plausibleAnalytics.postgresqlPublicPort}
|
||||
/>
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
@@ -160,8 +160,23 @@
|
||||
on:click={() => !isRunning && changeSettings('dualCerts')}
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="exposePort" class="text-base font-bold text-stone-100">Exposed Port</label>
|
||||
<input
|
||||
readonly={!$session.isAdmin && !isRunning}
|
||||
disabled={!$session.isAdmin || isRunning}
|
||||
name="exposePort"
|
||||
id="exposePort"
|
||||
bind:value={service.exposePort}
|
||||
placeholder="12345"
|
||||
/>
|
||||
<Explainer
|
||||
text={'You can expose your application to a port on the host system.<br><br>Useful if you would like to use your own reverse proxy or tunnel and also in development mode. Otherwise leave empty.'}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{#if service.type === 'plausibleanalytics'}
|
||||
<PlausibleAnalytics bind:service {readOnly} />
|
||||
<PlausibleAnalytics bind:service {isRunning} {readOnly} />
|
||||
{:else if service.type === 'minio'}
|
||||
<MinIo {service} />
|
||||
{:else if service.type === 'vscodeserver'}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
let ftpUser = service.wordpress.ftpUser;
|
||||
let ftpPassword = service.wordpress.ftpPassword;
|
||||
let ftpLoading = false;
|
||||
let ownMysql = service.wordpress.ownMysql;
|
||||
|
||||
function generateUrl(publicPort) {
|
||||
return browser
|
||||
@@ -40,7 +41,7 @@
|
||||
publicPort,
|
||||
ftpUser: user,
|
||||
ftpPassword: password
|
||||
} = await post(`/services/${id}/wordpress/settings.json`, {
|
||||
} = await post(`/services/${id}/wordpress/ftp.json`, {
|
||||
ftpEnabled
|
||||
});
|
||||
ftpUrl = generateUrl(publicPort);
|
||||
@@ -52,6 +53,18 @@
|
||||
} finally {
|
||||
ftpLoading = false;
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
if (name === 'ownMysql') {
|
||||
ownMysql = !ownMysql;
|
||||
}
|
||||
await post(`/services/${id}/wordpress/settings.json`, {
|
||||
ownMysql
|
||||
});
|
||||
service.wordpress.ownMysql = ownMysql;
|
||||
} catch ({ error }) {
|
||||
return errorNotification(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -106,51 +119,95 @@ define('SUBDOMAIN_INSTALL', false);`
|
||||
<div class="flex space-x-1 py-5 font-bold">
|
||||
<div class="title">MySQL</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<Setting
|
||||
dataTooltip={$t('forms.must_be_stopped_to_modify')}
|
||||
bind:setting={service.wordpress.ownMysql}
|
||||
disabled={isRunning}
|
||||
on:click={() => !isRunning && changeSettings('ownMysql')}
|
||||
title="Use your own MySQL server"
|
||||
description="Enables the use of your own MySQL server. If you don't have one, you can use the one provided by Coolify."
|
||||
/>
|
||||
</div>
|
||||
{#if service.wordpress.ownMysql}
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="mysqlHost">Host</label>
|
||||
<input
|
||||
name="mysqlHost"
|
||||
id="mysqlHost"
|
||||
required
|
||||
readonly={isRunning}
|
||||
disabled={isRunning}
|
||||
bind:value={service.wordpress.mysqlHost}
|
||||
placeholder="{$t('forms.eg')}: db.coolify.io"
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="mysqlPort">Port</label>
|
||||
<input
|
||||
name="mysqlPort"
|
||||
id="mysqlPort"
|
||||
required
|
||||
readonly={isRunning}
|
||||
disabled={isRunning}
|
||||
bind:value={service.wordpress.mysqlPort}
|
||||
placeholder="{$t('forms.eg')}: 3306"
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="mysqlDatabase">{$t('index.database')}</label>
|
||||
<input
|
||||
name="mysqlDatabase"
|
||||
id="mysqlDatabase"
|
||||
required
|
||||
readonly={readOnly}
|
||||
disabled={readOnly}
|
||||
readonly={readOnly && !service.wordpress.ownMysql}
|
||||
disabled={readOnly && !service.wordpress.ownMysql}
|
||||
bind:value={service.wordpress.mysqlDatabase}
|
||||
placeholder="{$t('forms.eg')}: wordpress_db"
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="mysqlRootUser">{$t('forms.root_user')}</label>
|
||||
<input
|
||||
name="mysqlRootUser"
|
||||
id="mysqlRootUser"
|
||||
placeholder="MySQL {$t('forms.root_user')}"
|
||||
value={service.wordpress.mysqlRootUser}
|
||||
disabled
|
||||
readonly
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="mysqlRootUserPassword">{$t('forms.roots_password')}</label>
|
||||
<CopyPasswordField
|
||||
id="mysqlRootUserPassword"
|
||||
isPasswordField
|
||||
readonly
|
||||
disabled
|
||||
name="mysqlRootUserPassword"
|
||||
value={service.wordpress.mysqlRootUserPassword}
|
||||
/>
|
||||
</div>
|
||||
{#if !service.wordpress.ownMysql}
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="mysqlRootUser">{$t('forms.root_user')}</label>
|
||||
<input
|
||||
name="mysqlRootUser"
|
||||
id="mysqlRootUser"
|
||||
placeholder="MySQL {$t('forms.root_user')}"
|
||||
value={service.wordpress.mysqlRootUser}
|
||||
readonly={isRunning || !service.wordpress.ownMysq}
|
||||
disabled={isRunning || !service.wordpress.ownMysq}
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="mysqlRootUserPassword">{$t('forms.roots_password')}</label>
|
||||
<CopyPasswordField
|
||||
id="mysqlRootUserPassword"
|
||||
isPasswordField
|
||||
readonly={isRunning || !service.wordpress.ownMysq}
|
||||
disabled={isRunning || !service.wordpress.ownMysq}
|
||||
name="mysqlRootUserPassword"
|
||||
value={service.wordpress.mysqlRootUserPassword}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="mysqlUser">{$t('forms.user')}</label>
|
||||
<input name="mysqlUser" id="mysqlUser" value={service.wordpress.mysqlUser} disabled readonly />
|
||||
<input
|
||||
name="mysqlUser"
|
||||
id="mysqlUser"
|
||||
value={service.wordpress.mysqlUser}
|
||||
readonly={isRunning || !service.wordpress.ownMysql}
|
||||
disabled={isRunning || !service.wordpress.ownMysql}
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="mysqlPassword">{$t('forms.password')}</label>
|
||||
<CopyPasswordField
|
||||
id="mysqlPassword"
|
||||
isPasswordField
|
||||
readonly
|
||||
disabled
|
||||
readonly={isRunning || !service.wordpress.ownMysql}
|
||||
disabled={isRunning || !service.wordpress.ownMysql}
|
||||
name="mysqlPassword"
|
||||
value={service.wordpress.mysqlPassword}
|
||||
/>
|
||||
|
||||
@@ -13,6 +13,7 @@ import { ErrorHandler, getServiceImage } from '$lib/database';
|
||||
import { makeLabelForServices } from '$lib/buildPacks/common';
|
||||
import type { ComposeFile } from '$lib/types/composeFile';
|
||||
import type { Service, DestinationDocker, Prisma } from '@prisma/client';
|
||||
import { getServiceMainPort } from '$lib/components/common';
|
||||
|
||||
export const post: RequestHandler = async (event) => {
|
||||
const { teamId, status, body } = await getUserDetails(event);
|
||||
@@ -30,6 +31,7 @@ export const post: RequestHandler = async (event) => {
|
||||
destinationDockerId,
|
||||
destinationDocker,
|
||||
serviceSecret,
|
||||
exposePort,
|
||||
fider: {
|
||||
postgresqlUser,
|
||||
postgresqlPassword,
|
||||
@@ -48,6 +50,7 @@ export const post: RequestHandler = async (event) => {
|
||||
} = service;
|
||||
const network = destinationDockerId && destinationDocker.network;
|
||||
const host = getEngine(destinationDocker.engine);
|
||||
const port = getServiceMainPort('fider');
|
||||
|
||||
const { workdir } = await createDirectories({ repository: type, buildId: id });
|
||||
const image = getServiceImage(type);
|
||||
@@ -97,6 +100,7 @@ export const post: RequestHandler = async (event) => {
|
||||
volumes: [],
|
||||
restart: 'always',
|
||||
labels: makeLabelForServices('fider'),
|
||||
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
||||
deploy: {
|
||||
restart_policy: {
|
||||
condition: 'on-failure',
|
||||
|
||||
@@ -11,11 +11,12 @@ export const post: RequestHandler = async (event) => {
|
||||
let {
|
||||
name,
|
||||
fqdn,
|
||||
exposePort,
|
||||
ghost: { mariadbDatabase }
|
||||
} = await event.request.json();
|
||||
if (fqdn) fqdn = fqdn.toLowerCase();
|
||||
try {
|
||||
await db.updateGhostService({ id, fqdn, name, mariadbDatabase });
|
||||
await db.updateGhostService({ id, fqdn, name, exposePort, mariadbDatabase });
|
||||
return { status: 201 };
|
||||
} catch (error) {
|
||||
return ErrorHandler(error);
|
||||
|
||||
@@ -12,6 +12,7 @@ import type { RequestHandler } from '@sveltejs/kit';
|
||||
import { ErrorHandler, getServiceImage } from '$lib/database';
|
||||
import { makeLabelForServices } from '$lib/buildPacks/common';
|
||||
import type { ComposeFile } from '$lib/types/composeFile';
|
||||
import { getServiceMainPort } from '$lib/components/common';
|
||||
|
||||
export const post: RequestHandler = async (event) => {
|
||||
const { teamId, status, body } = await getUserDetails(event);
|
||||
@@ -19,6 +20,8 @@ export const post: RequestHandler = async (event) => {
|
||||
|
||||
const { id } = event.params;
|
||||
|
||||
const port = getServiceMainPort('ghost');
|
||||
|
||||
try {
|
||||
const service = await db.getService({ id, teamId });
|
||||
const {
|
||||
@@ -27,6 +30,7 @@ export const post: RequestHandler = async (event) => {
|
||||
destinationDockerId,
|
||||
destinationDocker,
|
||||
serviceSecret,
|
||||
exposePort,
|
||||
fqdn,
|
||||
ghost: {
|
||||
defaultEmail,
|
||||
@@ -89,6 +93,7 @@ export const post: RequestHandler = async (event) => {
|
||||
volumes: [config.ghost.volume],
|
||||
environment: config.ghost.environmentVariables,
|
||||
restart: 'always',
|
||||
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
||||
labels: makeLabelForServices('ghost'),
|
||||
depends_on: [`${id}-mariadb`],
|
||||
deploy: {
|
||||
|
||||
@@ -7,6 +7,7 @@ import { ErrorHandler, getServiceImage } from '$lib/database';
|
||||
import { makeLabelForServices } from '$lib/buildPacks/common';
|
||||
import type { ComposeFile } from '$lib/types/composeFile';
|
||||
import type { Service, DestinationDocker, Prisma } from '@prisma/client';
|
||||
import { getServiceMainPort } from '$lib/components/common';
|
||||
|
||||
export const post: RequestHandler = async (event) => {
|
||||
const { teamId, status, body } = await getUserDetails(event);
|
||||
@@ -23,10 +24,12 @@ export const post: RequestHandler = async (event) => {
|
||||
destinationDockerId,
|
||||
destinationDocker,
|
||||
serviceSecret,
|
||||
exposePort,
|
||||
hasura: { postgresqlUser, postgresqlPassword, postgresqlDatabase }
|
||||
} = service;
|
||||
const network = destinationDockerId && destinationDocker.network;
|
||||
const host = getEngine(destinationDocker.engine);
|
||||
const port = getServiceMainPort('hasura');
|
||||
|
||||
const { workdir } = await createDirectories({ repository: type, buildId: id });
|
||||
const image = getServiceImage(type);
|
||||
@@ -65,6 +68,7 @@ export const post: RequestHandler = async (event) => {
|
||||
volumes: [],
|
||||
restart: 'always',
|
||||
labels: makeLabelForServices('hasura'),
|
||||
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
||||
deploy: {
|
||||
restart_policy: {
|
||||
condition: 'on-failure',
|
||||
|
||||
@@ -9,13 +9,15 @@ export const post: RequestHandler = async (event) => {
|
||||
|
||||
const { id } = event.params;
|
||||
|
||||
let { name, fqdn } = await event.request.json();
|
||||
let { name, fqdn, exposePort } = await event.request.json();
|
||||
if (fqdn) fqdn = fqdn.toLowerCase();
|
||||
if (exposePort) exposePort = Number(exposePort);
|
||||
|
||||
try {
|
||||
await db.updateService({ id, fqdn, name });
|
||||
await db.updateService({ id, fqdn, name, exposePort });
|
||||
return { status: 201 };
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
return ErrorHandler(error);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -6,6 +6,7 @@ import type { RequestHandler } from '@sveltejs/kit';
|
||||
import { ErrorHandler, getServiceImage } from '$lib/database';
|
||||
import { makeLabelForServices } from '$lib/buildPacks/common';
|
||||
import type { ComposeFile } from '$lib/types/composeFile';
|
||||
import { getServiceMainPort } from '$lib/components/common';
|
||||
|
||||
export const post: RequestHandler = async (event) => {
|
||||
const { teamId, status, body } = await getUserDetails(event);
|
||||
@@ -15,9 +16,11 @@ export const post: RequestHandler = async (event) => {
|
||||
|
||||
try {
|
||||
const service = await db.getService({ id, teamId });
|
||||
const { type, version, destinationDockerId, destinationDocker, serviceSecret } = service;
|
||||
const { type, version, destinationDockerId, destinationDocker, serviceSecret, exposePort } =
|
||||
service;
|
||||
const network = destinationDockerId && destinationDocker.network;
|
||||
const host = getEngine(destinationDocker.engine);
|
||||
const port = getServiceMainPort('languagetool');
|
||||
|
||||
const { workdir } = await createDirectories({ repository: type, buildId: id });
|
||||
const image = getServiceImage(type);
|
||||
@@ -42,6 +45,7 @@ export const post: RequestHandler = async (event) => {
|
||||
networks: [network],
|
||||
environment: config.environmentVariables,
|
||||
restart: 'always',
|
||||
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
||||
volumes: [config.volume],
|
||||
labels: makeLabelForServices('languagetool'),
|
||||
deploy: {
|
||||
|
||||
@@ -9,11 +9,12 @@ export const post: RequestHandler = async (event) => {
|
||||
|
||||
const { id } = event.params;
|
||||
|
||||
let { name, fqdn } = await event.request.json();
|
||||
let { name, fqdn, exposePort } = await event.request.json();
|
||||
if (fqdn) fqdn = fqdn.toLowerCase();
|
||||
if (exposePort) exposePort = Number(exposePort);
|
||||
|
||||
try {
|
||||
await db.updateService({ id, fqdn, name });
|
||||
await db.updateService({ id, fqdn, name, exposePort });
|
||||
return { status: 201 };
|
||||
} catch (error) {
|
||||
return ErrorHandler(error);
|
||||
|
||||
@@ -6,6 +6,7 @@ import type { RequestHandler } from '@sveltejs/kit';
|
||||
import { ErrorHandler, getServiceImage } from '$lib/database';
|
||||
import { makeLabelForServices } from '$lib/buildPacks/common';
|
||||
import type { ComposeFile } from '$lib/types/composeFile';
|
||||
import { getServiceMainPort } from '$lib/components/common';
|
||||
|
||||
export const post: RequestHandler = async (event) => {
|
||||
const { teamId, status, body } = await getUserDetails(event);
|
||||
@@ -18,9 +19,11 @@ export const post: RequestHandler = async (event) => {
|
||||
const {
|
||||
meiliSearch: { masterKey }
|
||||
} = service;
|
||||
const { type, version, destinationDockerId, destinationDocker, serviceSecret } = service;
|
||||
const { type, version, destinationDockerId, destinationDocker, serviceSecret, exposePort } =
|
||||
service;
|
||||
const network = destinationDockerId && destinationDocker.network;
|
||||
const host = getEngine(destinationDocker.engine);
|
||||
const port = getServiceMainPort('meilisearch');
|
||||
|
||||
const { workdir } = await createDirectories({ repository: type, buildId: id });
|
||||
const image = getServiceImage(type);
|
||||
@@ -47,6 +50,7 @@ export const post: RequestHandler = async (event) => {
|
||||
networks: [network],
|
||||
environment: config.environmentVariables,
|
||||
restart: 'always',
|
||||
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
||||
volumes: [config.volume],
|
||||
labels: makeLabelForServices('meilisearch'),
|
||||
deploy: {
|
||||
|
||||
@@ -9,11 +9,12 @@ export const post: RequestHandler = async (event) => {
|
||||
|
||||
const { id } = event.params;
|
||||
|
||||
let { name, fqdn } = await event.request.json();
|
||||
let { name, fqdn, exposePort } = await event.request.json();
|
||||
if (fqdn) fqdn = fqdn.toLowerCase();
|
||||
if (exposePort) exposePort = Number(exposePort);
|
||||
|
||||
try {
|
||||
await db.updateService({ id, fqdn, name });
|
||||
await db.updateService({ id, fqdn, name, exposePort });
|
||||
return { status: 201 };
|
||||
} catch (error) {
|
||||
return ErrorHandler(error);
|
||||
|
||||
@@ -7,6 +7,7 @@ import { startHttpProxy } from '$lib/haproxy';
|
||||
import { ErrorHandler, getFreePort, getServiceImage } from '$lib/database';
|
||||
import { makeLabelForServices } from '$lib/buildPacks/common';
|
||||
import type { ComposeFile } from '$lib/types/composeFile';
|
||||
import { getServiceMainPort } from '$lib/components/common';
|
||||
|
||||
export const post: RequestHandler = async (event) => {
|
||||
const { teamId, status, body } = await getUserDetails(event);
|
||||
@@ -22,12 +23,14 @@ export const post: RequestHandler = async (event) => {
|
||||
fqdn,
|
||||
destinationDockerId,
|
||||
destinationDocker,
|
||||
exposePort,
|
||||
minio: { rootUser, rootUserPassword },
|
||||
serviceSecret
|
||||
} = service;
|
||||
|
||||
const network = destinationDockerId && destinationDocker.network;
|
||||
const host = getEngine(destinationDocker.engine);
|
||||
const port = getServiceMainPort('minio');
|
||||
|
||||
const publicPort = await getFreePort();
|
||||
|
||||
@@ -62,6 +65,7 @@ export const post: RequestHandler = async (event) => {
|
||||
networks: [network],
|
||||
volumes: [config.volume],
|
||||
restart: 'always',
|
||||
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
||||
labels: makeLabelForServices('minio'),
|
||||
deploy: {
|
||||
restart_policy: {
|
||||
|
||||
@@ -8,11 +8,12 @@ export const post: RequestHandler = async (event) => {
|
||||
if (status === 401) return { status, body };
|
||||
const { id } = event.params;
|
||||
|
||||
let { name, fqdn } = await event.request.json();
|
||||
let { name, fqdn, exposePort } = await event.request.json();
|
||||
if (fqdn) fqdn = fqdn.toLowerCase();
|
||||
if (exposePort) exposePort = Number(exposePort);
|
||||
|
||||
try {
|
||||
await db.updateService({ id, fqdn, name });
|
||||
await db.updateService({ id, fqdn, name, exposePort });
|
||||
return { status: 201 };
|
||||
} catch (error) {
|
||||
return ErrorHandler(error);
|
||||
|
||||
@@ -6,6 +6,7 @@ import type { RequestHandler } from '@sveltejs/kit';
|
||||
import { ErrorHandler, getServiceImage } from '$lib/database';
|
||||
import { makeLabelForServices } from '$lib/buildPacks/common';
|
||||
import type { ComposeFile } from '$lib/types/composeFile';
|
||||
import { getServiceMainPort } from '$lib/components/common';
|
||||
|
||||
export const post: RequestHandler = async (event) => {
|
||||
const { teamId, status, body } = await getUserDetails(event);
|
||||
@@ -15,9 +16,11 @@ export const post: RequestHandler = async (event) => {
|
||||
|
||||
try {
|
||||
const service = await db.getService({ id, teamId });
|
||||
const { type, version, destinationDockerId, destinationDocker, serviceSecret } = service;
|
||||
const { type, version, destinationDockerId, destinationDocker, serviceSecret, exposePort } =
|
||||
service;
|
||||
const network = destinationDockerId && destinationDocker.network;
|
||||
const host = getEngine(destinationDocker.engine);
|
||||
const port = getServiceMainPort('n8n');
|
||||
|
||||
const { workdir } = await createDirectories({ repository: type, buildId: id });
|
||||
const image = getServiceImage(type);
|
||||
@@ -45,6 +48,7 @@ export const post: RequestHandler = async (event) => {
|
||||
environment: config.environmentVariables,
|
||||
restart: 'always',
|
||||
labels: makeLabelForServices('n8n'),
|
||||
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
||||
deploy: {
|
||||
restart_policy: {
|
||||
condition: 'on-failure',
|
||||
|
||||
@@ -8,11 +8,12 @@ export const post: RequestHandler = async (event) => {
|
||||
if (status === 401) return { status, body };
|
||||
const { id } = event.params;
|
||||
|
||||
let { name, fqdn } = await event.request.json();
|
||||
let { name, fqdn, exposePort } = await event.request.json();
|
||||
if (fqdn) fqdn = fqdn.toLowerCase();
|
||||
if (exposePort) exposePort = Number(exposePort);
|
||||
|
||||
try {
|
||||
await db.updateService({ id, fqdn, name });
|
||||
await db.updateService({ id, fqdn, name, exposePort });
|
||||
return { status: 201 };
|
||||
} catch (error) {
|
||||
return ErrorHandler(error);
|
||||
|
||||
@@ -6,6 +6,7 @@ import type { RequestHandler } from '@sveltejs/kit';
|
||||
import { ErrorHandler, getServiceImage } from '$lib/database';
|
||||
import { makeLabelForServices } from '$lib/buildPacks/common';
|
||||
import type { ComposeFile } from '$lib/types/composeFile';
|
||||
import { getServiceMainPort } from '$lib/components/common';
|
||||
|
||||
export const post: RequestHandler = async (event) => {
|
||||
const { teamId, status, body } = await getUserDetails(event);
|
||||
@@ -15,9 +16,11 @@ export const post: RequestHandler = async (event) => {
|
||||
|
||||
try {
|
||||
const service = await db.getService({ id, teamId });
|
||||
const { type, version, destinationDockerId, destinationDocker, serviceSecret } = service;
|
||||
const { type, version, destinationDockerId, destinationDocker, serviceSecret, exposePort } =
|
||||
service;
|
||||
const network = destinationDockerId && destinationDocker.network;
|
||||
const host = getEngine(destinationDocker.engine);
|
||||
const port = getServiceMainPort('nocodb');
|
||||
|
||||
const { workdir } = await createDirectories({ repository: type, buildId: id });
|
||||
const image = getServiceImage(type);
|
||||
@@ -40,6 +43,7 @@ export const post: RequestHandler = async (event) => {
|
||||
networks: [network],
|
||||
environment: config.environmentVariables,
|
||||
restart: 'always',
|
||||
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
||||
labels: makeLabelForServices('nocodb'),
|
||||
deploy: {
|
||||
restart_policy: {
|
||||
|
||||
@@ -11,14 +11,29 @@ export const post: RequestHandler = async (event) => {
|
||||
let {
|
||||
name,
|
||||
fqdn,
|
||||
plausibleAnalytics: { email, username }
|
||||
exposePort,
|
||||
plausibleAnalytics: { email, username, scriptName }
|
||||
} = await event.request.json();
|
||||
|
||||
if (fqdn) fqdn = fqdn.toLowerCase();
|
||||
if (email) email = email.toLowerCase();
|
||||
|
||||
if (exposePort) exposePort = Number(exposePort);
|
||||
if (scriptName) {
|
||||
scriptName = scriptName.toLowerCase();
|
||||
if (scriptName.startsWith('/')) {
|
||||
scriptName = scriptName.replaceAll(/\//gi, '');
|
||||
}
|
||||
}
|
||||
try {
|
||||
await db.updatePlausibleAnalyticsService({ id, fqdn, name, email, username });
|
||||
await db.updatePlausibleAnalyticsService({
|
||||
id,
|
||||
fqdn,
|
||||
name,
|
||||
email,
|
||||
username,
|
||||
exposePort,
|
||||
scriptName
|
||||
});
|
||||
return { status: 201 };
|
||||
} catch (error) {
|
||||
return ErrorHandler(error);
|
||||
|
||||
@@ -6,6 +6,7 @@ import type { RequestHandler } from '@sveltejs/kit';
|
||||
import { ErrorHandler, getServiceImage } from '$lib/database';
|
||||
import { makeLabelForServices } from '$lib/buildPacks/common';
|
||||
import type { ComposeFile } from '$lib/types/composeFile';
|
||||
import { getServiceMainPort } from '$lib/components/common';
|
||||
|
||||
export const post: RequestHandler = async (event) => {
|
||||
const { teamId, status, body } = await getUserDetails(event);
|
||||
@@ -22,6 +23,7 @@ export const post: RequestHandler = async (event) => {
|
||||
destinationDockerId,
|
||||
destinationDocker,
|
||||
serviceSecret,
|
||||
exposePort,
|
||||
plausibleAnalytics: {
|
||||
id: plausibleDbId,
|
||||
username,
|
||||
@@ -78,6 +80,7 @@ export const post: RequestHandler = async (event) => {
|
||||
}
|
||||
const network = destinationDockerId && destinationDocker.network;
|
||||
const host = getEngine(destinationDocker.engine);
|
||||
const port = getServiceMainPort('plausibleanalytics');
|
||||
|
||||
const { workdir } = await createDirectories({ repository: type, buildId: id });
|
||||
|
||||
@@ -132,6 +135,7 @@ COPY ./init-db.sh /docker-entrypoint-initdb.d/init-db.sh`;
|
||||
networks: [network],
|
||||
environment: config.plausibleAnalytics.environmentVariables,
|
||||
restart: 'always',
|
||||
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
||||
depends_on: [`${id}-postgresql`, `${id}-clickhouse`],
|
||||
labels: makeLabelForServices('plausibleAnalytics'),
|
||||
deploy: {
|
||||
@@ -191,6 +195,7 @@ COPY ./init-db.sh /docker-entrypoint-initdb.d/init-db.sh`;
|
||||
}
|
||||
};
|
||||
const composeFileDestination = `${workdir}/docker-compose.yaml`;
|
||||
console.log(JSON.stringify(composeFile, null, 2));
|
||||
await fs.writeFile(composeFileDestination, yaml.dump(composeFile));
|
||||
await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} pull`);
|
||||
await asyncExecShell(
|
||||
|
||||
@@ -9,11 +9,12 @@ export const post: RequestHandler = async (event) => {
|
||||
|
||||
const { id } = event.params;
|
||||
|
||||
let { name, fqdn } = await event.request.json();
|
||||
let { name, fqdn, exposePort } = await event.request.json();
|
||||
if (fqdn) fqdn = fqdn.toLowerCase();
|
||||
if (exposePort) exposePort = Number(exposePort);
|
||||
|
||||
try {
|
||||
await db.updateService({ id, fqdn, name });
|
||||
await db.updateService({ id, fqdn, name, exposePort });
|
||||
return { status: 201 };
|
||||
} catch (error) {
|
||||
return ErrorHandler(error);
|
||||
|
||||
@@ -8,6 +8,7 @@ import { makeLabelForServices } from '$lib/buildPacks/common';
|
||||
import type { ComposeFile } from '$lib/types/composeFile';
|
||||
import type { Service, DestinationDocker, Prisma } from '@prisma/client';
|
||||
import bcrypt from 'bcryptjs';
|
||||
import { getServiceMainPort } from '$lib/components/common';
|
||||
|
||||
export const post: RequestHandler = async (event) => {
|
||||
const { teamId, status, body } = await getUserDetails(event);
|
||||
@@ -24,6 +25,7 @@ export const post: RequestHandler = async (event) => {
|
||||
destinationDockerId,
|
||||
destinationDocker,
|
||||
serviceSecret,
|
||||
exposePort,
|
||||
umami: {
|
||||
umamiAdminPassword,
|
||||
postgresqlUser,
|
||||
@@ -34,6 +36,7 @@ export const post: RequestHandler = async (event) => {
|
||||
} = service;
|
||||
const network = destinationDockerId && destinationDocker.network;
|
||||
const host = getEngine(destinationDocker.engine);
|
||||
const port = getServiceMainPort('umami');
|
||||
|
||||
const { workdir } = await createDirectories({ repository: type, buildId: id });
|
||||
const image = getServiceImage(type);
|
||||
@@ -156,6 +159,7 @@ export const post: RequestHandler = async (event) => {
|
||||
networks: [network],
|
||||
volumes: [],
|
||||
restart: 'always',
|
||||
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
||||
labels: makeLabelForServices('umami'),
|
||||
deploy: {
|
||||
restart_policy: {
|
||||
|
||||
@@ -8,11 +8,12 @@ export const post: RequestHandler = async (event) => {
|
||||
if (status === 401) return { status, body };
|
||||
const { id } = event.params;
|
||||
|
||||
let { name, fqdn } = await event.request.json();
|
||||
let { name, fqdn, exposePort } = await event.request.json();
|
||||
if (fqdn) fqdn = fqdn.toLowerCase();
|
||||
if (exposePort) exposePort = Number(exposePort);
|
||||
|
||||
try {
|
||||
await db.updateService({ id, fqdn, name });
|
||||
await db.updateService({ id, fqdn, name, exposePort });
|
||||
return { status: 201 };
|
||||
} catch (error) {
|
||||
return ErrorHandler(error);
|
||||
|
||||
@@ -6,6 +6,7 @@ import type { RequestHandler } from '@sveltejs/kit';
|
||||
import { ErrorHandler, getServiceImage } from '$lib/database';
|
||||
import { makeLabelForServices } from '$lib/buildPacks/common';
|
||||
import type { ComposeFile } from '$lib/types/composeFile';
|
||||
import { getServiceMainPort } from '$lib/components/common';
|
||||
|
||||
export const post: RequestHandler = async (event) => {
|
||||
const { teamId, status, body } = await getUserDetails(event);
|
||||
@@ -15,9 +16,11 @@ export const post: RequestHandler = async (event) => {
|
||||
|
||||
try {
|
||||
const service = await db.getService({ id, teamId });
|
||||
const { type, version, destinationDockerId, destinationDocker, serviceSecret } = service;
|
||||
const { type, version, destinationDockerId, destinationDocker, serviceSecret, exposePort } =
|
||||
service;
|
||||
const network = destinationDockerId && destinationDocker.network;
|
||||
const host = getEngine(destinationDocker.engine);
|
||||
const port = getServiceMainPort('uptimekuma');
|
||||
|
||||
const { workdir } = await createDirectories({ repository: type, buildId: id });
|
||||
const image = getServiceImage(type);
|
||||
@@ -42,6 +45,7 @@ export const post: RequestHandler = async (event) => {
|
||||
volumes: [config.volume],
|
||||
environment: config.environmentVariables,
|
||||
restart: 'always',
|
||||
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
||||
labels: makeLabelForServices('uptimekuma'),
|
||||
deploy: {
|
||||
restart_policy: {
|
||||
|
||||
@@ -8,11 +8,12 @@ export const post: RequestHandler = async (event) => {
|
||||
if (status === 401) return { status, body };
|
||||
const { id } = event.params;
|
||||
|
||||
let { name, fqdn } = await event.request.json();
|
||||
let { name, fqdn, exposePort } = await event.request.json();
|
||||
if (fqdn) fqdn = fqdn.toLowerCase();
|
||||
if (exposePort) exposePort = Number(exposePort);
|
||||
|
||||
try {
|
||||
await db.updateService({ id, fqdn, name });
|
||||
await db.updateService({ id, fqdn, name, exposePort });
|
||||
return { status: 201 };
|
||||
} catch (error) {
|
||||
return ErrorHandler(error);
|
||||
|
||||
@@ -6,6 +6,7 @@ import type { RequestHandler } from '@sveltejs/kit';
|
||||
import { getServiceImage, ErrorHandler } from '$lib/database';
|
||||
import { makeLabelForServices } from '$lib/buildPacks/common';
|
||||
import type { ComposeFile } from '$lib/types/composeFile';
|
||||
import { getServiceMainPort } from '$lib/components/common';
|
||||
|
||||
export const post: RequestHandler = async (event) => {
|
||||
const { teamId, status, body } = await getUserDetails(event);
|
||||
@@ -15,10 +16,12 @@ export const post: RequestHandler = async (event) => {
|
||||
|
||||
try {
|
||||
const service = await db.getService({ id, teamId });
|
||||
const { type, version, destinationDockerId, destinationDocker, serviceSecret } = service;
|
||||
const { type, version, destinationDockerId, destinationDocker, serviceSecret, exposePort } =
|
||||
service;
|
||||
|
||||
const network = destinationDockerId && destinationDocker.network;
|
||||
const host = getEngine(destinationDocker.engine);
|
||||
const port = getServiceMainPort('vaultwarden');
|
||||
|
||||
const { workdir } = await createDirectories({ repository: type, buildId: id });
|
||||
const image = getServiceImage(type);
|
||||
@@ -43,6 +46,7 @@ export const post: RequestHandler = async (event) => {
|
||||
networks: [network],
|
||||
volumes: [config.volume],
|
||||
restart: 'always',
|
||||
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
||||
labels: makeLabelForServices('vaultWarden'),
|
||||
deploy: {
|
||||
restart_policy: {
|
||||
|
||||
@@ -9,11 +9,12 @@ export const post: RequestHandler = async (event) => {
|
||||
|
||||
const { id } = event.params;
|
||||
|
||||
let { name, fqdn } = await event.request.json();
|
||||
let { name, fqdn, exposePort } = await event.request.json();
|
||||
if (fqdn) fqdn = fqdn.toLowerCase();
|
||||
if (exposePort) exposePort = Number(exposePort);
|
||||
|
||||
try {
|
||||
await db.updateService({ id, fqdn, name });
|
||||
await db.updateService({ id, fqdn, name, exposePort });
|
||||
return { status: 201 };
|
||||
} catch (error) {
|
||||
return ErrorHandler(error);
|
||||
|
||||
@@ -6,6 +6,7 @@ import type { RequestHandler } from '@sveltejs/kit';
|
||||
import { ErrorHandler, getServiceImage } from '$lib/database';
|
||||
import { makeLabelForServices } from '$lib/buildPacks/common';
|
||||
import type { ComposeFile } from '$lib/types/composeFile';
|
||||
import { getServiceMainPort } from '$lib/components/common';
|
||||
|
||||
export const post: RequestHandler = async (event) => {
|
||||
const { teamId, status, body } = await getUserDetails(event);
|
||||
@@ -22,11 +23,13 @@ export const post: RequestHandler = async (event) => {
|
||||
destinationDocker,
|
||||
serviceSecret,
|
||||
persistentStorage,
|
||||
exposePort,
|
||||
vscodeserver: { password }
|
||||
} = service;
|
||||
|
||||
const network = destinationDockerId && destinationDocker.network;
|
||||
const host = getEngine(destinationDocker.engine);
|
||||
const port = getServiceMainPort('vscodeserver');
|
||||
|
||||
const { workdir } = await createDirectories({ repository: type, buildId: id });
|
||||
const image = getServiceImage(type);
|
||||
@@ -75,6 +78,7 @@ export const post: RequestHandler = async (event) => {
|
||||
networks: [network],
|
||||
volumes: [config.volume, ...volumes],
|
||||
restart: 'always',
|
||||
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
||||
labels: makeLabelForServices('vscodeServer'),
|
||||
deploy: {
|
||||
restart_policy: {
|
||||
|
||||
185
src/routes/services/[id]/wordpress/ftp.json.ts
Normal file
185
src/routes/services/[id]/wordpress/ftp.json.ts
Normal file
@@ -0,0 +1,185 @@
|
||||
import { dev } from '$app/env';
|
||||
import { asyncExecShell, getEngine, getUserDetails } from '$lib/common';
|
||||
import { decrypt, encrypt } from '$lib/crypto';
|
||||
import * as db from '$lib/database';
|
||||
import { ErrorHandler, generatePassword, getFreePort } from '$lib/database';
|
||||
import { checkContainer, startTcpProxy, stopTcpHttpProxy } from '$lib/haproxy';
|
||||
import type { ComposeFile } from '$lib/types/composeFile';
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
import cuid from 'cuid';
|
||||
import fs from 'fs/promises';
|
||||
import yaml from 'js-yaml';
|
||||
|
||||
export const post: RequestHandler = async (event) => {
|
||||
const { status, body, teamId } = await getUserDetails(event);
|
||||
if (status === 401) return { status, body };
|
||||
|
||||
const { id } = event.params;
|
||||
|
||||
const { ftpEnabled } = await event.request.json();
|
||||
const publicPort = await getFreePort();
|
||||
|
||||
let ftpUser = cuid();
|
||||
let ftpPassword = generatePassword();
|
||||
|
||||
const hostkeyDir = dev ? '/tmp/hostkeys' : '/app/ssl/hostkeys';
|
||||
try {
|
||||
const data = await db.prisma.wordpress.update({
|
||||
where: { serviceId: id },
|
||||
data: { ftpEnabled },
|
||||
include: { service: { include: { destinationDocker: true } } }
|
||||
});
|
||||
const {
|
||||
service: { destinationDockerId, destinationDocker },
|
||||
ftpPublicPort: oldPublicPort,
|
||||
ftpUser: user,
|
||||
ftpPassword: savedPassword,
|
||||
ftpHostKey,
|
||||
ftpHostKeyPrivate
|
||||
} = data;
|
||||
if (user) ftpUser = user;
|
||||
if (savedPassword) ftpPassword = decrypt(savedPassword);
|
||||
|
||||
const { stdout: password } = await asyncExecShell(
|
||||
`echo ${ftpPassword} | openssl passwd -1 -stdin`
|
||||
);
|
||||
if (destinationDockerId) {
|
||||
try {
|
||||
await fs.stat(hostkeyDir);
|
||||
} catch (error) {
|
||||
await asyncExecShell(`mkdir -p ${hostkeyDir}`);
|
||||
}
|
||||
if (!ftpHostKey) {
|
||||
await asyncExecShell(
|
||||
`ssh-keygen -t ed25519 -f ssh_host_ed25519_key -N "" -q -f ${hostkeyDir}/${id}.ed25519`
|
||||
);
|
||||
const { stdout: ftpHostKey } = await asyncExecShell(`cat ${hostkeyDir}/${id}.ed25519`);
|
||||
await db.prisma.wordpress.update({
|
||||
where: { serviceId: id },
|
||||
data: { ftpHostKey: encrypt(ftpHostKey) }
|
||||
});
|
||||
} else {
|
||||
await asyncExecShell(`echo "${decrypt(ftpHostKey)}" > ${hostkeyDir}/${id}.ed25519`);
|
||||
}
|
||||
if (!ftpHostKeyPrivate) {
|
||||
await asyncExecShell(`ssh-keygen -t rsa -b 4096 -N "" -f ${hostkeyDir}/${id}.rsa`);
|
||||
const { stdout: ftpHostKeyPrivate } = await asyncExecShell(`cat ${hostkeyDir}/${id}.rsa`);
|
||||
await db.prisma.wordpress.update({
|
||||
where: { serviceId: id },
|
||||
data: { ftpHostKeyPrivate: encrypt(ftpHostKeyPrivate) }
|
||||
});
|
||||
} else {
|
||||
await asyncExecShell(`echo "${decrypt(ftpHostKeyPrivate)}" > ${hostkeyDir}/${id}.rsa`);
|
||||
}
|
||||
const { network, engine } = destinationDocker;
|
||||
const host = getEngine(engine);
|
||||
if (ftpEnabled) {
|
||||
await db.prisma.wordpress.update({
|
||||
where: { serviceId: id },
|
||||
data: {
|
||||
ftpPublicPort: publicPort,
|
||||
ftpUser: user ? undefined : ftpUser,
|
||||
ftpPassword: savedPassword ? undefined : encrypt(ftpPassword)
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
const isRunning = await checkContainer(engine, `${id}-ftp`);
|
||||
if (isRunning) {
|
||||
await asyncExecShell(
|
||||
`DOCKER_HOST=${host} docker stop -t 0 ${id}-ftp && docker rm ${id}-ftp`
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
//
|
||||
}
|
||||
const volumes = [
|
||||
`${id}-wordpress-data:/home/${ftpUser}`,
|
||||
`${
|
||||
dev ? hostkeyDir : '/var/lib/docker/volumes/coolify-ssl-certs/_data/hostkeys'
|
||||
}/${id}.ed25519:/etc/ssh/ssh_host_ed25519_key`,
|
||||
`${
|
||||
dev ? hostkeyDir : '/var/lib/docker/volumes/coolify-ssl-certs/_data/hostkeys'
|
||||
}/${id}.rsa:/etc/ssh/ssh_host_rsa_key`,
|
||||
`${
|
||||
dev ? hostkeyDir : '/var/lib/docker/volumes/coolify-ssl-certs/_data/hostkeys'
|
||||
}/${id}.sh:/etc/sftp.d/chmod.sh`
|
||||
];
|
||||
|
||||
const compose: ComposeFile = {
|
||||
version: '3.8',
|
||||
services: {
|
||||
[`${id}-ftp`]: {
|
||||
image: `atmoz/sftp:alpine`,
|
||||
command: `'${ftpUser}:${password.replace('\n', '').replace(/\$/g, '$$$')}:e:33'`,
|
||||
extra_hosts: ['host.docker.internal:host-gateway'],
|
||||
container_name: `${id}-ftp`,
|
||||
volumes,
|
||||
networks: [network],
|
||||
depends_on: [],
|
||||
restart: 'always'
|
||||
}
|
||||
},
|
||||
networks: {
|
||||
[network]: {
|
||||
external: true
|
||||
}
|
||||
},
|
||||
volumes: {
|
||||
[`${id}-wordpress-data`]: {
|
||||
external: true,
|
||||
name: `${id}-wordpress-data`
|
||||
}
|
||||
}
|
||||
};
|
||||
await fs.writeFile(
|
||||
`${hostkeyDir}/${id}.sh`,
|
||||
`#!/bin/bash\nchmod 600 /etc/ssh/ssh_host_ed25519_key /etc/ssh/ssh_host_rsa_key`
|
||||
);
|
||||
await asyncExecShell(`chmod +x ${hostkeyDir}/${id}.sh`);
|
||||
await fs.writeFile(`${hostkeyDir}/${id}-docker-compose.yml`, yaml.dump(compose));
|
||||
await asyncExecShell(
|
||||
`DOCKER_HOST=${host} docker compose -f ${hostkeyDir}/${id}-docker-compose.yml up -d`
|
||||
);
|
||||
|
||||
await startTcpProxy(destinationDocker, `${id}-ftp`, publicPort, 22);
|
||||
} else {
|
||||
await db.prisma.wordpress.update({
|
||||
where: { serviceId: id },
|
||||
data: { ftpPublicPort: null }
|
||||
});
|
||||
try {
|
||||
await asyncExecShell(
|
||||
`DOCKER_HOST=${host} docker stop -t 0 ${id}-ftp && docker rm ${id}-ftp`
|
||||
);
|
||||
} catch (error) {
|
||||
//
|
||||
}
|
||||
await stopTcpHttpProxy(destinationDocker, oldPublicPort);
|
||||
}
|
||||
}
|
||||
if (ftpEnabled) {
|
||||
return {
|
||||
status: 201,
|
||||
body: {
|
||||
publicPort,
|
||||
ftpUser,
|
||||
ftpPassword
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
status: 200,
|
||||
body: {}
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
return ErrorHandler(error);
|
||||
} finally {
|
||||
await asyncExecShell(
|
||||
`rm -f ${hostkeyDir}/${id}-docker-compose.yml ${hostkeyDir}/${id}.ed25519 ${hostkeyDir}/${id}.ed25519.pub ${hostkeyDir}/${id}.rsa ${hostkeyDir}/${id}.rsa.pub ${hostkeyDir}/${id}.sh`
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -11,12 +11,25 @@ export const post: RequestHandler = async (event) => {
|
||||
let {
|
||||
name,
|
||||
fqdn,
|
||||
wordpress: { extraConfig, mysqlDatabase }
|
||||
exposePort,
|
||||
wordpress: { extraConfig, mysqlDatabase, mysqlHost, mysqlPort }
|
||||
} = await event.request.json();
|
||||
|
||||
if (fqdn) fqdn = fqdn.toLowerCase();
|
||||
if (exposePort) exposePort = Number(exposePort);
|
||||
if (mysqlPort) mysqlPort = Number(mysqlPort);
|
||||
|
||||
try {
|
||||
await db.updateWordpress({ id, fqdn, name, extraConfig, mysqlDatabase });
|
||||
await db.updateWordpress({
|
||||
id,
|
||||
fqdn,
|
||||
name,
|
||||
extraConfig,
|
||||
mysqlDatabase,
|
||||
exposePort,
|
||||
mysqlHost,
|
||||
mysqlPort
|
||||
});
|
||||
return { status: 201 };
|
||||
} catch (error) {
|
||||
return ErrorHandler(error);
|
||||
|
||||
@@ -8,7 +8,6 @@ import type { ComposeFile } from '$lib/types/composeFile';
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
import cuid from 'cuid';
|
||||
import fs from 'fs/promises';
|
||||
import getPort, { portNumbers } from 'get-port';
|
||||
import yaml from 'js-yaml';
|
||||
|
||||
export const post: RequestHandler = async (event) => {
|
||||
@@ -17,170 +16,17 @@ export const post: RequestHandler = async (event) => {
|
||||
|
||||
const { id } = event.params;
|
||||
|
||||
const { ftpEnabled } = await event.request.json();
|
||||
const publicPort = await getFreePort();
|
||||
|
||||
let ftpUser = cuid();
|
||||
let ftpPassword = generatePassword();
|
||||
|
||||
const hostkeyDir = dev ? '/tmp/hostkeys' : '/app/ssl/hostkeys';
|
||||
const { ownMysql } = await event.request.json();
|
||||
try {
|
||||
const data = await db.prisma.wordpress.update({
|
||||
await db.prisma.wordpress.update({
|
||||
where: { serviceId: id },
|
||||
data: { ftpEnabled },
|
||||
include: { service: { include: { destinationDocker: true } } }
|
||||
data: { ownMysql }
|
||||
});
|
||||
const {
|
||||
service: { destinationDockerId, destinationDocker },
|
||||
ftpPublicPort: oldPublicPort,
|
||||
ftpUser: user,
|
||||
ftpPassword: savedPassword,
|
||||
ftpHostKey,
|
||||
ftpHostKeyPrivate
|
||||
} = data;
|
||||
if (user) ftpUser = user;
|
||||
if (savedPassword) ftpPassword = decrypt(savedPassword);
|
||||
|
||||
const { stdout: password } = await asyncExecShell(
|
||||
`echo ${ftpPassword} | openssl passwd -1 -stdin`
|
||||
);
|
||||
if (destinationDockerId) {
|
||||
try {
|
||||
await fs.stat(hostkeyDir);
|
||||
} catch (error) {
|
||||
await asyncExecShell(`mkdir -p ${hostkeyDir}`);
|
||||
}
|
||||
if (!ftpHostKey) {
|
||||
await asyncExecShell(
|
||||
`ssh-keygen -t ed25519 -f ssh_host_ed25519_key -N "" -q -f ${hostkeyDir}/${id}.ed25519`
|
||||
);
|
||||
const { stdout: ftpHostKey } = await asyncExecShell(`cat ${hostkeyDir}/${id}.ed25519`);
|
||||
await db.prisma.wordpress.update({
|
||||
where: { serviceId: id },
|
||||
data: { ftpHostKey: encrypt(ftpHostKey) }
|
||||
});
|
||||
} else {
|
||||
await asyncExecShell(`echo "${decrypt(ftpHostKey)}" > ${hostkeyDir}/${id}.ed25519`);
|
||||
}
|
||||
if (!ftpHostKeyPrivate) {
|
||||
await asyncExecShell(`ssh-keygen -t rsa -b 4096 -N "" -f ${hostkeyDir}/${id}.rsa`);
|
||||
const { stdout: ftpHostKeyPrivate } = await asyncExecShell(`cat ${hostkeyDir}/${id}.rsa`);
|
||||
await db.prisma.wordpress.update({
|
||||
where: { serviceId: id },
|
||||
data: { ftpHostKeyPrivate: encrypt(ftpHostKeyPrivate) }
|
||||
});
|
||||
} else {
|
||||
await asyncExecShell(`echo "${decrypt(ftpHostKeyPrivate)}" > ${hostkeyDir}/${id}.rsa`);
|
||||
}
|
||||
const { network, engine } = destinationDocker;
|
||||
const host = getEngine(engine);
|
||||
if (ftpEnabled) {
|
||||
await db.prisma.wordpress.update({
|
||||
where: { serviceId: id },
|
||||
data: {
|
||||
ftpPublicPort: publicPort,
|
||||
ftpUser: user ? undefined : ftpUser,
|
||||
ftpPassword: savedPassword ? undefined : encrypt(ftpPassword)
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
const isRunning = await checkContainer(engine, `${id}-ftp`);
|
||||
if (isRunning) {
|
||||
await asyncExecShell(
|
||||
`DOCKER_HOST=${host} docker stop -t 0 ${id}-ftp && docker rm ${id}-ftp`
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
//
|
||||
}
|
||||
const volumes = [
|
||||
`${id}-wordpress-data:/home/${ftpUser}`,
|
||||
`${
|
||||
dev ? hostkeyDir : '/var/lib/docker/volumes/coolify-ssl-certs/_data/hostkeys'
|
||||
}/${id}.ed25519:/etc/ssh/ssh_host_ed25519_key`,
|
||||
`${
|
||||
dev ? hostkeyDir : '/var/lib/docker/volumes/coolify-ssl-certs/_data/hostkeys'
|
||||
}/${id}.rsa:/etc/ssh/ssh_host_rsa_key`,
|
||||
`${
|
||||
dev ? hostkeyDir : '/var/lib/docker/volumes/coolify-ssl-certs/_data/hostkeys'
|
||||
}/${id}.sh:/etc/sftp.d/chmod.sh`
|
||||
];
|
||||
|
||||
const compose: ComposeFile = {
|
||||
version: '3.8',
|
||||
services: {
|
||||
[`${id}-ftp`]: {
|
||||
image: `atmoz/sftp:alpine`,
|
||||
command: `'${ftpUser}:${password.replace('\n', '').replace(/\$/g, '$$$')}:e:33'`,
|
||||
extra_hosts: ['host.docker.internal:host-gateway'],
|
||||
container_name: `${id}-ftp`,
|
||||
volumes,
|
||||
networks: [network],
|
||||
depends_on: [],
|
||||
restart: 'always'
|
||||
}
|
||||
},
|
||||
networks: {
|
||||
[network]: {
|
||||
external: true
|
||||
}
|
||||
},
|
||||
volumes: {
|
||||
[`${id}-wordpress-data`]: {
|
||||
external: true,
|
||||
name: `${id}-wordpress-data`
|
||||
}
|
||||
}
|
||||
};
|
||||
await fs.writeFile(
|
||||
`${hostkeyDir}/${id}.sh`,
|
||||
`#!/bin/bash\nchmod 600 /etc/ssh/ssh_host_ed25519_key /etc/ssh/ssh_host_rsa_key`
|
||||
);
|
||||
await asyncExecShell(`chmod +x ${hostkeyDir}/${id}.sh`);
|
||||
await fs.writeFile(`${hostkeyDir}/${id}-docker-compose.yml`, yaml.dump(compose));
|
||||
await asyncExecShell(
|
||||
`DOCKER_HOST=${host} docker compose -f ${hostkeyDir}/${id}-docker-compose.yml up -d`
|
||||
);
|
||||
|
||||
await startTcpProxy(destinationDocker, `${id}-ftp`, publicPort, 22);
|
||||
} else {
|
||||
await db.prisma.wordpress.update({
|
||||
where: { serviceId: id },
|
||||
data: { ftpPublicPort: null }
|
||||
});
|
||||
try {
|
||||
await asyncExecShell(
|
||||
`DOCKER_HOST=${host} docker stop -t 0 ${id}-ftp && docker rm ${id}-ftp`
|
||||
);
|
||||
} catch (error) {
|
||||
//
|
||||
}
|
||||
await stopTcpHttpProxy(destinationDocker, oldPublicPort);
|
||||
}
|
||||
}
|
||||
if (ftpEnabled) {
|
||||
return {
|
||||
status: 201,
|
||||
body: {
|
||||
publicPort,
|
||||
ftpUser,
|
||||
ftpPassword
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
status: 200,
|
||||
body: {}
|
||||
};
|
||||
}
|
||||
return {
|
||||
status: 201
|
||||
};
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
return ErrorHandler(error);
|
||||
} finally {
|
||||
await asyncExecShell(
|
||||
`rm -f ${hostkeyDir}/${id}-docker-compose.yml ${hostkeyDir}/${id}.ed25519 ${hostkeyDir}/${id}.ed25519.pub ${hostkeyDir}/${id}.rsa ${hostkeyDir}/${id}.rsa.pub ${hostkeyDir}/${id}.sh`
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -6,6 +6,7 @@ import type { RequestHandler } from '@sveltejs/kit';
|
||||
import { ErrorHandler, getServiceImage } from '$lib/database';
|
||||
import { makeLabelForServices } from '$lib/buildPacks/common';
|
||||
import type { ComposeFile } from '$lib/types/composeFile';
|
||||
import { getServiceMainPort } from '$lib/components/common';
|
||||
|
||||
export const post: RequestHandler = async (event) => {
|
||||
const { teamId, status, body } = await getUserDetails(event);
|
||||
@@ -22,19 +23,24 @@ export const post: RequestHandler = async (event) => {
|
||||
destinationDockerId,
|
||||
serviceSecret,
|
||||
destinationDocker,
|
||||
exposePort,
|
||||
wordpress: {
|
||||
mysqlDatabase,
|
||||
mysqlHost,
|
||||
mysqlPort,
|
||||
mysqlUser,
|
||||
mysqlPassword,
|
||||
extraConfig,
|
||||
mysqlRootUser,
|
||||
mysqlRootUserPassword
|
||||
mysqlRootUserPassword,
|
||||
ownMysql
|
||||
}
|
||||
} = service;
|
||||
|
||||
const network = destinationDockerId && destinationDocker.network;
|
||||
const host = getEngine(destinationDocker.engine);
|
||||
const image = getServiceImage(type);
|
||||
const port = getServiceMainPort('wordpress');
|
||||
|
||||
const { workdir } = await createDirectories({ repository: type, buildId: id });
|
||||
const config = {
|
||||
@@ -42,7 +48,7 @@ export const post: RequestHandler = async (event) => {
|
||||
image: `${image}:${version}`,
|
||||
volume: `${id}-wordpress-data:/var/www/html`,
|
||||
environmentVariables: {
|
||||
WORDPRESS_DB_HOST: `${id}-mysql`,
|
||||
WORDPRESS_DB_HOST: ownMysql ? `${mysqlHost}:${mysqlPort}` : `${id}-mysql`,
|
||||
WORDPRESS_DB_USER: mysqlUser,
|
||||
WORDPRESS_DB_PASSWORD: mysqlPassword,
|
||||
WORDPRESS_DB_NAME: mysqlDatabase,
|
||||
@@ -66,7 +72,7 @@ export const post: RequestHandler = async (event) => {
|
||||
config.wordpress.environmentVariables[secret.name] = secret.value;
|
||||
});
|
||||
}
|
||||
const composeFile: ComposeFile = {
|
||||
let composeFile: ComposeFile = {
|
||||
version: '3.8',
|
||||
services: {
|
||||
[id]: {
|
||||
@@ -76,7 +82,7 @@ export const post: RequestHandler = async (event) => {
|
||||
volumes: [config.wordpress.volume],
|
||||
networks: [network],
|
||||
restart: 'always',
|
||||
depends_on: [`${id}-mysql`],
|
||||
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
||||
labels: makeLabelForServices('wordpress'),
|
||||
deploy: {
|
||||
restart_policy: {
|
||||
@@ -86,22 +92,6 @@ export const post: RequestHandler = async (event) => {
|
||||
window: '120s'
|
||||
}
|
||||
}
|
||||
},
|
||||
[`${id}-mysql`]: {
|
||||
container_name: `${id}-mysql`,
|
||||
image: config.mysql.image,
|
||||
volumes: [config.mysql.volume],
|
||||
environment: config.mysql.environmentVariables,
|
||||
networks: [network],
|
||||
restart: 'always',
|
||||
deploy: {
|
||||
restart_policy: {
|
||||
condition: 'on-failure',
|
||||
delay: '5s',
|
||||
max_attempts: 3,
|
||||
window: '120s'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
networks: {
|
||||
@@ -112,12 +102,32 @@ export const post: RequestHandler = async (event) => {
|
||||
volumes: {
|
||||
[config.wordpress.volume.split(':')[0]]: {
|
||||
name: config.wordpress.volume.split(':')[0]
|
||||
},
|
||||
[config.mysql.volume.split(':')[0]]: {
|
||||
name: config.mysql.volume.split(':')[0]
|
||||
}
|
||||
}
|
||||
};
|
||||
if (!ownMysql) {
|
||||
composeFile.services[id].depends_on = [`${id}-mysql`];
|
||||
composeFile.services[`${id}-mysql`] = {
|
||||
container_name: `${id}-mysql`,
|
||||
image: config.mysql.image,
|
||||
volumes: [config.mysql.volume],
|
||||
environment: config.mysql.environmentVariables,
|
||||
networks: [network],
|
||||
restart: 'always',
|
||||
deploy: {
|
||||
restart_policy: {
|
||||
condition: 'on-failure',
|
||||
delay: '5s',
|
||||
max_attempts: 3,
|
||||
window: '120s'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
composeFile.volumes[config.mysql.volume.split(':')[0]] = {
|
||||
name: config.mysql.volume.split(':')[0]
|
||||
};
|
||||
}
|
||||
const composeFileDestination = `${workdir}/docker-compose.yaml`;
|
||||
await fs.writeFile(composeFileDestination, yaml.dump(composeFile));
|
||||
try {
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col flex-wrap justify-center">
|
||||
<div class="flex justify-center">
|
||||
{#if !services || ownServices.length === 0}
|
||||
<div class="flex-col">
|
||||
<div class="text-center text-xl font-bold">{$t('service.no_service')}</div>
|
||||
|
||||
@@ -1,25 +1,54 @@
|
||||
import { asyncExecShell, getEngine, getUserDetails } from '$lib/common';
|
||||
import { dev } from '$app/env';
|
||||
import { checkDomainsIsValidInDNS, getDomain, getUserDetails, isDNSValid } from '$lib/common';
|
||||
import * as db from '$lib/database';
|
||||
import { ErrorHandler } from '$lib/database';
|
||||
import { t } from '$lib/translations';
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
|
||||
export const get: RequestHandler = async (event) => {
|
||||
const { status, body } = await getUserDetails(event);
|
||||
if (status === 401) return { status, body };
|
||||
const domain = event.url.searchParams.get('domain');
|
||||
if (!domain) {
|
||||
return {
|
||||
status: 500,
|
||||
body: {
|
||||
message: t.get('application.domain_required')
|
||||
}
|
||||
};
|
||||
}
|
||||
try {
|
||||
await isDNSValid(event, domain);
|
||||
return {
|
||||
status: 200
|
||||
};
|
||||
} catch (error) {
|
||||
return ErrorHandler(error);
|
||||
}
|
||||
};
|
||||
|
||||
export const post: RequestHandler = async (event) => {
|
||||
const { status, body } = await getUserDetails(event);
|
||||
if (status === 401) return { status, body };
|
||||
const { id } = event.params;
|
||||
|
||||
let { fqdn } = await event.request.json();
|
||||
let { fqdn, forceSave, dualCerts, isDNSCheckEnabled } = await event.request.json();
|
||||
if (fqdn) fqdn = fqdn.toLowerCase();
|
||||
|
||||
try {
|
||||
const found = await db.isDomainConfigured({ id, fqdn });
|
||||
console.log(found);
|
||||
if (found) {
|
||||
throw {
|
||||
message: t.get('application.domain_already_in_use', {
|
||||
domain: getDomain(fqdn).replace('www.', '')
|
||||
})
|
||||
};
|
||||
}
|
||||
if (isDNSCheckEnabled && !forceSave) {
|
||||
return await checkDomainsIsValidInDNS({ event, fqdn, dualCerts });
|
||||
}
|
||||
return {
|
||||
status: found ? 500 : 200,
|
||||
body: {
|
||||
error:
|
||||
found && t.get('application.domain_already_in_use', { domain: fqdn.replace('www.', '') })
|
||||
}
|
||||
status: 200
|
||||
};
|
||||
} catch (error) {
|
||||
return ErrorHandler(error);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { dev } from '$app/env';
|
||||
import { getUserDetails } from '$lib/common';
|
||||
import * as db from '$lib/database';
|
||||
import { listSettings, ErrorHandler } from '$lib/database';
|
||||
@@ -71,7 +72,8 @@ export const post: RequestHandler = async (event) => {
|
||||
minPort,
|
||||
maxPort,
|
||||
isAutoUpdateEnabled,
|
||||
isDNSCheckEnabled
|
||||
isDNSCheckEnabled,
|
||||
forceSave
|
||||
} = await event.request.json();
|
||||
try {
|
||||
const { id } = await db.listSettings();
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
import Setting from '$lib/components/Setting.svelte';
|
||||
import Explainer from '$lib/components/Explainer.svelte';
|
||||
import { errorNotification } from '$lib/form';
|
||||
import { del, post } from '$lib/api';
|
||||
import { del, get, post } from '$lib/api';
|
||||
import CopyPasswordField from '$lib/components/CopyPasswordField.svelte';
|
||||
import { browser } from '$app/env';
|
||||
import { getDomain } from '$lib/components/common';
|
||||
@@ -47,7 +47,11 @@
|
||||
let minPort = settings.minPort;
|
||||
let maxPort = settings.maxPort;
|
||||
|
||||
let forceSave = false;
|
||||
let fqdn = settings.fqdn;
|
||||
let nonWWWDomain = fqdn && getDomain(fqdn).replace(/^www\./, '');
|
||||
let isNonWWWDomainOK = false;
|
||||
let isWWWDomainOK = false;
|
||||
let isFqdnSet = !!settings.fqdn;
|
||||
let loading = {
|
||||
save: false,
|
||||
@@ -69,6 +73,7 @@
|
||||
}
|
||||
async function changeSettings(name) {
|
||||
try {
|
||||
resetView();
|
||||
if (name === 'isRegistrationEnabled') {
|
||||
isRegistrationEnabled = !isRegistrationEnabled;
|
||||
}
|
||||
@@ -95,8 +100,10 @@
|
||||
async function handleSubmit() {
|
||||
try {
|
||||
loading.save = true;
|
||||
nonWWWDomain = fqdn && getDomain(fqdn).replace(/^www\./, '');
|
||||
|
||||
if (fqdn !== settings.fqdn) {
|
||||
await post(`/settings/check.json`, { fqdn });
|
||||
await post(`/settings/check.json`, { fqdn, forceSave, dualCerts, isDNSCheckEnabled });
|
||||
await post(`/settings.json`, { fqdn });
|
||||
return window.location.reload();
|
||||
}
|
||||
@@ -105,12 +112,50 @@
|
||||
settings.minPort = minPort;
|
||||
settings.maxPort = maxPort;
|
||||
}
|
||||
forceSave = false;
|
||||
} catch ({ error }) {
|
||||
if (error?.startsWith($t('application.dns_not_set_partial_error'))) {
|
||||
forceSave = true;
|
||||
if (dualCerts) {
|
||||
isNonWWWDomainOK = await isDNSValid(getDomain(nonWWWDomain), false);
|
||||
isWWWDomainOK = await isDNSValid(getDomain(`www.${nonWWWDomain}`), true);
|
||||
} else {
|
||||
const isWWW = getDomain(settings.fqdn).includes('www.');
|
||||
if (isWWW) {
|
||||
isWWWDomainOK = await isDNSValid(getDomain(`www.${nonWWWDomain}`), true);
|
||||
} else {
|
||||
isNonWWWDomainOK = await isDNSValid(getDomain(nonWWWDomain), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
return errorNotification(error);
|
||||
} finally {
|
||||
loading.save = false;
|
||||
}
|
||||
}
|
||||
async function renewCerts() {
|
||||
try {
|
||||
toast.push('Renewing certificates...');
|
||||
return await post(`/settings/renew.json`, {});
|
||||
} catch ({ error }) {
|
||||
return errorNotification(error);
|
||||
}
|
||||
}
|
||||
async function isDNSValid(domain, isWWW) {
|
||||
try {
|
||||
await get(`/settings/check.json?domain=${domain}`);
|
||||
toast.push('DNS configuration is valid.');
|
||||
isWWW ? (isWWWDomainOK = true) : (isNonWWWDomainOK = true);
|
||||
return true;
|
||||
} catch ({ error }) {
|
||||
errorNotification(error);
|
||||
isWWW ? (isWWWDomainOK = false) : (isNonWWWDomainOK = false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
function resetView() {
|
||||
forceSave = false;
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="flex space-x-1 p-6 font-bold">
|
||||
@@ -123,11 +168,18 @@
|
||||
<div class="title font-bold">{$t('index.global_settings')}</div>
|
||||
<button
|
||||
type="submit"
|
||||
class:bg-green-600={!loading.save}
|
||||
class:bg-orange-600={forceSave}
|
||||
class:hover:bg-green-500={!loading.save}
|
||||
class:hover:bg-orange-400={forceSave}
|
||||
disabled={loading.save}
|
||||
class:bg-yellow-500={!loading.save}
|
||||
class:hover:bg-yellow-400={!loading.save}
|
||||
class="mx-2 ">{loading.save ? $t('forms.saving') : $t('forms.save')}</button
|
||||
>{loading.save
|
||||
? $t('forms.saving')
|
||||
: forceSave
|
||||
? $t('forms.confirm_continue')
|
||||
: $t('forms.save')}</button
|
||||
>
|
||||
|
||||
{#if isFqdnSet}
|
||||
<button
|
||||
on:click|preventDefault={removeFqdn}
|
||||
@@ -152,11 +204,47 @@
|
||||
bind:value={fqdn}
|
||||
readonly={!$session.isAdmin || isFqdnSet}
|
||||
disabled={!$session.isAdmin || isFqdnSet}
|
||||
on:input={resetView}
|
||||
name="fqdn"
|
||||
id="fqdn"
|
||||
pattern="^https?://([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{'{'}2,{'}'}$"
|
||||
placeholder="{$t('forms.eg')}: https://coolify.io"
|
||||
/>
|
||||
|
||||
{#if forceSave}
|
||||
<div class="flex-col space-y-2 pt-4 text-center">
|
||||
{#if isNonWWWDomainOK}
|
||||
<button
|
||||
class="bg-green-600 hover:bg-green-500"
|
||||
on:click|preventDefault={() => isDNSValid(getDomain(nonWWWDomain), false)}
|
||||
>DNS settings for {nonWWWDomain} is OK, click to recheck.</button
|
||||
>
|
||||
{:else}
|
||||
<button
|
||||
class="bg-red-600 hover:bg-red-500"
|
||||
on:click|preventDefault={() => isDNSValid(getDomain(nonWWWDomain), false)}
|
||||
>DNS settings for {nonWWWDomain} is invalid, click to recheck.</button
|
||||
>
|
||||
{/if}
|
||||
{#if dualCerts}
|
||||
{#if isWWWDomainOK}
|
||||
<button
|
||||
class="bg-green-600 hover:bg-green-500"
|
||||
on:click|preventDefault={() =>
|
||||
isDNSValid(getDomain(`www.${nonWWWDomain}`), true)}
|
||||
>DNS settings for www.{nonWWWDomain} is OK, click to recheck.</button
|
||||
>
|
||||
{:else}
|
||||
<button
|
||||
class="bg-red-600 hover:bg-red-500"
|
||||
on:click|preventDefault={() =>
|
||||
isDNSValid(getDomain(`www.${nonWWWDomain}`), true)}
|
||||
>DNS settings for www.{nonWWWDomain} is invalid, click to recheck.</button
|
||||
>
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-start py-6">
|
||||
@@ -219,6 +307,19 @@
|
||||
on:click={() => changeSettings('isAutoUpdateEnabled')}
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<div class="flex flex-col">
|
||||
<div class="pt-2 text-base font-bold text-stone-100">
|
||||
Renew SSL Certificates manually
|
||||
</div>
|
||||
<Explainer text="It will check and renew certificates manually" />
|
||||
</div>
|
||||
<div class="mx-auto ">
|
||||
<button class="w-32 bg-coollabs hover:bg-coollabs-100" on:click={renewCerts}
|
||||
>SSL renew manually</button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</form>
|
||||
|
||||
26
src/routes/settings/renew.json.ts
Normal file
26
src/routes/settings/renew.json.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { getUserDetails } from '$lib/common';
|
||||
import { ErrorHandler } from '$lib/database';
|
||||
import { renewSSLCerts } from '$lib/letsencrypt';
|
||||
import { t } from '$lib/translations';
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
|
||||
export const post: RequestHandler = async (event) => {
|
||||
const { teamId, status, body } = await getUserDetails(event);
|
||||
if (teamId !== '0')
|
||||
return {
|
||||
status: 401,
|
||||
body: {
|
||||
message: t.get('setting.permission_denied')
|
||||
}
|
||||
};
|
||||
if (status === 401) return { status, body };
|
||||
|
||||
try {
|
||||
renewSSLCerts();
|
||||
return {
|
||||
status: 201
|
||||
};
|
||||
} catch (error) {
|
||||
return ErrorHandler(error);
|
||||
}
|
||||
};
|
||||
@@ -68,10 +68,48 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="flex space-x-1 p-6 px-6 text-2xl font-bold">
|
||||
<div class="tracking-tight">{$t('application.git_source')}</div>
|
||||
<span class="arrow-right-applications px-1 text-orange-500">></span>
|
||||
<span class="pr-2">{source.name}</span>
|
||||
<div class="flex h-20 items-center space-x-2 p-5 px-6 font-bold">
|
||||
<div class="-mb-5 flex-col">
|
||||
<div class="md:max-w-64 truncate text-base tracking-tight md:text-2xl lg:block">
|
||||
Configuration
|
||||
</div>
|
||||
<span class="text-xs">{source.name}</span>
|
||||
</div>
|
||||
{#if source?.type === 'gitlab'}
|
||||
<svg viewBox="0 0 128 128" class="w-8">
|
||||
<path
|
||||
fill="#FC6D26"
|
||||
d="M126.615 72.31l-7.034-21.647L105.64 7.76c-.716-2.206-3.84-2.206-4.556 0l-13.94 42.903H40.856L26.916 7.76c-.717-2.206-3.84-2.206-4.557 0L8.42 50.664 1.385 72.31a4.792 4.792 0 001.74 5.358L64 121.894l60.874-44.227a4.793 4.793 0 001.74-5.357"
|
||||
/><path fill="#E24329" d="M64 121.894l23.144-71.23H40.856L64 121.893z" /><path
|
||||
fill="#FC6D26"
|
||||
d="M64 121.894l-23.144-71.23H8.42L64 121.893z"
|
||||
/><path
|
||||
fill="#FCA326"
|
||||
d="M8.42 50.663L1.384 72.31a4.79 4.79 0 001.74 5.357L64 121.894 8.42 50.664z"
|
||||
/><path
|
||||
fill="#E24329"
|
||||
d="M8.42 50.663h32.436L26.916 7.76c-.717-2.206-3.84-2.206-4.557 0L8.42 50.664z"
|
||||
/><path fill="#FC6D26" d="M64 121.894l23.144-71.23h32.437L64 121.893z" /><path
|
||||
fill="#FCA326"
|
||||
d="M119.58 50.663l7.035 21.647a4.79 4.79 0 01-1.74 5.357L64 121.894l55.58-71.23z"
|
||||
/><path
|
||||
fill="#E24329"
|
||||
d="M119.58 50.663H87.145l13.94-42.902c.717-2.206 3.84-2.206 4.557 0l13.94 42.903z"
|
||||
/>
|
||||
</svg>
|
||||
{:else if source?.type === 'github'}
|
||||
<svg viewBox="0 0 128 128" class="w-8">
|
||||
<g fill="#ffffff"
|
||||
><path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M64 5.103c-33.347 0-60.388 27.035-60.388 60.388 0 26.682 17.303 49.317 41.297 57.303 3.017.56 4.125-1.31 4.125-2.905 0-1.44-.056-6.197-.082-11.243-16.8 3.653-20.345-7.125-20.345-7.125-2.747-6.98-6.705-8.836-6.705-8.836-5.48-3.748.413-3.67.413-3.67 6.063.425 9.257 6.223 9.257 6.223 5.386 9.23 14.127 6.562 17.573 5.02.542-3.903 2.107-6.568 3.834-8.076-13.413-1.525-27.514-6.704-27.514-29.843 0-6.593 2.36-11.98 6.223-16.21-.628-1.52-2.695-7.662.584-15.98 0 0 5.07-1.623 16.61 6.19C53.7 35 58.867 34.327 64 34.304c5.13.023 10.3.694 15.127 2.033 11.526-7.813 16.59-6.19 16.59-6.19 3.287 8.317 1.22 14.46.593 15.98 3.872 4.23 6.215 9.617 6.215 16.21 0 23.194-14.127 28.3-27.574 29.796 2.167 1.874 4.097 5.55 4.097 11.183 0 8.08-.07 14.583-.07 16.572 0 1.607 1.088 3.49 4.148 2.897 23.98-7.994 41.263-30.622 41.263-57.294C124.388 32.14 97.35 5.104 64 5.104z"
|
||||
/><path
|
||||
d="M26.484 91.806c-.133.3-.605.39-1.035.185-.44-.196-.685-.605-.543-.906.13-.31.603-.395 1.04-.188.44.197.69.61.537.91zm2.446 2.729c-.287.267-.85.143-1.232-.28-.396-.42-.47-.983-.177-1.254.298-.266.844-.14 1.24.28.394.426.472.984.17 1.255zM31.312 98.012c-.37.258-.976.017-1.35-.52-.37-.538-.37-1.183.01-1.44.373-.258.97-.025 1.35.507.368.545.368 1.19-.01 1.452zm3.261 3.361c-.33.365-1.036.267-1.552-.23-.527-.487-.674-1.18-.343-1.544.336-.366 1.045-.264 1.564.23.527.486.686 1.18.333 1.543zm4.5 1.951c-.147.473-.825.688-1.51.486-.683-.207-1.13-.76-.99-1.238.14-.477.823-.7 1.512-.485.683.206 1.13.756.988 1.237zm4.943.361c.017.498-.563.91-1.28.92-.723.017-1.308-.387-1.315-.877 0-.503.568-.91 1.29-.924.717-.013 1.306.387 1.306.88zm4.598-.782c.086.485-.413.984-1.126 1.117-.7.13-1.35-.172-1.44-.653-.086-.498.422-.997 1.122-1.126.714-.123 1.354.17 1.444.663zm0 0"
|
||||
/></g
|
||||
>
|
||||
</svg>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col justify-center">
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="flex flex-col flex-wrap justify-center">
|
||||
<div class="flex justify-center">
|
||||
{#if !sources || ownSources.length === 0}
|
||||
<div class="flex-col">
|
||||
<div class="text-center text-xl font-bold">{$t('source.no_git_sources_found')}</div>
|
||||
@@ -74,11 +74,48 @@
|
||||
{#each ownSources as source}
|
||||
<a href="/sources/{source.id}" class="w-96 p-2 no-underline">
|
||||
<div
|
||||
class="box-selection group hover:bg-orange-600"
|
||||
class="box-selection group relative hover:bg-orange-600"
|
||||
class:border-red-500={source.gitlabApp && !source.gitlabAppId}
|
||||
class:border-0={source.gitlabApp && !source.gitlabAppId}
|
||||
class:border-l-4={source.gitlabApp && !source.gitlabAppId}
|
||||
>
|
||||
<div class="absolute top-0 left-0 -m-5 h-10 w-10">
|
||||
{#if source?.type === 'gitlab'}
|
||||
<svg viewBox="0 0 128 128">
|
||||
<path
|
||||
fill="#FC6D26"
|
||||
d="M126.615 72.31l-7.034-21.647L105.64 7.76c-.716-2.206-3.84-2.206-4.556 0l-13.94 42.903H40.856L26.916 7.76c-.717-2.206-3.84-2.206-4.557 0L8.42 50.664 1.385 72.31a4.792 4.792 0 001.74 5.358L64 121.894l60.874-44.227a4.793 4.793 0 001.74-5.357"
|
||||
/><path fill="#E24329" d="M64 121.894l23.144-71.23H40.856L64 121.893z" /><path
|
||||
fill="#FC6D26"
|
||||
d="M64 121.894l-23.144-71.23H8.42L64 121.893z"
|
||||
/><path
|
||||
fill="#FCA326"
|
||||
d="M8.42 50.663L1.384 72.31a4.79 4.79 0 001.74 5.357L64 121.894 8.42 50.664z"
|
||||
/><path
|
||||
fill="#E24329"
|
||||
d="M8.42 50.663h32.436L26.916 7.76c-.717-2.206-3.84-2.206-4.557 0L8.42 50.664z"
|
||||
/><path fill="#FC6D26" d="M64 121.894l23.144-71.23h32.437L64 121.893z" /><path
|
||||
fill="#FCA326"
|
||||
d="M119.58 50.663l7.035 21.647a4.79 4.79 0 01-1.74 5.357L64 121.894l55.58-71.23z"
|
||||
/><path
|
||||
fill="#E24329"
|
||||
d="M119.58 50.663H87.145l13.94-42.902c.717-2.206 3.84-2.206 4.557 0l13.94 42.903z"
|
||||
/>
|
||||
</svg>
|
||||
{:else if source?.type === 'github'}
|
||||
<svg viewBox="0 0 128 128">
|
||||
<g fill="#ffffff"
|
||||
><path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M64 5.103c-33.347 0-60.388 27.035-60.388 60.388 0 26.682 17.303 49.317 41.297 57.303 3.017.56 4.125-1.31 4.125-2.905 0-1.44-.056-6.197-.082-11.243-16.8 3.653-20.345-7.125-20.345-7.125-2.747-6.98-6.705-8.836-6.705-8.836-5.48-3.748.413-3.67.413-3.67 6.063.425 9.257 6.223 9.257 6.223 5.386 9.23 14.127 6.562 17.573 5.02.542-3.903 2.107-6.568 3.834-8.076-13.413-1.525-27.514-6.704-27.514-29.843 0-6.593 2.36-11.98 6.223-16.21-.628-1.52-2.695-7.662.584-15.98 0 0 5.07-1.623 16.61 6.19C53.7 35 58.867 34.327 64 34.304c5.13.023 10.3.694 15.127 2.033 11.526-7.813 16.59-6.19 16.59-6.19 3.287 8.317 1.22 14.46.593 15.98 3.872 4.23 6.215 9.617 6.215 16.21 0 23.194-14.127 28.3-27.574 29.796 2.167 1.874 4.097 5.55 4.097 11.183 0 8.08-.07 14.583-.07 16.572 0 1.607 1.088 3.49 4.148 2.897 23.98-7.994 41.263-30.622 41.263-57.294C124.388 32.14 97.35 5.104 64 5.104z"
|
||||
/><path
|
||||
d="M26.484 91.806c-.133.3-.605.39-1.035.185-.44-.196-.685-.605-.543-.906.13-.31.603-.395 1.04-.188.44.197.69.61.537.91zm2.446 2.729c-.287.267-.85.143-1.232-.28-.396-.42-.47-.983-.177-1.254.298-.266.844-.14 1.24.28.394.426.472.984.17 1.255zM31.312 98.012c-.37.258-.976.017-1.35-.52-.37-.538-.37-1.183.01-1.44.373-.258.97-.025 1.35.507.368.545.368 1.19-.01 1.452zm3.261 3.361c-.33.365-1.036.267-1.552-.23-.527-.487-.674-1.18-.343-1.544.336-.366 1.045-.264 1.564.23.527.486.686 1.18.333 1.543zm4.5 1.951c-.147.473-.825.688-1.51.486-.683-.207-1.13-.76-.99-1.238.14-.477.823-.7 1.512-.485.683.206 1.13.756.988 1.237zm4.943.361c.017.498-.563.91-1.28.92-.723.017-1.308-.387-1.315-.877 0-.503.568-.91 1.29-.924.717-.013 1.306.387 1.306.88zm4.598-.782c.086.485-.413.984-1.126 1.117-.7.13-1.35-.172-1.44-.653-.086-.498.422-.997 1.122-1.126.714-.123 1.354.17 1.444.663zm0 0"
|
||||
/></g
|
||||
>
|
||||
</svg>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="truncate text-center text-xl font-bold">{source.name}</div>
|
||||
{#if $session.teamId === '0' && otherSources.length > 0}
|
||||
<div class="truncate text-center">{source.teams[0].name}</div>
|
||||
|
||||
@@ -2,6 +2,7 @@ import { dev } from '$app/env';
|
||||
import { asyncExecShell, version } from '$lib/common';
|
||||
import { asyncSleep } from '$lib/components/common';
|
||||
import { ErrorHandler } from '$lib/database';
|
||||
import * as db from '$lib/database';
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
import compare from 'compare-versions';
|
||||
import got from 'got';
|
||||
@@ -36,8 +37,12 @@ export const post: RequestHandler = async (event) => {
|
||||
if (type === 'update') {
|
||||
try {
|
||||
if (!dev) {
|
||||
const { isAutoUpdateEnabled } = await db.prisma.setting.findFirst();
|
||||
await asyncExecShell(`docker pull coollabsio/coolify:${latestVersion}`);
|
||||
await asyncExecShell(`env | grep COOLIFY > .env`);
|
||||
await asyncExecShell(
|
||||
`sed -i '/COOLIFY_AUTO_UPDATE=/c\COOLIFY_AUTO_UPDATE=${isAutoUpdateEnabled}' .env`
|
||||
);
|
||||
await asyncExecShell(
|
||||
`docker run --rm -tid --env-file .env -v /var/run/docker.sock:/var/run/docker.sock -v coolify-db coollabsio/coolify:${latestVersion} /bin/sh -c "env | grep COOLIFY > .env && echo 'TAG=${latestVersion}' >> .env && docker stop -t 0 coolify coolify-redis && docker rm coolify coolify-redis && docker compose up -d --force-recreate"`
|
||||
);
|
||||
|
||||
@@ -73,6 +73,7 @@ export const post: RequestHandler = async (event) => {
|
||||
JSON.stringify({
|
||||
buildPack: applicationFound.buildPack,
|
||||
port: applicationFound.port,
|
||||
exposePort: applicationFound.exposePort,
|
||||
installCommand: applicationFound.installCommand,
|
||||
buildCommand: applicationFound.buildCommand,
|
||||
startCommand: applicationFound.startCommand
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user