From 35b31dce2b55afce0474fc4e6d949f8321874542 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Tue, 17 May 2022 10:14:06 +0200 Subject: [PATCH] WIP: Notifications and application usage --- package.json | 12 +- pnpm-lock.yaml | 103 +++++++++------- .../migration.sql | 2 +- .../migration.sql | 10 ++ prisma/schema.prisma | 12 +- src/lib/haproxy/index.ts | 15 +++ src/lib/store.ts | 9 ++ src/routes/__layout.svelte | 3 + src/routes/applications/[id]/__layout.svelte | 110 +++++++++++------- src/routes/applications/[id]/index.json.ts | 13 +-- src/routes/applications/[id]/index.svelte | 82 ++++++++++--- src/routes/applications/[id]/status.json.ts | 36 ++++++ src/routes/applications/[id]/usage.json.ts | 31 +++++ src/routes/notifications.json.ts | 30 +++++ src/routes/webhooks/traefik/other.json.ts | 9 +- 15 files changed, 349 insertions(+), 128 deletions(-) rename prisma/migrations/{20220513154929_traefik => 20220517081328_traefik}/migration.sql (95%) create mode 100644 prisma/migrations/20220517081338_notifications/migration.sql create mode 100644 src/routes/applications/[id]/status.json.ts create mode 100644 src/routes/applications/[id]/usage.json.ts create mode 100644 src/routes/notifications.json.ts diff --git a/package.json b/package.json index 96d9a64a4..1f766bd18 100644 --- a/package.json +++ b/package.json @@ -30,11 +30,11 @@ }, "devDependencies": { "@sveltejs/adapter-node": "1.0.0-next.73", - "@sveltejs/adapter-static": "1.0.0-next.29", - "@sveltejs/kit": "1.0.0-next.326", + "@sveltejs/adapter-static": "1.0.0-next.31", + "@sveltejs/kit": "1.0.0-next.334", "@types/js-cookie": "3.0.2", "@types/js-yaml": "4.0.5", - "@types/node": "17.0.31", + "@types/node": "17.0.34", "@types/node-forge": "1.0.2", "@typescript-eslint/eslint-plugin": "4.31.1", "@typescript-eslint/parser": "4.31.1", @@ -50,10 +50,10 @@ "postcss": "8.4.13", "prettier": "2.6.2", "prettier-plugin-svelte": "2.7.0", - "prettier-plugin-tailwindcss": "0.1.10", + "prettier-plugin-tailwindcss": "0.1.11", "prisma": "3.11.1", "svelte": "3.48.0", - "svelte-check": "2.7.0", + "svelte-check": "2.7.1", "svelte-preprocess": "4.10.6", "svelte-select": "4.4.7", "sveltekit-i18n": "2.2.1", @@ -68,7 +68,7 @@ "@prisma/client": "3.11.1", "@sentry/node": "6.19.7", "bcryptjs": "2.4.3", - "bullmq": "1.81.4", + "bullmq": "1.82.2", "compare-versions": "4.1.3", "cookie": "0.5.0", "cuid": "2.1.8", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 28b0ea786..b626b4fbd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,18 +5,18 @@ specifiers: '@prisma/client': 3.11.1 '@sentry/node': 6.19.7 '@sveltejs/adapter-node': 1.0.0-next.73 - '@sveltejs/adapter-static': 1.0.0-next.29 - '@sveltejs/kit': 1.0.0-next.326 + '@sveltejs/adapter-static': 1.0.0-next.31 + '@sveltejs/kit': 1.0.0-next.334 '@types/js-cookie': 3.0.2 '@types/js-yaml': 4.0.5 - '@types/node': 17.0.31 + '@types/node': 17.0.34 '@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.7 bcryptjs: 2.4.3 - bullmq: 1.81.4 + bullmq: 1.82.2 compare-versions: 4.1.3 cookie: 0.5.0 cross-env: 7.0.3 @@ -44,10 +44,10 @@ specifiers: postcss: 8.4.13 prettier: 2.6.2 prettier-plugin-svelte: 2.7.0 - prettier-plugin-tailwindcss: 0.1.10 + prettier-plugin-tailwindcss: 0.1.11 prisma: 3.11.1 svelte: 3.48.0 - svelte-check: 2.7.0 + svelte-check: 2.7.1 svelte-kit-cookie-session: 2.1.4 svelte-preprocess: 4.10.6 svelte-select: 4.4.7 @@ -64,7 +64,7 @@ dependencies: '@prisma/client': 3.11.1_prisma@3.11.1 '@sentry/node': 6.19.7 bcryptjs: 2.4.3 - bullmq: 1.81.4 + bullmq: 1.82.2 compare-versions: 4.1.3 cookie: 0.5.0 cuid: 2.1.8 @@ -88,11 +88,11 @@ dependencies: devDependencies: '@sveltejs/adapter-node': 1.0.0-next.73 - '@sveltejs/adapter-static': 1.0.0-next.29 - '@sveltejs/kit': 1.0.0-next.326_svelte@3.48.0 + '@sveltejs/adapter-static': 1.0.0-next.31 + '@sveltejs/kit': 1.0.0-next.334_svelte@3.48.0 '@types/js-cookie': 3.0.2 '@types/js-yaml': 4.0.5 - '@types/node': 17.0.31 + '@types/node': 17.0.34 '@types/node-forge': 1.0.2 '@typescript-eslint/eslint-plugin': 4.31.1_lii63oz3usekbu5ehvrcuwn5jy '@typescript-eslint/parser': 4.31.1_e4zyhrvfnqudwdx5bevnvkluy4 @@ -108,15 +108,15 @@ devDependencies: postcss: 8.4.13 prettier: 2.6.2 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 svelte: 3.48.0 - svelte-check: 2.7.0_f2ke6qjyzu5axsjd6yk3u4tn7a + svelte-check: 2.7.1_f2ke6qjyzu5axsjd6yk3u4tn7a svelte-preprocess: 4.10.6_nq4dx2skq5drra53vttuo4lltu svelte-select: 4.4.7 sveltekit-i18n: 2.2.1_svelte@3.48.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 typescript: 4.6.4 @@ -216,6 +216,31 @@ packages: } 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: resolution: { @@ -382,21 +407,21 @@ packages: tiny-glob: 0.2.9 dev: true - /@sveltejs/adapter-static/1.0.0-next.29: + /@sveltejs/adapter-static/1.0.0-next.31: resolution: { - integrity: sha512-0hjGnfT3BRyoHnzJ2w0/xL+xICRpKneDTm45ZzggiRrc0r71WJfF6toGeg8N4QUQnj8EJ3Itm453gsS1kt7VUQ== + integrity: sha512-d9RNA/de5ljb+gN8mKA3YfmfJoTbYFdH96NYDD8u4Lu9O/ZnseUxOAcAmD4/LKbLXOY/oYhRpt029xT2owyI3Q== } dependencies: tiny-glob: 0.2.9 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: { - integrity: sha512-prJqmXZ2H1wmFfnMw7wDujfbkcA8vuubuqUkpVVmXhfh2+SEzQscPTNwxoE5EJxb5sywtLWEvYx3hv1gPS4Lvg== + integrity: sha512-HPMF1oYBfyOG6wfU0Y6F4SID8jphue9yF+PXJqVTDBL5Z2WBG2ogum6MavE8aWhq+g2H6w5y0jNT8+8DO2KTCA== } - engines: { node: '>=14.13' } + engines: { node: '>=16' } hasBin: true peerDependencies: svelte: ^3.44.0 @@ -506,7 +531,7 @@ packages: dependencies: '@types/http-cache-semantics': 4.0.1 '@types/keyv': 3.1.3 - '@types/node': 17.0.31 + '@types/node': 17.0.34 '@types/responselike': 1.0.0 dev: false @@ -544,7 +569,7 @@ packages: integrity: sha512-FXCJgyyN3ivVgRoml4h94G/p3kY+u/B86La+QptcqJaWtBWtmc6TtkNfS40n9bIvyLteHh7zXOtgbobORKPbDg== } dependencies: - '@types/node': 17.0.31 + '@types/node': 17.0.34 dev: false /@types/node-forge/1.0.2: @@ -553,13 +578,13 @@ packages: integrity: sha512-J1OkeZGaW0y9Y7xD49Ja8O82B9l5nZDeoYuGWqIOYPAf9LR+xF23k9ILdzv8dH+2H033fx3D5oiA0GlmicI+sg== } dependencies: - '@types/node': 17.0.31 + '@types/node': 17.0.34 dev: true - /@types/node/17.0.31: + /@types/node/17.0.34: resolution: { - integrity: sha512-AR0x5HbXGqkEx9CadRH3EBYx/VkiUgZIhP4wvPn/+5KIsgpNoyFaRlVe0Zlx9gRtg8fA06a9tskE2MSN7TcG4Q== + integrity: sha512-XImEz7XwTvDBtzlTnm8YvMqGW/ErMWBsKZ+hMTvnDIjGCKxwK5Xpc+c/oQjOauwq8M4OS11hEkpjX8rrI/eEgA== } /@types/pug/2.0.5: @@ -575,7 +600,7 @@ packages: integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA== } dependencies: - '@types/node': 17.0.31 + '@types/node': 17.0.34 dev: false /@types/sass/1.16.1: @@ -584,7 +609,7 @@ packages: integrity: sha512-iZUcRrGuz/Tbg3loODpW7vrQJkUtpY2fFSf4ELqqkApcS2TkZ1msk7ie8iZPB86lDOP8QOTTmuvWjc5S0R9OjQ== } dependencies: - '@types/node': 17.0.31 + '@types/node': 17.0.34 dev: true /@typescript-eslint/eslint-plugin/4.31.1_lii63oz3usekbu5ehvrcuwn5jy: @@ -1700,10 +1725,10 @@ packages: ieee754: 1.2.1 dev: false - /bullmq/1.81.4: + /bullmq/1.82.2: resolution: { - integrity: sha512-sUEWOMKZnWlh1/XNqYAoSwXW6P8nZN7uJiHKZ8XlZCiIxWlEGjFtlugkkiCZ0lsTI2nNRHdxfpn78x9K3L1utQ== + integrity: sha512-pDmMl6HmL/7B41ldBK4lnmGUcobkI/n/a0T3d/volMWC0ULxsaZ6R6fDePk23LwH9Fxu4o9Ny+zurCL3vG7lbg== } dependencies: cron-parser: 4.2.1 @@ -4161,7 +4186,7 @@ packages: dependencies: lilconfig: 2.0.5 postcss: 8.4.13 - ts-node: 10.7.0_l47be6km5p57gglrggidw5gsgm + ts-node: 10.7.0_3smuweqyuzdazdnyhhezld6mfa yaml: 1.10.2 dev: true @@ -4229,10 +4254,10 @@ packages: svelte: 3.48.0 dev: true - /prettier-plugin-tailwindcss/0.1.10_prettier@2.6.2: + /prettier-plugin-tailwindcss/0.1.11_prettier@2.6.2: resolution: { - integrity: sha512-ooDGNuXUjgCXfShliVYQ6+0iXqUFXn+zdNInPe0WZN9qINt9srbLGFGY5jeVL4MXtY20/4S8JaBcd8l6N6NfCQ== + integrity: sha512-a28+1jvpIZQdZ/W97wOXb6VqI762MKE/TxMMuibMEHhyYsSxQA8Ek30KObd5kJI2HF1ldtSYprFayXJXi3pz8Q== } engines: { node: '>=12.17.0' } peerDependencies: @@ -4719,14 +4744,6 @@ packages: engines: { node: '>=0.10.0' } dev: true - /source-map/0.7.3: - resolution: - { - integrity: sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== - } - engines: { node: '>= 8' } - dev: true - /sourcemap-codec/1.4.8: resolution: { @@ -4899,21 +4916,21 @@ packages: engines: { node: '>= 0.4' } dev: true - /svelte-check/2.7.0_f2ke6qjyzu5axsjd6yk3u4tn7a: + /svelte-check/2.7.1_f2ke6qjyzu5axsjd6yk3u4tn7a: resolution: { - integrity: sha512-GrvG24j0+i8AOm0k0KyJ6Dqc+TAR2yzB7rtS4nljHStunVxCTr/1KYlv4EsOeoqtHLzeWMOd5D2O6nDdP/yw4A== + integrity: sha512-vHVu2+SQ6ibt77iTQaq2oiOjBgGL48qqcg0ZdEOsP5pPOjgeyR9QbnaEdzdBs9nsVYBc/42haKtzb2uFqS8GVw== } hasBin: true peerDependencies: svelte: ^3.24.0 dependencies: + '@jridgewell/trace-mapping': 0.3.13 chokidar: 3.5.3 fast-glob: 3.2.11 import-fresh: 3.3.0 picocolors: 1.0.0 sade: 1.7.4 - source-map: 0.7.3 svelte: 3.48.0 svelte-preprocess: 4.10.6_nq4dx2skq5drra53vttuo4lltu typescript: 4.6.4 @@ -5154,7 +5171,7 @@ packages: engines: { node: '>=0.10.0' } dev: true - /ts-node/10.7.0_l47be6km5p57gglrggidw5gsgm: + /ts-node/10.7.0_3smuweqyuzdazdnyhhezld6mfa: resolution: { integrity: sha512-TbIGS4xgJoX2i3do417KSaep1uRAW/Lu+WAL2doDHC0D6ummjirVOXU5/7aiZotbQ5p1Zp9tP7U6cYhA0O7M8A== @@ -5176,7 +5193,7 @@ packages: '@tsconfig/node12': 1.0.9 '@tsconfig/node14': 1.0.1 '@tsconfig/node16': 1.0.2 - '@types/node': 17.0.31 + '@types/node': 17.0.34 acorn: 8.5.0 acorn-walk: 8.2.0 arg: 4.1.3 diff --git a/prisma/migrations/20220513154929_traefik/migration.sql b/prisma/migrations/20220517081328_traefik/migration.sql similarity index 95% rename from prisma/migrations/20220513154929_traefik/migration.sql rename to prisma/migrations/20220517081328_traefik/migration.sql index 164bed387..a83281fa4 100644 --- a/prisma/migrations/20220513154929_traefik/migration.sql +++ b/prisma/migrations/20220517081328_traefik/migration.sql @@ -12,7 +12,7 @@ CREATE TABLE "new_Setting" ( "proxyHash" TEXT, "isAutoUpdateEnabled" BOOLEAN NOT NULL DEFAULT false, "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, "updatedAt" DATETIME NOT NULL ); diff --git a/prisma/migrations/20220517081338_notifications/migration.sql b/prisma/migrations/20220517081338_notifications/migration.sql new file mode 100644 index 000000000..069f938d5 --- /dev/null +++ b/prisma/migrations/20220517081338_notifications/migration.sql @@ -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 +); diff --git a/prisma/schema.prisma b/prisma/schema.prisma index a20b3455c..97d092331 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -20,11 +20,21 @@ model Setting { proxyHash String? isAutoUpdateEnabled Boolean @default(false) isDNSCheckEnabled Boolean @default(true) - isTraefikUsed Boolean @default(false) + isTraefikUsed Boolean @default(true) createdAt DateTime @default(now()) 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 { id String @id @unique @default(cuid()) email String @unique diff --git a/src/lib/haproxy/index.ts b/src/lib/haproxy/index.ts index d2424589c..5af082efe 100644 --- a/src/lib/haproxy/index.ts +++ b/src/lib/haproxy/index.ts @@ -421,6 +421,21 @@ export async function checkContainer( return containerFound; } +export async function getContainerUsage(engine: string, container: string): Promise { + 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( engine: string ): Promise<{ stdout: string; stderr: string } | Error> { diff --git a/src/lib/store.ts b/src/lib/store.ts index 75b943b46..9366d70b2 100644 --- a/src/lib/store.ts +++ b/src/lib/store.ts @@ -14,3 +14,12 @@ export const features: Readable<{ latestVersion: string; beta: boolean }> = read }); export const isTraefikUsed: Writable = writable(false); + +export const status: Writable = writable({ + application: { + isRunning: false, + isExited: false, + loading: false, + initialLoading: true + } +}); diff --git a/src/routes/__layout.svelte b/src/routes/__layout.svelte index 0dceeb9af..95c80565c 100644 --- a/src/routes/__layout.svelte +++ b/src/routes/__layout.svelte @@ -80,6 +80,9 @@ } finally { } } + try { + const data = await get(`/notifications.json`); + } catch (error) {} } }); diff --git a/src/routes/applications/[id]/__layout.svelte b/src/routes/applications/[id]/__layout.svelte index cc8c19c19..db30336fa 100644 --- a/src/routes/applications/[id]/__layout.svelte +++ b/src/routes/applications/[id]/__layout.svelte @@ -17,7 +17,7 @@ const endpoint = `/applications/${params.id}.json`; const res = await fetch(endpoint); 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) { return { status: 302, @@ -45,13 +45,10 @@ return { props: { application, - isRunning, - isExited, githubToken, gitlabToken }, stuff: { - isRunning, application, appId } @@ -67,8 +64,6 @@ @@ -153,16 +154,16 @@ {#if loading} {:else} - {#if isExited} + {#if $status.application.isExited} {/if} - {#if isRunning} + {#if $status.application.initialLoading} + + {:else if $status.application.isRunning}