WIP: Notifications and application usage

This commit is contained in:
Andras Bacsai 2022-05-17 10:14:06 +02:00
parent 1ec620be4b
commit 35b31dce2b
15 changed files with 349 additions and 128 deletions

View File

@ -30,11 +30,11 @@
}, },
"devDependencies": { "devDependencies": {
"@sveltejs/adapter-node": "1.0.0-next.73", "@sveltejs/adapter-node": "1.0.0-next.73",
"@sveltejs/adapter-static": "1.0.0-next.29", "@sveltejs/adapter-static": "1.0.0-next.31",
"@sveltejs/kit": "1.0.0-next.326", "@sveltejs/kit": "1.0.0-next.334",
"@types/js-cookie": "3.0.2", "@types/js-cookie": "3.0.2",
"@types/js-yaml": "4.0.5", "@types/js-yaml": "4.0.5",
"@types/node": "17.0.31", "@types/node": "17.0.34",
"@types/node-forge": "1.0.2", "@types/node-forge": "1.0.2",
"@typescript-eslint/eslint-plugin": "4.31.1", "@typescript-eslint/eslint-plugin": "4.31.1",
"@typescript-eslint/parser": "4.31.1", "@typescript-eslint/parser": "4.31.1",
@ -50,10 +50,10 @@
"postcss": "8.4.13", "postcss": "8.4.13",
"prettier": "2.6.2", "prettier": "2.6.2",
"prettier-plugin-svelte": "2.7.0", "prettier-plugin-svelte": "2.7.0",
"prettier-plugin-tailwindcss": "0.1.10", "prettier-plugin-tailwindcss": "0.1.11",
"prisma": "3.11.1", "prisma": "3.11.1",
"svelte": "3.48.0", "svelte": "3.48.0",
"svelte-check": "2.7.0", "svelte-check": "2.7.1",
"svelte-preprocess": "4.10.6", "svelte-preprocess": "4.10.6",
"svelte-select": "4.4.7", "svelte-select": "4.4.7",
"sveltekit-i18n": "2.2.1", "sveltekit-i18n": "2.2.1",
@ -68,7 +68,7 @@
"@prisma/client": "3.11.1", "@prisma/client": "3.11.1",
"@sentry/node": "6.19.7", "@sentry/node": "6.19.7",
"bcryptjs": "2.4.3", "bcryptjs": "2.4.3",
"bullmq": "1.81.4", "bullmq": "1.82.2",
"compare-versions": "4.1.3", "compare-versions": "4.1.3",
"cookie": "0.5.0", "cookie": "0.5.0",
"cuid": "2.1.8", "cuid": "2.1.8",

View File

@ -5,18 +5,18 @@ specifiers:
'@prisma/client': 3.11.1 '@prisma/client': 3.11.1
'@sentry/node': 6.19.7 '@sentry/node': 6.19.7
'@sveltejs/adapter-node': 1.0.0-next.73 '@sveltejs/adapter-node': 1.0.0-next.73
'@sveltejs/adapter-static': 1.0.0-next.29 '@sveltejs/adapter-static': 1.0.0-next.31
'@sveltejs/kit': 1.0.0-next.326 '@sveltejs/kit': 1.0.0-next.334
'@types/js-cookie': 3.0.2 '@types/js-cookie': 3.0.2
'@types/js-yaml': 4.0.5 '@types/js-yaml': 4.0.5
'@types/node': 17.0.31 '@types/node': 17.0.34
'@types/node-forge': 1.0.2 '@types/node-forge': 1.0.2
'@typescript-eslint/eslint-plugin': 4.31.1 '@typescript-eslint/eslint-plugin': 4.31.1
'@typescript-eslint/parser': 4.31.1 '@typescript-eslint/parser': 4.31.1
'@zerodevx/svelte-toast': 0.7.1 '@zerodevx/svelte-toast': 0.7.1
autoprefixer: 10.4.7 autoprefixer: 10.4.7
bcryptjs: 2.4.3 bcryptjs: 2.4.3
bullmq: 1.81.4 bullmq: 1.82.2
compare-versions: 4.1.3 compare-versions: 4.1.3
cookie: 0.5.0 cookie: 0.5.0
cross-env: 7.0.3 cross-env: 7.0.3
@ -44,10 +44,10 @@ specifiers:
postcss: 8.4.13 postcss: 8.4.13
prettier: 2.6.2 prettier: 2.6.2
prettier-plugin-svelte: 2.7.0 prettier-plugin-svelte: 2.7.0
prettier-plugin-tailwindcss: 0.1.10 prettier-plugin-tailwindcss: 0.1.11
prisma: 3.11.1 prisma: 3.11.1
svelte: 3.48.0 svelte: 3.48.0
svelte-check: 2.7.0 svelte-check: 2.7.1
svelte-kit-cookie-session: 2.1.4 svelte-kit-cookie-session: 2.1.4
svelte-preprocess: 4.10.6 svelte-preprocess: 4.10.6
svelte-select: 4.4.7 svelte-select: 4.4.7
@ -64,7 +64,7 @@ dependencies:
'@prisma/client': 3.11.1_prisma@3.11.1 '@prisma/client': 3.11.1_prisma@3.11.1
'@sentry/node': 6.19.7 '@sentry/node': 6.19.7
bcryptjs: 2.4.3 bcryptjs: 2.4.3
bullmq: 1.81.4 bullmq: 1.82.2
compare-versions: 4.1.3 compare-versions: 4.1.3
cookie: 0.5.0 cookie: 0.5.0
cuid: 2.1.8 cuid: 2.1.8
@ -88,11 +88,11 @@ dependencies:
devDependencies: devDependencies:
'@sveltejs/adapter-node': 1.0.0-next.73 '@sveltejs/adapter-node': 1.0.0-next.73
'@sveltejs/adapter-static': 1.0.0-next.29 '@sveltejs/adapter-static': 1.0.0-next.31
'@sveltejs/kit': 1.0.0-next.326_svelte@3.48.0 '@sveltejs/kit': 1.0.0-next.334_svelte@3.48.0
'@types/js-cookie': 3.0.2 '@types/js-cookie': 3.0.2
'@types/js-yaml': 4.0.5 '@types/js-yaml': 4.0.5
'@types/node': 17.0.31 '@types/node': 17.0.34
'@types/node-forge': 1.0.2 '@types/node-forge': 1.0.2
'@typescript-eslint/eslint-plugin': 4.31.1_lii63oz3usekbu5ehvrcuwn5jy '@typescript-eslint/eslint-plugin': 4.31.1_lii63oz3usekbu5ehvrcuwn5jy
'@typescript-eslint/parser': 4.31.1_e4zyhrvfnqudwdx5bevnvkluy4 '@typescript-eslint/parser': 4.31.1_e4zyhrvfnqudwdx5bevnvkluy4
@ -108,15 +108,15 @@ devDependencies:
postcss: 8.4.13 postcss: 8.4.13
prettier: 2.6.2 prettier: 2.6.2
prettier-plugin-svelte: 2.7.0_kkjbqzpydplecjtkxrgomroeru prettier-plugin-svelte: 2.7.0_kkjbqzpydplecjtkxrgomroeru
prettier-plugin-tailwindcss: 0.1.10_prettier@2.6.2 prettier-plugin-tailwindcss: 0.1.11_prettier@2.6.2
prisma: 3.11.1 prisma: 3.11.1
svelte: 3.48.0 svelte: 3.48.0
svelte-check: 2.7.0_f2ke6qjyzu5axsjd6yk3u4tn7a svelte-check: 2.7.1_f2ke6qjyzu5axsjd6yk3u4tn7a
svelte-preprocess: 4.10.6_nq4dx2skq5drra53vttuo4lltu svelte-preprocess: 4.10.6_nq4dx2skq5drra53vttuo4lltu
svelte-select: 4.4.7 svelte-select: 4.4.7
sveltekit-i18n: 2.2.1_svelte@3.48.0 sveltekit-i18n: 2.2.1_svelte@3.48.0
tailwindcss: 3.0.24_ts-node@10.7.0 tailwindcss: 3.0.24_ts-node@10.7.0
ts-node: 10.7.0_l47be6km5p57gglrggidw5gsgm ts-node: 10.7.0_3smuweqyuzdazdnyhhezld6mfa
tslib: 2.4.0 tslib: 2.4.0
typescript: 4.6.4 typescript: 4.6.4
@ -216,6 +216,31 @@ packages:
} }
dev: false dev: false
/@jridgewell/resolve-uri/3.0.7:
resolution:
{
integrity: sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA==
}
engines: { node: '>=6.0.0' }
dev: true
/@jridgewell/sourcemap-codec/1.4.13:
resolution:
{
integrity: sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w==
}
dev: true
/@jridgewell/trace-mapping/0.3.13:
resolution:
{
integrity: sha512-o1xbKhp9qnIAoHJSWd6KlCZfqslL4valSF81H8ImioOAxluWYWOpWkpyktY2vnt4tbrX9XYaxovq6cgowaJp2w==
}
dependencies:
'@jridgewell/resolve-uri': 3.0.7
'@jridgewell/sourcemap-codec': 1.4.13
dev: true
/@nodelib/fs.scandir/2.1.5: /@nodelib/fs.scandir/2.1.5:
resolution: resolution:
{ {
@ -382,21 +407,21 @@ packages:
tiny-glob: 0.2.9 tiny-glob: 0.2.9
dev: true dev: true
/@sveltejs/adapter-static/1.0.0-next.29: /@sveltejs/adapter-static/1.0.0-next.31:
resolution: resolution:
{ {
integrity: sha512-0hjGnfT3BRyoHnzJ2w0/xL+xICRpKneDTm45ZzggiRrc0r71WJfF6toGeg8N4QUQnj8EJ3Itm453gsS1kt7VUQ== integrity: sha512-d9RNA/de5ljb+gN8mKA3YfmfJoTbYFdH96NYDD8u4Lu9O/ZnseUxOAcAmD4/LKbLXOY/oYhRpt029xT2owyI3Q==
} }
dependencies: dependencies:
tiny-glob: 0.2.9 tiny-glob: 0.2.9
dev: true dev: true
/@sveltejs/kit/1.0.0-next.326_svelte@3.48.0: /@sveltejs/kit/1.0.0-next.334_svelte@3.48.0:
resolution: resolution:
{ {
integrity: sha512-prJqmXZ2H1wmFfnMw7wDujfbkcA8vuubuqUkpVVmXhfh2+SEzQscPTNwxoE5EJxb5sywtLWEvYx3hv1gPS4Lvg== integrity: sha512-HPMF1oYBfyOG6wfU0Y6F4SID8jphue9yF+PXJqVTDBL5Z2WBG2ogum6MavE8aWhq+g2H6w5y0jNT8+8DO2KTCA==
} }
engines: { node: '>=14.13' } engines: { node: '>=16' }
hasBin: true hasBin: true
peerDependencies: peerDependencies:
svelte: ^3.44.0 svelte: ^3.44.0
@ -506,7 +531,7 @@ packages:
dependencies: dependencies:
'@types/http-cache-semantics': 4.0.1 '@types/http-cache-semantics': 4.0.1
'@types/keyv': 3.1.3 '@types/keyv': 3.1.3
'@types/node': 17.0.31 '@types/node': 17.0.34
'@types/responselike': 1.0.0 '@types/responselike': 1.0.0
dev: false dev: false
@ -544,7 +569,7 @@ packages:
integrity: sha512-FXCJgyyN3ivVgRoml4h94G/p3kY+u/B86La+QptcqJaWtBWtmc6TtkNfS40n9bIvyLteHh7zXOtgbobORKPbDg== integrity: sha512-FXCJgyyN3ivVgRoml4h94G/p3kY+u/B86La+QptcqJaWtBWtmc6TtkNfS40n9bIvyLteHh7zXOtgbobORKPbDg==
} }
dependencies: dependencies:
'@types/node': 17.0.31 '@types/node': 17.0.34
dev: false dev: false
/@types/node-forge/1.0.2: /@types/node-forge/1.0.2:
@ -553,13 +578,13 @@ packages:
integrity: sha512-J1OkeZGaW0y9Y7xD49Ja8O82B9l5nZDeoYuGWqIOYPAf9LR+xF23k9ILdzv8dH+2H033fx3D5oiA0GlmicI+sg== integrity: sha512-J1OkeZGaW0y9Y7xD49Ja8O82B9l5nZDeoYuGWqIOYPAf9LR+xF23k9ILdzv8dH+2H033fx3D5oiA0GlmicI+sg==
} }
dependencies: dependencies:
'@types/node': 17.0.31 '@types/node': 17.0.34
dev: true dev: true
/@types/node/17.0.31: /@types/node/17.0.34:
resolution: resolution:
{ {
integrity: sha512-AR0x5HbXGqkEx9CadRH3EBYx/VkiUgZIhP4wvPn/+5KIsgpNoyFaRlVe0Zlx9gRtg8fA06a9tskE2MSN7TcG4Q== integrity: sha512-XImEz7XwTvDBtzlTnm8YvMqGW/ErMWBsKZ+hMTvnDIjGCKxwK5Xpc+c/oQjOauwq8M4OS11hEkpjX8rrI/eEgA==
} }
/@types/pug/2.0.5: /@types/pug/2.0.5:
@ -575,7 +600,7 @@ packages:
integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA== integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==
} }
dependencies: dependencies:
'@types/node': 17.0.31 '@types/node': 17.0.34
dev: false dev: false
/@types/sass/1.16.1: /@types/sass/1.16.1:
@ -584,7 +609,7 @@ packages:
integrity: sha512-iZUcRrGuz/Tbg3loODpW7vrQJkUtpY2fFSf4ELqqkApcS2TkZ1msk7ie8iZPB86lDOP8QOTTmuvWjc5S0R9OjQ== integrity: sha512-iZUcRrGuz/Tbg3loODpW7vrQJkUtpY2fFSf4ELqqkApcS2TkZ1msk7ie8iZPB86lDOP8QOTTmuvWjc5S0R9OjQ==
} }
dependencies: dependencies:
'@types/node': 17.0.31 '@types/node': 17.0.34
dev: true dev: true
/@typescript-eslint/eslint-plugin/4.31.1_lii63oz3usekbu5ehvrcuwn5jy: /@typescript-eslint/eslint-plugin/4.31.1_lii63oz3usekbu5ehvrcuwn5jy:
@ -1700,10 +1725,10 @@ packages:
ieee754: 1.2.1 ieee754: 1.2.1
dev: false dev: false
/bullmq/1.81.4: /bullmq/1.82.2:
resolution: resolution:
{ {
integrity: sha512-sUEWOMKZnWlh1/XNqYAoSwXW6P8nZN7uJiHKZ8XlZCiIxWlEGjFtlugkkiCZ0lsTI2nNRHdxfpn78x9K3L1utQ== integrity: sha512-pDmMl6HmL/7B41ldBK4lnmGUcobkI/n/a0T3d/volMWC0ULxsaZ6R6fDePk23LwH9Fxu4o9Ny+zurCL3vG7lbg==
} }
dependencies: dependencies:
cron-parser: 4.2.1 cron-parser: 4.2.1
@ -4161,7 +4186,7 @@ packages:
dependencies: dependencies:
lilconfig: 2.0.5 lilconfig: 2.0.5
postcss: 8.4.13 postcss: 8.4.13
ts-node: 10.7.0_l47be6km5p57gglrggidw5gsgm ts-node: 10.7.0_3smuweqyuzdazdnyhhezld6mfa
yaml: 1.10.2 yaml: 1.10.2
dev: true dev: true
@ -4229,10 +4254,10 @@ packages:
svelte: 3.48.0 svelte: 3.48.0
dev: true dev: true
/prettier-plugin-tailwindcss/0.1.10_prettier@2.6.2: /prettier-plugin-tailwindcss/0.1.11_prettier@2.6.2:
resolution: resolution:
{ {
integrity: sha512-ooDGNuXUjgCXfShliVYQ6+0iXqUFXn+zdNInPe0WZN9qINt9srbLGFGY5jeVL4MXtY20/4S8JaBcd8l6N6NfCQ== integrity: sha512-a28+1jvpIZQdZ/W97wOXb6VqI762MKE/TxMMuibMEHhyYsSxQA8Ek30KObd5kJI2HF1ldtSYprFayXJXi3pz8Q==
} }
engines: { node: '>=12.17.0' } engines: { node: '>=12.17.0' }
peerDependencies: peerDependencies:
@ -4719,14 +4744,6 @@ packages:
engines: { node: '>=0.10.0' } engines: { node: '>=0.10.0' }
dev: true dev: true
/source-map/0.7.3:
resolution:
{
integrity: sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==
}
engines: { node: '>= 8' }
dev: true
/sourcemap-codec/1.4.8: /sourcemap-codec/1.4.8:
resolution: resolution:
{ {
@ -4899,21 +4916,21 @@ packages:
engines: { node: '>= 0.4' } engines: { node: '>= 0.4' }
dev: true dev: true
/svelte-check/2.7.0_f2ke6qjyzu5axsjd6yk3u4tn7a: /svelte-check/2.7.1_f2ke6qjyzu5axsjd6yk3u4tn7a:
resolution: resolution:
{ {
integrity: sha512-GrvG24j0+i8AOm0k0KyJ6Dqc+TAR2yzB7rtS4nljHStunVxCTr/1KYlv4EsOeoqtHLzeWMOd5D2O6nDdP/yw4A== integrity: sha512-vHVu2+SQ6ibt77iTQaq2oiOjBgGL48qqcg0ZdEOsP5pPOjgeyR9QbnaEdzdBs9nsVYBc/42haKtzb2uFqS8GVw==
} }
hasBin: true hasBin: true
peerDependencies: peerDependencies:
svelte: ^3.24.0 svelte: ^3.24.0
dependencies: dependencies:
'@jridgewell/trace-mapping': 0.3.13
chokidar: 3.5.3 chokidar: 3.5.3
fast-glob: 3.2.11 fast-glob: 3.2.11
import-fresh: 3.3.0 import-fresh: 3.3.0
picocolors: 1.0.0 picocolors: 1.0.0
sade: 1.7.4 sade: 1.7.4
source-map: 0.7.3
svelte: 3.48.0 svelte: 3.48.0
svelte-preprocess: 4.10.6_nq4dx2skq5drra53vttuo4lltu svelte-preprocess: 4.10.6_nq4dx2skq5drra53vttuo4lltu
typescript: 4.6.4 typescript: 4.6.4
@ -5154,7 +5171,7 @@ packages:
engines: { node: '>=0.10.0' } engines: { node: '>=0.10.0' }
dev: true dev: true
/ts-node/10.7.0_l47be6km5p57gglrggidw5gsgm: /ts-node/10.7.0_3smuweqyuzdazdnyhhezld6mfa:
resolution: resolution:
{ {
integrity: sha512-TbIGS4xgJoX2i3do417KSaep1uRAW/Lu+WAL2doDHC0D6ummjirVOXU5/7aiZotbQ5p1Zp9tP7U6cYhA0O7M8A== integrity: sha512-TbIGS4xgJoX2i3do417KSaep1uRAW/Lu+WAL2doDHC0D6ummjirVOXU5/7aiZotbQ5p1Zp9tP7U6cYhA0O7M8A==
@ -5176,7 +5193,7 @@ packages:
'@tsconfig/node12': 1.0.9 '@tsconfig/node12': 1.0.9
'@tsconfig/node14': 1.0.1 '@tsconfig/node14': 1.0.1
'@tsconfig/node16': 1.0.2 '@tsconfig/node16': 1.0.2
'@types/node': 17.0.31 '@types/node': 17.0.34
acorn: 8.5.0 acorn: 8.5.0
acorn-walk: 8.2.0 acorn-walk: 8.2.0
arg: 4.1.3 arg: 4.1.3

View File

@ -12,7 +12,7 @@ CREATE TABLE "new_Setting" (
"proxyHash" TEXT, "proxyHash" TEXT,
"isAutoUpdateEnabled" BOOLEAN NOT NULL DEFAULT false, "isAutoUpdateEnabled" BOOLEAN NOT NULL DEFAULT false,
"isDNSCheckEnabled" BOOLEAN NOT NULL DEFAULT true, "isDNSCheckEnabled" BOOLEAN NOT NULL DEFAULT true,
"isTraefikUsed" BOOLEAN NOT NULL DEFAULT false, "isTraefikUsed" BOOLEAN NOT NULL DEFAULT true,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL "updatedAt" DATETIME NOT NULL
); );

View File

@ -0,0 +1,10 @@
-- CreateTable
CREATE TABLE "Notification" (
"id" TEXT NOT NULL PRIMARY KEY,
"type" TEXT NOT NULL,
"message" TEXT NOT NULL,
"isRead" BOOLEAN NOT NULL DEFAULT false,
"showAtVersion" TEXT NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);

View File

@ -20,11 +20,21 @@ model Setting {
proxyHash String? proxyHash String?
isAutoUpdateEnabled Boolean @default(false) isAutoUpdateEnabled Boolean @default(false)
isDNSCheckEnabled Boolean @default(true) isDNSCheckEnabled Boolean @default(true)
isTraefikUsed Boolean @default(false) isTraefikUsed Boolean @default(true)
createdAt DateTime @default(now()) createdAt DateTime @default(now())
updatedAt DateTime @updatedAt updatedAt DateTime @updatedAt
} }
model Notification {
id String @id @default(cuid())
type String
message String
isRead Boolean @default(false)
showAtVersion String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model User { model User {
id String @id @unique @default(cuid()) id String @id @unique @default(cuid())
email String @unique email String @unique

View File

@ -421,6 +421,21 @@ export async function checkContainer(
return containerFound; return containerFound;
} }
export async function getContainerUsage(engine: string, container: string): Promise<any> {
const host = getEngine(engine);
try {
const { stdout } = await asyncExecShell(
`DOCKER_HOST="${host}" docker container stats ${container} --no-stream --no-trunc --format "{{json .}}"`
);
return JSON.parse(stdout);
} catch (err) {
return {
MemUsage: 0,
CPUPerc: 0,
NetIO: 0
};
}
}
export async function stopCoolifyProxy( export async function stopCoolifyProxy(
engine: string engine: string
): Promise<{ stdout: string; stderr: string } | Error> { ): Promise<{ stdout: string; stderr: string } | Error> {

View File

@ -14,3 +14,12 @@ export const features: Readable<{ latestVersion: string; beta: boolean }> = read
}); });
export const isTraefikUsed: Writable<boolean> = writable(false); export const isTraefikUsed: Writable<boolean> = writable(false);
export const status: Writable<any> = writable({
application: {
isRunning: false,
isExited: false,
loading: false,
initialLoading: true
}
});

View File

@ -80,6 +80,9 @@
} finally { } finally {
} }
} }
try {
const data = await get(`/notifications.json`);
} catch (error) {}
} }
}); });

