Merge pull request #416 from coollabsio/next

v2.8.0
This commit is contained in:
Andras Bacsai 2022-05-10 11:50:07 +02:00 committed by GitHub
commit 79dfc6a660
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 1310 additions and 622 deletions

View File

@ -1,7 +1,7 @@
{
"name": "coolify",
"description": "An open-source & self-hostable Heroku / Netlify alternative.",
"version": "2.7.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,61 +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",
"is-ip": "^4.0.0",
"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"
},

View File

@ -3,25 +3,25 @@ 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,92 +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
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_r3ph5xlwsrsg4ewthrjemd3cfq
'@typescript-eslint/parser': 4.31.1_hrkuebk64jiu2ut2d2sm4oylnu
'@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_4oxeyilw5mxcaksmcxtpjddhfe
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_sqtt6dzjlskmywoml5ykunxlce
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_cp6olp7pwsfaq5mjijwt65d6uy
svelte-preprocess: 4.10.6_igaqrb5onrwvsmrrc32h4m72ha
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_3z6inmgn4ud4moqealnfxgbl2m
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:
@ -285,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
@ -342,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
@ -378,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
@ -400,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==
@ -419,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
@ -492,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
@ -503,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
@ -530,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:
@ -561,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:
@ -570,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_r3ph5xlwsrsg4ewthrjemd3cfq:
/@typescript-eslint/eslint-plugin/4.31.1_lii63oz3usekbu5ehvrcuwn5jy:
resolution:
{
integrity: sha512-UDqhWmd5i0TvPLmbK5xY3UZB0zEGseF+DHPghZ37Sb83Qd3p8ujhvAtkU4OF46Ka5Pm5kWvFIx0cCTBFKo0alA==
@ -587,21 +590,21 @@ packages:
typescript:
optional: true
dependencies:
'@typescript-eslint/experimental-utils': 4.31.1_hrkuebk64jiu2ut2d2sm4oylnu
'@typescript-eslint/parser': 4.31.1_hrkuebk64jiu2ut2d2sm4oylnu
'@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_hrkuebk64jiu2ut2d2sm4oylnu:
/@typescript-eslint/experimental-utils/4.31.1_e4zyhrvfnqudwdx5bevnvkluy4:
resolution:
{
integrity: sha512-NtoPsqmcSsWty0mcL5nTZXMf7Ei0Xr2MT8jWjXMVgRK0/1qeQ2jZzLFUh4QtyJ4+/lPUyMw5cSfeeME+Zrtp9Q==
@ -613,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
@ -622,7 +625,7 @@ packages:
- typescript
dev: true
/@typescript-eslint/parser/4.31.1_hrkuebk64jiu2ut2d2sm4oylnu:
/@typescript-eslint/parser/4.31.1_e4zyhrvfnqudwdx5bevnvkluy4:
resolution:
{
integrity: sha512-dnVZDB6FhpIby6yVbHkwTKkn2ypjVIfAR9nh+kYsA/ZL0JlTsd22BiDjouotisY3Irmd3OW1qlk9EI5R8GrvRQ==
@ -637,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
@ -664,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==
@ -682,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
@ -956,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
@ -1653,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
@ -1686,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
@ -1753,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
@ -2048,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
@ -2267,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
@ -2615,7 +2618,7 @@ packages:
eslint: 7.32.0
dev: true
/eslint-plugin-svelte3/3.4.1_4oxeyilw5mxcaksmcxtpjddhfe:
/eslint-plugin-svelte3/3.4.1_6wevxxng4y4ff26nzlndg2wnpa:
resolution:
{
integrity: sha512-7p59WG8qV8L6wLdl4d/c3mdjkgVglQCdv5XOTk/iNPBKXuuV+Q0eFP5Wa6iJd/G2M1qR3BkLPEzaANOqKAZczw==
@ -2626,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:
@ -3080,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:
@ -3544,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
@ -3884,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
@ -3914,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
@ -4110,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==
@ -4120,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_ysmyu6g5dtd6yanj6zrab4uqoy:
/postcss-load-config/3.1.4_4jqnslpwnj4ifyjfqbkuebd4fy:
resolution:
{
integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==
@ -4139,12 +4149,12 @@ packages:
optional: true
dependencies:
lilconfig: 2.0.5
postcss: 8.4.12
ts-node: 10.7.0_3z6inmgn4ud4moqealnfxgbl2m
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==
@ -4153,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
@ -4175,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
@ -4195,7 +4205,7 @@ packages:
engines: { node: '>= 0.8.0' }
dev: true
/prettier-plugin-svelte/2.7.0_sqtt6dzjlskmywoml5ykunxlce:
/prettier-plugin-svelte/2.7.0_kkjbqzpydplecjtkxrgomroeru:
resolution:
{
integrity: sha512-fQhhZICprZot2IqEyoiUYLTRdumULGRvw0o4dzl5jt0jfzVWdGqeYW27QTWAeXhoupEZJULmNoH3ueJwUWFLIA==
@ -4205,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:
@ -4513,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:
@ -4878,7 +4888,7 @@ packages:
engines: { node: '>= 0.4' }
dev: true
/svelte-check/2.7.0_cp6olp7pwsfaq5mjijwt65d6uy:
/svelte-check/2.7.0_f2ke6qjyzu5axsjd6yk3u4tn7a:
resolution:
{
integrity: sha512-GrvG24j0+i8AOm0k0KyJ6Dqc+TAR2yzB7rtS4nljHStunVxCTr/1KYlv4EsOeoqtHLzeWMOd5D2O6nDdP/yw4A==
@ -4893,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_igaqrb5onrwvsmrrc32h4m72ha
typescript: 4.6.3
svelte: 3.48.0
svelte-preprocess: 4.10.6_nq4dx2skq5drra53vttuo4lltu
typescript: 4.6.4
transitivePeerDependencies:
- '@babel/core'
- coffeescript
@ -4909,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==
@ -4917,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_igaqrb5onrwvsmrrc32h4m72ha:
/svelte-preprocess/4.10.6_nq4dx2skq5drra53vttuo4lltu:
resolution:
{
integrity: sha512-I2SV1w/AveMvgIQlUF/ZOO3PYVnhxfcpNyGt8pxpUVhPfyfL/CZBkkw/KPfuFix5FJ9TnnNYMhACK3DtSaYVVQ==
@ -4975,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:
@ -4989,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:
@ -5057,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_ysmyu6g5dtd6yanj6zrab4uqoy
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
@ -5133,7 +5143,7 @@ packages:
engines: { node: '>=0.10.0' }
dev: true
/ts-node/10.7.0_3z6inmgn4ud4moqealnfxgbl2m:
/ts-node/10.7.0_l47be6km5p57gglrggidw5gsgm:
resolution:
{
integrity: sha512-TbIGS4xgJoX2i3do417KSaep1uRAW/Lu+WAL2doDHC0D6ummjirVOXU5/7aiZotbQ5p1Zp9tP7U6cYhA0O7M8A==
@ -5155,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
@ -5173,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==
@ -5190,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:
@ -5223,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
@ -5303,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:

View File

@ -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;

View File

@ -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;

View File

@ -322,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())
@ -352,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

View File

@ -405,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,
@ -426,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';

View File

@ -3,13 +3,88 @@
</script>
<svg
class={isAbsolute ? 'absolute top-0 left-0 -m-10 h-20 w-20' : 'mx-auto w-8 h-8'}
id="Layer_1"
data-name="Layer 1"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 361.67651 499.33603"
><path
d="M203.77731,148.85754c-10.8147-12.762-20.13269-25.8139-22.02478-28.49224a.426.426,0,0,0-.70032.00006c-1.89172,2.6784-11.20758,15.73022-22.02191,28.49218-92.69141,118.085,14.62982,197.75507,14.62982,197.75507l.87.60461c.8136,12.32624,2.83508,30.041,2.83508,30.041H185.442s2.01282-17.63849,2.83-29.96106l.87549-.68451S296.46774,266.94257,203.77731,148.85754ZM181.404,344.88123h-.001s-4.811-4.10383-6.10962-6.16l-.01172-.22131,5.81946-128.56055a.30281.30281,0,0,1,.605,0l5.81946,128.56036-.01135.22065C186.21652,340.77625,181.404,344.88123,181.404,344.88123Z"
fill="#00684a"
/></svg
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
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
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>

View File

@ -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"
/>

View File

@ -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
};

View File

@ -28,7 +28,7 @@ if (!dev) {
}
export const prisma = new PrismaClient({
errorFormat: 'pretty',
errorFormat: 'minimal',
rejectOnNotFound: false
});

View File

@ -329,7 +329,8 @@ export async function updatePlausibleAnalyticsService({
email,
exposePort,
username,
name
name,
scriptName
}: {
id: string;
fqdn: string;
@ -337,8 +338,12 @@ export async function updatePlausibleAnalyticsService({
name: string;
email: string;
username: string;
scriptName: string;
}): Promise<void> {
await prisma.plausibleAnalytics.update({ where: { serviceId: id }, data: { email, username } });
await prisma.plausibleAnalytics.update({
where: { serviceId: id },
data: { email, username, scriptName }
});
await prisma.service.update({ where: { id }, data: { name, fqdn, exposePort } });
}
@ -414,7 +419,9 @@ export async function updateWordpress({
name,
exposePort,
mysqlDatabase,
extraConfig
extraConfig,
mysqlHost,
mysqlPort
}: {
id: string;
fqdn: string;
@ -422,10 +429,24 @@ export async function updateWordpress({
exposePort?: number;
mysqlDatabase: string;
extraConfig: string;
mysqlHost?: string;
mysqlPort?: number;
}): Promise<Service> {
return await prisma.service.update({
where: { id },
data: { fqdn, name, exposePort, wordpress: { update: { mysqlDatabase, extraConfig } } }
data: {
fqdn,
name,
exposePort,
wordpress: {
update: {
mysqlDatabase,
extraConfig,
mysqlHost,
mysqlPort
}
}
}
});
}

View File

@ -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
});
}
}

39
src/routes/_Trend.svelte Normal file
View 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}

View File

@ -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"

View File

@ -358,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"
@ -525,7 +527,8 @@
<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}
readonly={!$session.isAdmin && !isRunning}
disabled={!$session.isAdmin || isRunning}
name="exposePort"
id="exposePort"
bind:value={application.exposePort}

View File

@ -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>

View File

@ -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>

View File

@ -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);
}
}
};

View File

@ -47,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>

View File

@ -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">

View File

@ -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>

View File

@ -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> -->

View File

@ -27,7 +27,6 @@
let loading = false;
let loadingVerification = false;
let dualCerts = service.dualCerts;
let showExposePort = service.exposePort !== null;
async function handleSubmit() {
loading = true;
@ -161,34 +160,23 @@
on:click={() => !isRunning && changeSettings('dualCerts')}
/>
</div>
<div class="grid grid-cols-2 items-center">
<Setting
isCenter={false}
bind:setting={showExposePort}
on:click={() => {
showExposePort = !showExposePort;
service.exposePort = undefined;
}}
title={$t('application.expose_a_port')}
description="Expose a port to the host system"
<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 showExposePort}
<div class="grid grid-cols-2 items-center">
<label for="exposePort" class="text-base font-bold text-stone-100">Expose Port</label>
<input
readonly={!$session.isAdmin}
name="exposePort"
id="exposePort"
bind:value={service.exposePort}
placeholder="12345"
/>
</div>
{/if}
{#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'}

View File

@ -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}
/>

View File

@ -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',

View File

@ -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',

View File

@ -65,7 +65,7 @@ export const post: RequestHandler = async (event) => {
networks: [network],
volumes: [config.volume],
restart: 'always',
...(exposePort && { ports: [`${port}:${port}`] }),
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
labels: makeLabelForServices('minio'),
deploy: {
restart_policy: {

View File

@ -48,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',

View File

@ -12,15 +12,28 @@ export const post: RequestHandler = async (event) => {
name,
fqdn,
exposePort,
plausibleAnalytics: { email, username }
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, exposePort });
await db.updatePlausibleAnalyticsService({
id,
fqdn,
name,
email,
username,
exposePort,
scriptName
});
return { status: 201 };
} catch (error) {
return ErrorHandler(error);

View File

@ -135,7 +135,7 @@ COPY ./init-db.sh /docker-entrypoint-initdb.d/init-db.sh`;
networks: [network],
environment: config.plausibleAnalytics.environmentVariables,
restart: 'always',
...(exposePort && { ports: [`${port}:${exposePort}`] }),
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
depends_on: [`${id}-postgresql`, `${id}-clickhouse`],
labels: makeLabelForServices('plausibleAnalytics'),
deploy: {
@ -195,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(

View File

@ -159,7 +159,7 @@ export const post: RequestHandler = async (event) => {
networks: [network],
volumes: [],
restart: 'always',
...(exposePort ? { ports: [`${port}:${port}`] } : {}),
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
labels: makeLabelForServices('umami'),
deploy: {
restart_policy: {

View File

@ -78,7 +78,7 @@ export const post: RequestHandler = async (event) => {
networks: [network],
volumes: [config.volume, ...volumes],
restart: 'always',
...(exposePort ? { ports: [`${port}:${exposePort}`] } : {}),
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
labels: makeLabelForServices('vscodeServer'),
deploy: {
restart_policy: {

View 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`
);
}
};

View File

@ -12,13 +12,24 @@ export const post: RequestHandler = async (event) => {
name,
fqdn,
exposePort,
wordpress: { extraConfig, mysqlDatabase }
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, exposePort });
await db.updateWordpress({
id,
fqdn,
name,
extraConfig,
mysqlDatabase,
exposePort,
mysqlHost,
mysqlPort
});
return { status: 201 };
} catch (error) {
return ErrorHandler(error);

View File

@ -16,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`
);
}
};

View File

@ -26,11 +26,14 @@ export const post: RequestHandler = async (event) => {
exposePort,
wordpress: {
mysqlDatabase,
mysqlHost,
mysqlPort,
mysqlUser,
mysqlPassword,
extraConfig,
mysqlRootUser,
mysqlRootUserPassword
mysqlRootUserPassword,
ownMysql
}
} = service;
@ -45,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,
@ -69,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]: {
@ -79,8 +82,7 @@ export const post: RequestHandler = async (event) => {
volumes: [config.wordpress.volume],
networks: [network],
restart: 'always',
...(exposePort ? { ports: [`${port}:${port}`] } : {}),
depends_on: [`${id}-mysql`],
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
labels: makeLabelForServices('wordpress'),
deploy: {
restart_policy: {
@ -90,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: {
@ -116,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 {

View File

@ -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>

View File

@ -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">

View File

@ -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>

View File

@ -107,7 +107,7 @@ .title {
@apply mr-4 text-base tracking-tight md:text-2xl;
}
.nav-main {
@apply fixed top-0 left-0 min-h-screen w-16 min-w-[4rem] border-r border-stone-800 bg-coolgray-200;
@apply fixed top-0 left-0 min-h-screen w-16 min-w-[4rem] overflow-auto border-r border-stone-800 bg-coolgray-200 scrollbar-w-1 scrollbar-thumb-coollabs scrollbar-track-coolgray-200 xl:overflow-visible;
}
.nav-side {
@ -356,7 +356,7 @@ .tooltip-right:after {
}
.box-selection {
@apply min-w-[16rem] max-w-[24rem] justify-center rounded-lg border-transparent bg-coolgray-200 p-6 shadow-lg transition duration-150 hover:scale-105 hover:border-transparent hover:bg-coolgray-400;
@apply min-w-[16rem] max-w-[24rem] justify-center rounded border-transparent bg-coolgray-200 p-6 hover:border-transparent hover:bg-coolgray-400;
}
._toastBar {