View File

@ -17,7 +17,7 @@
const endpoint = `/applications/${params.id}.json`; const endpoint = `/applications/${params.id}.json`;
const res = await fetch(endpoint); const res = await fetch(endpoint);
if (res.ok) { if (res.ok) {
let { application, isRunning, isExited, appId, githubToken, gitlabToken } = await res.json(); let { application, appId, githubToken, gitlabToken } = await res.json();
if (!application || Object.entries(application).length === 0) { if (!application || Object.entries(application).length === 0) {
return { return {
status: 302, status: 302,
@ -45,13 +45,10 @@
return { return {
props: { props: {
application, application,
isRunning,
isExited,
githubToken, githubToken,
gitlabToken gitlabToken
}, },
stuff: { stuff: {
isRunning,
application, application,
appId appId
} }
@ -67,8 +64,6 @@
<script lang="ts"> <script lang="ts">
export let application; export let application;
export let isRunning;
export let isExited;
export let githubToken; export let githubToken;
export let gitlabToken; export let gitlabToken;
import { page, session } from '$app/stores'; import { page, session } from '$app/stores';
@ -77,7 +72,7 @@
import Loading from '$lib/components/Loading.svelte'; import Loading from '$lib/components/Loading.svelte';
import { del, get, post } from '$lib/api'; import { del, get, post } from '$lib/api';
import { goto } from '$app/navigation'; import { goto } from '$app/navigation';
import { gitTokens } from '$lib/store'; import { gitTokens, status } from '$lib/store';
import { toast } from '@zerodevx/svelte-toast'; import { toast } from '@zerodevx/svelte-toast';
import { disabledButton } from '$lib/store'; import { disabledButton } from '$lib/store';
import { onDestroy, onMount } from 'svelte'; import { onDestroy, onMount } from 'svelte';
@ -135,17 +130,23 @@
} }
} }
async function getStatus() { async function getStatus() {
statusInterval = setInterval(async () => { if ($status.application.loading) return;
const data = await get(`/applications/${id}.json`); console.log('getStatus');
isRunning = data.isRunning; $status.application.loading = true;
isExited = data.isExited; const data = await get(`/applications/${id}/status.json`);
}, 1000); $status.application.isRunning = data.isRunning;
$status.application.isExited = data.isExited;
$status.application.loading = false;
$status.application.initialLoading = false;
} }
onDestroy(() => { onDestroy(() => {
clearInterval(statusInterval); clearInterval(statusInterval);
}); });
onMount(async () => { onMount(async () => {
await getStatus(); await getStatus();
statusInterval = setInterval(async () => {
await getStatus();
}, 1000);
}); });
</script> </script>
@ -153,16 +154,16 @@
{#if loading} {#if loading}
<Loading fullscreen cover /> <Loading fullscreen cover />
{:else} {:else}
{#if isExited} {#if $status.application.isExited}
<a <a
href={!$disabledButton ? `/applications/${id}/logs` : null} href={!$disabledButton ? `/applications/${id}/logs` : null}
class=" icons bg-transparent tooltip-bottom text-sm flex items-center text-red-500 tooltip-red-500" class=" icons tooltip-bottom tooltip-red-500 flex items-center bg-transparent text-sm text-red-500"
data-tooltip="Application exited with an error!" data-tooltip="Application exited with an error!"
sveltekit:prefetch sveltekit:prefetch
> >
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
class="w-6 h-6" class="h-6 w-6"
viewBox="0 0 24 24" viewBox="0 0 24 24"
stroke-width="1.5" stroke-width="1.5"
stroke="currentcolor" stroke="currentcolor"
@ -179,20 +180,43 @@
</svg> </svg>
</a> </a>
{/if} {/if}
{#if isRunning} {#if $status.application.initialLoading}
<button
class="icons tooltip-bottom flex animate-spin items-center space-x-2 bg-transparent text-sm duration-500 ease-in-out"
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-6 w-6"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M9 4.55a8 8 0 0 1 6 14.9m0 -4.45v5h5" />
<line x1="5.63" y1="7.16" x2="5.63" y2="7.17" />
<line x1="4.06" y1="11" x2="4.06" y2="11.01" />
<line x1="4.63" y1="15.1" x2="4.63" y2="15.11" />
<line x1="7.16" y1="18.37" x2="7.16" y2="18.38" />
<line x1="11" y1="19.94" x2="11" y2="19.95" />
</svg>
</button>
{:else if $status.application.isRunning}
<button <button
on:click={stopApplication} on:click={stopApplication}
title="Stop application" title="Stop application"
type="submit" type="submit"
disabled={$disabledButton} disabled={$disabledButton}
class="icons bg-transparent tooltip-bottom text-sm flex items-center space-x-2 text-red-500" class="icons tooltip-bottom flex items-center space-x-2 bg-transparent text-sm text-red-500"
data-tooltip={$session.isAdmin data-tooltip={$session.isAdmin
? $t('application.stop_application') ? $t('application.stop_application')
: $t('application.permission_denied_stop_application')} : $t('application.permission_denied_stop_application')}
> >
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
class="w-6 h-6" class="h-6 w-6"
viewBox="0 0 24 24" viewBox="0 0 24 24"
stroke-width="1.5" stroke-width="1.5"
stroke="currentColor" stroke="currentColor"
@ -210,14 +234,14 @@
title="Rebuild application" title="Rebuild application"
type="submit" type="submit"
disabled={$disabledButton} disabled={$disabledButton}
class="icons bg-transparent tooltip-bottom text-sm flex items-center space-x-2 hover:text-green-500" class="icons tooltip-bottom flex items-center space-x-2 bg-transparent text-sm hover:text-green-500"
data-tooltip={$session.isAdmin data-tooltip={$session.isAdmin
? 'Rebuild application' ? 'Rebuild application'
: 'You do not have permission to rebuild application.'} : 'You do not have permission to rebuild application.'}
> >
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
class="w-6 h-6" class="h-6 w-6"
viewBox="0 0 24 24" viewBox="0 0 24 24"
stroke-width="1.5" stroke-width="1.5"
stroke="currentColor" stroke="currentColor"
@ -239,14 +263,14 @@
title="Build and start application" title="Build and start application"
type="submit" type="submit"
disabled={$disabledButton} disabled={$disabledButton}
class="icons bg-transparent tooltip-bottom text-sm flex items-center space-x-2 text-green-500" class="icons tooltip-bottom flex items-center space-x-2 bg-transparent text-sm text-green-500"
data-tooltip={$session.isAdmin data-tooltip={$session.isAdmin
? 'Build and start application' ? 'Build and start application'
: 'You do not have permission to Build and start application.'} : 'You do not have permission to Build and start application.'}
> >
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
class="w-6 h-6" class="h-6 w-6"
viewBox="0 0 24 24" viewBox="0 0 24 24"
stroke-width="1.5" stroke-width="1.5"
stroke="currentColor" stroke="currentColor"
@ -261,18 +285,18 @@
</form> </form>
{/if} {/if}
<div class="border border-coolgray-500 h-8" /> <div class="h-8 border border-coolgray-500" />
<a <a
href={!$disabledButton ? `/applications/${id}` : null} href={!$disabledButton ? `/applications/${id}` : null}
sveltekit:prefetch sveltekit:prefetch
class="hover:text-yellow-500 rounded" class="rounded hover:text-yellow-500"
class:text-yellow-500={$page.url.pathname === `/applications/${id}`} class:text-yellow-500={$page.url.pathname === `/applications/${id}`}
class:bg-coolgray-500={$page.url.pathname === `/applications/${id}`} class:bg-coolgray-500={$page.url.pathname === `/applications/${id}`}
> >
<button <button
title="Configurations" title="Configurations"
disabled={$disabledButton} disabled={$disabledButton}
class="icons bg-transparent tooltip-bottom text-sm" class="icons tooltip-bottom bg-transparent text-sm"
data-tooltip="Configurations" data-tooltip="Configurations"
> >
<svg <svg
@ -301,19 +325,19 @@
<a <a
href={!$disabledButton ? `/applications/${id}/secrets` : null} href={!$disabledButton ? `/applications/${id}/secrets` : null}
sveltekit:prefetch sveltekit:prefetch
class="hover:text-pink-500 rounded" class="rounded hover:text-pink-500"
class:text-pink-500={$page.url.pathname === `/applications/${id}/secrets`} class:text-pink-500={$page.url.pathname === `/applications/${id}/secrets`}
class:bg-coolgray-500={$page.url.pathname === `/applications/${id}/secrets`} class:bg-coolgray-500={$page.url.pathname === `/applications/${id}/secrets`}
> >
<button <button
title="Secret" title="Secret"
disabled={$disabledButton} disabled={$disabledButton}
class="icons bg-transparent tooltip-bottom text-sm" class="icons tooltip-bottom bg-transparent text-sm"
data-tooltip="Secret" data-tooltip="Secret"
> >
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
class="w-6 h-6" class="h-6 w-6"
viewBox="0 0 24 24" viewBox="0 0 24 24"
stroke-width="1.5" stroke-width="1.5"
stroke="currentColor" stroke="currentColor"
@ -333,19 +357,19 @@
<a <a
href={!$disabledButton ? `/applications/${id}/storage` : null} href={!$disabledButton ? `/applications/${id}/storage` : null}
sveltekit:prefetch sveltekit:prefetch
class="hover:text-pink-500 rounded" class="rounded hover:text-pink-500"
class:text-pink-500={$page.url.pathname === `/applications/${id}/storage`} class:text-pink-500={$page.url.pathname === `/applications/${id}/storage`}
class:bg-coolgray-500={$page.url.pathname === `/applications/${id}/storage`} class:bg-coolgray-500={$page.url.pathname === `/applications/${id}/storage`}
> >
<button <button
title="Persistent Storage" title="Persistent Storage"
disabled={$disabledButton} disabled={$disabledButton}
class="icons bg-transparent tooltip-bottom text-sm" class="icons tooltip-bottom bg-transparent text-sm"
data-tooltip="Persistent Storage" data-tooltip="Persistent Storage"
> >
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
class="w-6 h-6" class="h-6 w-6"
viewBox="0 0 24 24" viewBox="0 0 24 24"
stroke-width="1.5" stroke-width="1.5"
stroke="currentColor" stroke="currentColor"
@ -363,19 +387,19 @@
<a <a
href={!$disabledButton ? `/applications/${id}/previews` : null} href={!$disabledButton ? `/applications/${id}/previews` : null}
sveltekit:prefetch sveltekit:prefetch
class="hover:text-orange-500 rounded" class="rounded hover:text-orange-500"
class:text-orange-500={$page.url.pathname === `/applications/${id}/previews`} class:text-orange-500={$page.url.pathname === `/applications/${id}/previews`}
class:bg-coolgray-500={$page.url.pathname === `/applications/${id}/previews`} class:bg-coolgray-500={$page.url.pathname === `/applications/${id}/previews`}
> >
<button <button
title="Previews" title="Previews"
disabled={$disabledButton} disabled={$disabledButton}
class="icons bg-transparent tooltip-bottom text-sm" class="icons tooltip-bottom bg-transparent text-sm"
data-tooltip="Previews" data-tooltip="Previews"
> >
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
class="w-6 h-6" class="h-6 w-6"
viewBox="0 0 24 24" viewBox="0 0 24 24"
stroke-width="1.5" stroke-width="1.5"
stroke="currentColor" stroke="currentColor"
@ -392,18 +416,18 @@
</svg></button </svg></button
></a ></a
> >
<div class="border border-coolgray-500 h-8" /> <div class="h-8 border border-coolgray-500" />
<a <a
href={!$disabledButton && isRunning ? `/applications/${id}/logs` : null} href={!$disabledButton && $status.application.isRunning ? `/applications/${id}/logs` : null}
sveltekit:prefetch sveltekit:prefetch
class="hover:text-sky-500 rounded" class="rounded hover:text-sky-500"
class:text-sky-500={$page.url.pathname === `/applications/${id}/logs`} class:text-sky-500={$page.url.pathname === `/applications/${id}/logs`}
class:bg-coolgray-500={$page.url.pathname === `/applications/${id}/logs`} class:bg-coolgray-500={$page.url.pathname === `/applications/${id}/logs`}
> >
<button <button
title={$t('application.logs')} title={$t('application.logs')}
disabled={$disabledButton || !isRunning} disabled={$disabledButton || !$status.application.isRunning}
class="icons bg-transparent tooltip-bottom text-sm" class="icons tooltip-bottom bg-transparent text-sm"
data-tooltip={$t('application.logs')} data-tooltip={$t('application.logs')}
> >
<svg <svg
@ -428,14 +452,14 @@
<a <a
href={!$disabledButton ? `/applications/${id}/logs/build` : null} href={!$disabledButton ? `/applications/${id}/logs/build` : null}
sveltekit:prefetch sveltekit:prefetch
class="hover:text-red-500 rounded" class="rounded hover:text-red-500"
class:text-red-500={$page.url.pathname === `/applications/${id}/logs/build`} class:text-red-500={$page.url.pathname === `/applications/${id}/logs/build`}
class:bg-coolgray-500={$page.url.pathname === `/applications/${id}/logs/build`} class:bg-coolgray-500={$page.url.pathname === `/applications/${id}/logs/build`}
> >
<button <button
title="Build Logs" title="Build Logs"
disabled={$disabledButton} disabled={$disabledButton}
class="icons bg-transparent tooltip-bottom text-sm" class="icons tooltip-bottom bg-transparent text-sm"
data-tooltip="Build Logs" data-tooltip="Build Logs"
> >
<svg <svg
@ -460,7 +484,7 @@
</svg> </svg>
</button></a </button></a
> >
<div class="border border-coolgray-500 h-8" /> <div class="h-8 border border-coolgray-500" />
<button <button
on:click={() => deleteApplication(application.name)} on:click={() => deleteApplication(application.name)}
@ -468,7 +492,7 @@
type="submit" type="submit"
disabled={!$session.isAdmin} disabled={!$session.isAdmin}
class:hover:text-red-500={$session.isAdmin} class:hover:text-red-500={$session.isAdmin}
class="icons bg-transparent tooltip-bottom text-sm" class="icons tooltip-bottom bg-transparent text-sm"
data-tooltip={$session.isAdmin data-tooltip={$session.isAdmin
? $t('application.delete_application') ? $t('application.delete_application')
: $t('application.permission_denied_delete_application')} : $t('application.permission_denied_delete_application')}

View File

@ -1,7 +1,7 @@
import { getUserDetails } from '$lib/common'; import { asyncExecShell, getUserDetails } from '$lib/common';
import * as db from '$lib/database'; import * as db from '$lib/database';
import { ErrorHandler } from '$lib/database'; import { ErrorHandler } from '$lib/database';
import { checkContainer, isContainerExited } from '$lib/haproxy'; import { checkContainer, getContainerUsage, isContainerExited } from '$lib/haproxy';
import type { RequestHandler } from '@sveltejs/kit'; import type { RequestHandler } from '@sveltejs/kit';
import { setDefaultConfiguration } from '$lib/buildPacks/common'; import { setDefaultConfiguration } from '$lib/buildPacks/common';
@ -12,21 +12,14 @@ export const get: RequestHandler = async (event) => {
const { id } = event.params; const { id } = event.params;
const appId = process.env['COOLIFY_APP_ID']; const appId = process.env['COOLIFY_APP_ID'];
let isRunning = false;
let isExited = false;
let githubToken = event.locals.cookies?.githubToken || null; let githubToken = event.locals.cookies?.githubToken || null;
let gitlabToken = event.locals.cookies?.gitlabToken || null; let gitlabToken = event.locals.cookies?.gitlabToken || null;
try { try {
const application = await db.getApplication({ id, teamId }); const application = await db.getApplication({ id, teamId });
if (application.destinationDockerId) {
isRunning = await checkContainer(application.destinationDocker.engine, id);
isExited = await isContainerExited(application.destinationDocker.engine, id);
}
return { return {
status: 200, status: 200,
body: { body: {
isRunning,
isExited,
application, application,
appId, appId,
githubToken, githubToken,

View File

@ -4,8 +4,7 @@
if (stuff?.application?.id) { if (stuff?.application?.id) {
return { return {
props: { props: {
application: stuff.application, application: stuff.application
isRunning: stuff.isRunning
} }
}; };
} }
@ -36,10 +35,9 @@
baseImages: Array<{ value: string; label: string }>; baseImages: Array<{ value: string; label: string }>;
baseBuildImages: Array<{ value: string; label: string }>; baseBuildImages: Array<{ value: string; label: string }>;
}; };
export let isRunning;
import { page, session } from '$app/stores'; import { page, session } from '$app/stores';
import { errorNotification } from '$lib/form'; import { errorNotification } from '$lib/form';
import { onMount } from 'svelte'; import { onDestroy, onMount } from 'svelte';
import Select from 'svelte-select'; import Select from 'svelte-select';
import Explainer from '$lib/components/Explainer.svelte'; import Explainer from '$lib/components/Explainer.svelte';
@ -50,13 +48,22 @@
import { get, post } from '$lib/api'; import { get, post } from '$lib/api';
import cuid from 'cuid'; import cuid from 'cuid';
import { browser } from '$app/env'; import { browser } from '$app/env';
import { disabledButton } from '$lib/store'; import { disabledButton, status } from '$lib/store';
import { t } from '$lib/translations'; import { t } from '$lib/translations';
const { id } = $page.params; const { id } = $page.params;
let domainEl: HTMLInputElement; let domainEl: HTMLInputElement;
let loading = false; let loading = false;
let usageLoading = false;
let usage = {
MemUsage: 0,
CPUPerc: 0,
NetIO: 0
};
let usageInterval;
let forceSave = false; let forceSave = false;
let debug = application.settings.debug; let debug = application.settings.debug;
let previews = application.settings.previews; let previews = application.settings.previews;
@ -78,15 +85,29 @@
} }
]; ];
function containerClass() { function containerClass() {
if (!$session.isAdmin || isRunning) { if (!$session.isAdmin || $status.application.isRunning) {
return 'text-white border border-dashed border-coolgray-300 bg-transparent font-thin px-0'; return 'text-white border border-dashed border-coolgray-300 bg-transparent font-thin px-0';
} }
} }
if (browser && window.location.hostname === 'demo.coolify.io' && !application.fqdn) { if (browser && window.location.hostname === 'demo.coolify.io' && !application.fqdn) {
application.fqdn = `http://${cuid()}.demo.coolify.io`; application.fqdn = `http://${cuid()}.demo.coolify.io`;
} }
onMount(() => { async function getUsage() {
if (usageLoading) return;
usageLoading = true;
const data = await get(`/applications/${id}/usage.json`);
usage = data.usage;
usageLoading = false;
}
onDestroy(() => {
clearInterval(usageInterval);
});
onMount(async () => {
domainEl.focus(); domainEl.focus();
await getUsage();
usageInterval = setInterval(async () => {
await getUsage();
}, 1000);
}); });
async function changeSettings(name) { async function changeSettings(name) {
@ -261,6 +282,33 @@
</a> </a>
</div> </div>
<div class="mx-auto max-w-4xl px-6 py-4">
<div class="text-2xl font-bold">Application Usage</div>
<div class="mx-auto">
<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=" text-sm font-medium text-white">Used Memory / Memory Limit</dt>
<dd class="mt-1 text-xl font-semibold text-white">
{usage?.MemUsage}
</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 CPU</dt>
<dd class="mt-1 text-xl font-semibold text-white ">
{usage?.CPUPerc}
</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">Network IO</dt>
<dd class="mt-1 text-xl font-semibold text-white ">
{usage?.NetIO}
</dd>
</div>
</dl>
</div>
</div>
<div class="mx-auto max-w-4xl px-6"> <div class="mx-auto max-w-4xl px-6">
<!-- svelte-ignore missing-declaration --> <!-- svelte-ignore missing-declaration -->
<form on:submit|preventDefault={handleSubmit} class="py-4"> <form on:submit|preventDefault={handleSubmit} class="py-4">
@ -365,10 +413,10 @@
> >
<div class="custom-select-wrapper"> <div class="custom-select-wrapper">
<Select <Select
isDisabled={!$session.isAdmin || isRunning} isDisabled={!$session.isAdmin || $status.application.isRunning}
containerClasses={containerClass()} containerClasses={containerClass()}
id="baseImages" id="baseImages"
showIndicator={!isRunning} showIndicator={!$status.application.isRunning}
items={application.baseImages} items={application.baseImages}
on:select={selectBaseImage} on:select={selectBaseImage}
value={application.baseImage} value={application.baseImage}
@ -386,10 +434,10 @@
<div class="custom-select-wrapper"> <div class="custom-select-wrapper">
<Select <Select
isDisabled={!$session.isAdmin || isRunning} isDisabled={!$session.isAdmin || $status.application.isRunning}
containerClasses={containerClass()} containerClasses={containerClass()}
id="baseBuildImages" id="baseBuildImages"
showIndicator={!isRunning} showIndicator={!$status.application.isRunning}
items={application.baseBuildImages} items={application.baseBuildImages}
on:select={selectBaseBuildImage} on:select={selectBaseBuildImage}
value={application.baseBuildImage} value={application.baseBuildImage}
@ -422,8 +470,8 @@
</div> </div>
<div> <div>
<input <input
readonly={!$session.isAdmin || isRunning} readonly={!$session.isAdmin || $status.application.isRunning}
disabled={!$session.isAdmin || isRunning} disabled={!$session.isAdmin || $status.application.isRunning}
bind:this={domainEl} bind:this={domainEl}
name="fqdn" name="fqdn"
id="fqdn" id="fqdn"
@ -470,12 +518,12 @@
<div class="grid grid-cols-2 items-center pb-8"> <div class="grid grid-cols-2 items-center pb-8">
<Setting <Setting
dataTooltip={$t('forms.must_be_stopped_to_modify')} dataTooltip={$t('forms.must_be_stopped_to_modify')}
disabled={isRunning} disabled={$status.application.isRunning}
isCenter={false} isCenter={false}
bind:setting={dualCerts} bind:setting={dualCerts}
title={$t('application.ssl_www_and_non_www')} title={$t('application.ssl_www_and_non_www')}
description={$t('application.ssl_explainer')} description={$t('application.ssl_explainer')}
on:click={() => !isRunning && changeSettings('dualCerts')} on:click={() => !$status.application.isRunning && changeSettings('dualCerts')}
/> />
</div> </div>
{#if application.buildPack === 'python'} {#if application.buildPack === 'python'}
@ -527,8 +575,8 @@
<div class="grid grid-cols-2 items-center"> <div class="grid grid-cols-2 items-center">
<label for="exposePort" class="text-base font-bold text-stone-100">Exposed Port</label> <label for="exposePort" class="text-base font-bold text-stone-100">Exposed Port</label>
<input <input
readonly={!$session.isAdmin && !isRunning} readonly={!$session.isAdmin && !$status.application.isRunning}
disabled={!$session.isAdmin || isRunning} disabled={!$session.isAdmin || $status.application.isRunning}
name="exposePort" name="exposePort"
id="exposePort" id="exposePort"
bind:value={application.exposePort} bind:value={application.exposePort}

View File

@ -0,0 +1,36 @@
import { asyncExecShell, getUserDetails } from '$lib/common';
import * as db from '$lib/database';
import { ErrorHandler } from '$lib/database';
import { checkContainer, getContainerUsage, isContainerExited } from '$lib/haproxy';
import type { RequestHandler } from '@sveltejs/kit';
import { setDefaultConfiguration } from '$lib/buildPacks/common';
export const get: RequestHandler = async (event) => {
const { teamId, status, body } = await getUserDetails(event);
if (status === 401) return { status, body };
const { id } = event.params;
let isRunning = false;
let isExited = false;
try {
const application = await db.getApplication({ id, teamId });
if (application.destinationDockerId) {
[isRunning, isExited] = await Promise.all([
checkContainer(application.destinationDocker.engine, id),
isContainerExited(application.destinationDocker.engine, id)
]);
}
return {
status: 200,
body: {
isRunning,
isExited
},
headers: {}
};
} catch (error) {
console.log(error);
return ErrorHandler(error);
}
};

View File

@ -0,0 +1,31 @@
import { asyncExecShell, getUserDetails } from '$lib/common';
import * as db from '$lib/database';
import { ErrorHandler } from '$lib/database';
import { checkContainer, getContainerUsage, isContainerExited } from '$lib/haproxy';
import type { RequestHandler } from '@sveltejs/kit';
import { setDefaultConfiguration } from '$lib/buildPacks/common';
export const get: RequestHandler = async (event) => {
const { teamId, status, body } = await getUserDetails(event);
if (status === 401) return { status, body };
const { id } = event.params;
let usage = {};
try {
const application = await db.getApplication({ id, teamId });
if (application.destinationDockerId) {
[usage] = await Promise.all([getContainerUsage(application.destinationDocker.engine, id)]);
}
return {
status: 200,
body: {
usage
},
headers: {}
};
} catch (error) {
console.log(error);
return ErrorHandler(error);
}
};

View File

@ -0,0 +1,30 @@
import { ErrorHandler } from '$lib/database';
import { version } from '$lib/common';
import * as db from '$lib/database';
import type { RequestHandler } from '@sveltejs/kit';
export const get: RequestHandler = async (request) => {
try {
const unreadNotifications = await db.prisma.notification.findMany({
where: { isRead: false, showAtVersion: version }
});
return {
status: 200,
body: {
...unreadNotifications
}
};
} catch (error) {
console.log(error);
return ErrorHandler(error);
}
};
export const post: RequestHandler = async (event) => {
const { type, latestVersion } = await event.request.json();
const settings = await db.prisma.setting.findFirst();
return {
status: 500
};
};

View File

@ -27,7 +27,7 @@ export const get: RequestHandler = async (event) => {
services: { services: {
[id]: { [id]: {
loadbalancer: { loadbalancer: {
servers: [] servers: [{ address: `${id}:${privatePort}` }]
} }
} }
} }
@ -49,7 +49,7 @@ export const get: RequestHandler = async (event) => {
services: { services: {
[id]: { [id]: {
loadbalancer: { loadbalancer: {
servers: [] servers: [{ url: `http://${id}:${privatePort}` }]
} }
} }
} }
@ -58,11 +58,6 @@ export const get: RequestHandler = async (event) => {
} }
} }
} }
if (type === 'tcp') {
traefik[type].services[id].loadbalancer.servers.push({ address: `${id}:${privatePort}` });
} else if (type === 'http') {
traefik[type].services[id].loadbalancer.servers.push({ url: `http://${id}:${privatePort}` });
}
return { return {
status: 200, status: 200,
body: { body: {