From 91fa7629856edf399daa6b8613b04a055c612f3b Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Tue, 16 Aug 2022 09:13:22 +0000 Subject: [PATCH 01/14] fix: appwrite --- apps/api/src/lib/services.ts | 4 +- .../src/routes/api/v1/databases/handlers.ts | 3 +- .../src/routes/api/v1/services/handlers.ts | 887 ++++-------------- .../components/svg/services/Appwrite.svelte | 21 + .../svg/services/ServiceIcons.svelte | 2 + .../src/lib/components/svg/services/index.ts | 30 +- .../routes/services/[id]/_ServiceLinks.svelte | 2 +- .../services/[id]/_Services/_Wordpress.svelte | 2 +- 8 files changed, 202 insertions(+), 749 deletions(-) create mode 100644 apps/ui/src/lib/components/svg/services/Appwrite.svelte diff --git a/apps/api/src/lib/services.ts b/apps/api/src/lib/services.ts index 22c8081a5..c5d315ff0 100644 --- a/apps/api/src/lib/services.ts +++ b/apps/api/src/lib/services.ts @@ -13,13 +13,13 @@ export async function defaultServiceConfigurations({ id, teamId }) { let secrets = []; if (serviceSecret.length > 0) { serviceSecret.forEach((secret) => { - secrets.push([secret.name]=secret.value); + secrets.push(`${secret.name}=${secret.value}`); }); } return { ...service, network, port, workdir, image, secrets } } -export function defaultServiceComposeConfiguration(network: string) { +export function defaultServiceComposeConfiguration(network: string): any { return { networks: [network], restart: 'always', diff --git a/apps/api/src/routes/api/v1/databases/handlers.ts b/apps/api/src/routes/api/v1/databases/handlers.ts index 5d3bcac51..96c740440 100644 --- a/apps/api/src/routes/api/v1/databases/handlers.ts +++ b/apps/api/src/routes/api/v1/databases/handlers.ts @@ -3,8 +3,7 @@ import type { FastifyRequest } from 'fastify'; import { FastifyReply } from 'fastify'; import yaml from 'js-yaml'; import fs from 'fs/promises'; -import { ComposeFile, createDirectories, decrypt, encrypt, errorHandler, executeDockerCmd, generateDatabaseConfiguration, generatePassword, getContainerUsage, getDatabaseImage, getDatabaseVersions, getFreePublicPort, isARM, listSettings, makeLabelForStandaloneDatabase, prisma, startTraefikTCPProxy, stopDatabaseContainer, stopTcpHttpProxy, supportedDatabaseTypesAndVersions, uniqueName, updatePasswordInDb } from '../../../../lib/common'; -import { checkContainer } from '../../../../lib/docker'; +import { ComposeFile, createDirectories, decrypt, encrypt, errorHandler, executeDockerCmd, generateDatabaseConfiguration, generatePassword, getContainerUsage, getDatabaseImage, getDatabaseVersions, getFreePublicPort, listSettings, makeLabelForStandaloneDatabase, prisma, startTraefikTCPProxy, stopDatabaseContainer, stopTcpHttpProxy, supportedDatabaseTypesAndVersions, uniqueName, updatePasswordInDb } from '../../../../lib/common'; import { day } from '../../../../lib/dayjs'; import { GetDatabaseLogs, OnlyId, SaveDatabase, SaveDatabaseDestination, SaveDatabaseSettings, SaveVersion } from '../../../../types'; diff --git a/apps/api/src/routes/api/v1/services/handlers.ts b/apps/api/src/routes/api/v1/services/handlers.ts index ceef05420..bfd8a9352 100644 --- a/apps/api/src/routes/api/v1/services/handlers.ts +++ b/apps/api/src/routes/api/v1/services/handlers.ts @@ -2,7 +2,7 @@ import type { FastifyReply, FastifyRequest } from 'fastify'; import fs from 'fs/promises'; import yaml from 'js-yaml'; import bcrypt from 'bcryptjs'; -import { prisma, uniqueName, asyncExecShell, getServiceImage, configureServiceType, getServiceFromDB, getContainerUsage, removeService, isDomainConfigured, saveUpdateableFields, fixType, decrypt, encrypt, getServiceMainPort, createDirectories, ComposeFile, makeLabelForServices, getFreePublicPort, getDomain, errorHandler, generatePassword, isDev, stopTcpHttpProxy, supportedServiceTypesAndVersions, executeDockerCmd, listSettings, getFreeExposedPort, checkDomainsIsValidInDNS, persistentVolumes } from '../../../../lib/common'; +import { prisma, uniqueName, asyncExecShell, getServiceImage, configureServiceType, getServiceFromDB, getContainerUsage, removeService, isDomainConfigured, saveUpdateableFields, fixType, decrypt, encrypt, getServiceMainPort, createDirectories, ComposeFile, makeLabelForServices, getFreePublicPort, getDomain, errorHandler, generatePassword, isDev, stopTcpHttpProxy, supportedServiceTypesAndVersions, executeDockerCmd, listSettings, getFreeExposedPort, checkDomainsIsValidInDNS, persistentVolumes, asyncSleep, isARM } from '../../../../lib/common'; import { day } from '../../../../lib/dayjs'; import { checkContainer, isContainerExited, removeContainer } from '../../../../lib/docker'; import cuid from 'cuid'; @@ -135,8 +135,7 @@ import { defaultServiceComposeConfiguration, defaultServiceConfigurations } from // // config.services[id].environment = environmentVariables // const composeFileDestination = `${workdir}/docker-compose.yaml`; // // await fs.writeFile(composeFileDestination, yaml.dump(config)); -// // await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} pull`); -// // await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up -d`); +// await startServiceContainers(destinationDocker.id, composeFileDestination) // return {} // } catch ({ status, message }) { // return errorHandler({ status, message }) @@ -599,56 +598,54 @@ export async function startService(request: FastifyRequest) { } export async function stopService(request: FastifyRequest) { try { - const { type } = request.params - if (type === 'plausibleanalytics') { - return await stopPlausibleAnalyticsService(request) - } - if (type === 'nocodb') { - return await stopNocodbService(request) - } - if (type === 'minio') { - return await stopMinioService(request) - } - if (type === 'vscodeserver') { - return await stopVscodeService(request) - } - if (type === 'wordpress') { - return await stopWordpressService(request) - } - if (type === 'vaultwarden') { - return await stopVaultwardenService(request) - } - if (type === 'languagetool') { - return await stopLanguageToolService(request) - } - if (type === 'n8n') { - return await stopN8nService(request) - } - if (type === 'uptimekuma') { - return await stopUptimekumaService(request) - } - if (type === 'ghost') { - return await stopGhostService(request) - } - if (type === 'meilisearch') { - return await stopMeilisearchService(request) - } - if (type === 'umami') { - return await stopUmamiService(request) - } - if (type === 'hasura') { - return await stopHasuraService(request) - } - if (type === 'fider') { - return await stopFiderService(request) - } - if (type === 'appwrite') { - return await stopAppWriteService(request) - } - if (type === 'moodle') { - return await stopMoodleService(request) - } - throw `Service type ${type} not supported.` + return await stopServiceContainers(request) + // const { type } = request.params + // if (type === 'plausibleanalytics') { + // return await stopPlausibleAnalyticsService(request) + // } + // if (type === 'nocodb') { + // return await stopNocodbService(request) + // } + // if (type === 'minio') { + // return await stopMinioService(request) + // } + // if (type === 'vscodeserver') { + // return await stopVscodeService(request) + // } + // if (type === 'wordpress') { + // return await stopWordpressService(request) + // } + // if (type === 'vaultwarden') { + // return await stopVaultwardenService(request) + // } + // if (type === 'languagetool') { + // return await stopLanguageToolService(request) + // } + // if (type === 'n8n') { + // return await stopN8nService(request) + // } + // if (type === 'uptimekuma') { + // return await stopUptimekumaService(request) + // } + // if (type === 'ghost') { + // return await stopGhostService(request) + // } + // if (type === 'meilisearch') { + // return await stopMeilisearchService(request) + // } + // if (type === 'umami') { + // return await stopUmamiService(request) + // } + // if (type === 'hasura') { + // return await stopHasuraService(request) + // } + // if (type === 'fider') { + // return await stopFiderService(request) + // } + // if (type === 'moodle') { + // return await stopMoodleService(request) + // } + // throw `Service type ${type} not supported.` } catch (error) { throw { status: 500, message: error?.message || error } } @@ -805,52 +802,25 @@ COPY ./init-db.sh /docker-entrypoint-initdb.d/init-db.sh`; volumes, command: 'sh -c "sleep 10 && /entrypoint.sh db createdb && /entrypoint.sh db migrate && /entrypoint.sh db init-admin && /entrypoint.sh run"', - networks: [network], environment: config.plausibleAnalytics.environmentVariables, - restart: 'always', ...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}), depends_on: [`${id}-postgresql`, `${id}-clickhouse`], labels: makeLabelForServices('plausibleAnalytics'), - deploy: { - restart_policy: { - condition: 'on-failure', - delay: '10s', - max_attempts: 5, - window: '120s' - } - } + ...defaultServiceComposeConfiguration(network), }, [`${id}-postgresql`]: { container_name: `${id}-postgresql`, image: config.postgresql.image, - networks: [network], environment: config.postgresql.environmentVariables, volumes: [config.postgresql.volume], - restart: 'always', - deploy: { - restart_policy: { - condition: 'on-failure', - delay: '10s', - max_attempts: 5, - window: '120s' - } - } + ...defaultServiceComposeConfiguration(network), }, [`${id}-clickhouse`]: { build: workdir, container_name: `${id}-clickhouse`, - networks: [network], environment: config.clickhouse.environmentVariables, volumes: [config.clickhouse.volume], - restart: 'always', - deploy: { - restart_policy: { - condition: 'on-failure', - delay: '10s', - max_attempts: 5, - window: '120s' - } - } + ...defaultServiceComposeConfiguration(network), } }, networks: { @@ -870,36 +840,7 @@ COPY ./init-db.sh /docker-entrypoint-initdb.d/init-db.sh`; }; const composeFileDestination = `${workdir}/docker-compose.yaml`; await fs.writeFile(composeFileDestination, yaml.dump(composeFile)); - await executeDockerCmd({ dockerId: destinationDocker.id, command: `docker compose -f ${composeFileDestination} pull` }) - await executeDockerCmd({ dockerId: destinationDocker.id, command: `docker compose -f ${composeFileDestination} up --build -d` }) - return {} - } catch ({ status, message }) { - return errorHandler({ status, message }) - } -} -async function stopPlausibleAnalyticsService(request: FastifyRequest) { - try { - const { id } = request.params; - const teamId = request.user.teamId; - const service = await getServiceFromDB({ id, teamId }); - const { destinationDockerId, destinationDocker, fqdn } = service; - if (destinationDockerId) { - const engine = destinationDocker.engine; - - let found = await checkContainer({ dockerId: destinationDocker.id, container: id }); - if (found) { - await removeContainer({ id, dockerId: destinationDocker.id }); - } - found = await checkContainer({ dockerId: destinationDocker.id, container: `${id}-postgresql` }); - if (found) { - await removeContainer({ id: `${id}-postgresql`, dockerId: destinationDocker.id }); - } - found = await checkContainer({ dockerId: destinationDocker.id, container: `${id}-clickhouse` }); - if (found) { - await removeContainer({ id: `${id}-clickhouse`, dockerId: destinationDocker.id }); - } - } - + await startServiceContainers(destinationDocker.id, composeFileDestination) return {} } catch ({ status, message }) { return errorHandler({ status, message }) @@ -936,20 +877,11 @@ async function startNocodbService(request: FastifyRequest) { [id]: { container_name: id, image: config.image, - networks: [network], volumes, environment: config.environmentVariables, - restart: 'always', ...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}), labels: makeLabelForServices('nocodb'), - deploy: { - restart_policy: { - condition: 'on-failure', - delay: '5s', - max_attempts: 3, - window: '120s' - } - } + ...defaultServiceComposeConfiguration(network), } }, networks: { @@ -961,25 +893,7 @@ async function startNocodbService(request: FastifyRequest) { }; const composeFileDestination = `${workdir}/docker-compose.yaml`; await fs.writeFile(composeFileDestination, yaml.dump(composeFile)); - await executeDockerCmd({ dockerId: destinationDocker.id, command: `docker compose -f ${composeFileDestination} pull` }) - await executeDockerCmd({ dockerId: destinationDocker.id, command: `docker compose -f ${composeFileDestination} up --build -d` }) - return {} - } catch ({ status, message }) { - return errorHandler({ status, message }) - } -} -async function stopNocodbService(request: FastifyRequest) { - try { - const { id } = request.params; - const teamId = request.user.teamId; - const service = await getServiceFromDB({ id, teamId }); - const { destinationDockerId, destinationDocker, fqdn } = service; - if (destinationDockerId) { - const found = await checkContainer({ dockerId: destinationDocker.id, container: id }); - if (found) { - await removeContainer({ id, dockerId: destinationDocker.id }); - } - } + await startServiceContainers(destinationDocker.id, composeFileDestination) return {} } catch ({ status, message }) { return errorHandler({ status, message }) @@ -1036,19 +950,10 @@ async function startMinioService(request: FastifyRequest) { image: config.image, command: `server /data --console-address ":${consolePort}"`, environment: config.environmentVariables, - networks: [network], volumes, - restart: 'always', ...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}), labels: makeLabelForServices('minio'), - deploy: { - restart_policy: { - condition: 'on-failure', - delay: '5s', - max_attempts: 3, - window: '120s' - } - } + ...defaultServiceComposeConfiguration(network), } }, networks: { @@ -1060,32 +965,13 @@ async function startMinioService(request: FastifyRequest) { }; const composeFileDestination = `${workdir}/docker-compose.yaml`; await fs.writeFile(composeFileDestination, yaml.dump(composeFile)); - await executeDockerCmd({ dockerId: destinationDocker.id, command: `docker compose -f ${composeFileDestination} pull` }) - await executeDockerCmd({ dockerId: destinationDocker.id, command: `docker compose -f ${composeFileDestination} up --build -d` }) + await startServiceContainers(destinationDocker.id, composeFileDestination) await prisma.minio.update({ where: { serviceId: id }, data: { publicPort } }); return {} } catch ({ status, message }) { return errorHandler({ status, message }) } } -async function stopMinioService(request: FastifyRequest) { - try { - const { id } = request.params; - const teamId = request.user.teamId; - const service = await getServiceFromDB({ id, teamId }); - const { destinationDockerId, destinationDocker } = service; - await prisma.minio.update({ where: { serviceId: id }, data: { publicPort: null } }) - if (destinationDockerId) { - const found = await checkContainer({ dockerId: destinationDocker.id, container: id }); - if (found) { - await removeContainer({ id, dockerId: destinationDocker.id }); - } - } - return {} - } catch ({ status, message }) { - return errorHandler({ status, message }) - } -} async function startVscodeService(request: FastifyRequest) { try { @@ -1130,19 +1016,10 @@ async function startVscodeService(request: FastifyRequest) { container_name: id, image: config.image, environment: config.environmentVariables, - networks: [network], volumes, - restart: 'always', ...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}), labels: makeLabelForServices('vscodeServer'), - deploy: { - restart_policy: { - condition: 'on-failure', - delay: '5s', - max_attempts: 3, - window: '120s' - } - } + ...defaultServiceComposeConfiguration(network), } }, networks: { @@ -1155,8 +1032,7 @@ async function startVscodeService(request: FastifyRequest) { const composeFileDestination = `${workdir}/docker-compose.yaml`; await fs.writeFile(composeFileDestination, yaml.dump(composeFile)); - await executeDockerCmd({ dockerId: destinationDocker.id, command: `docker compose -f ${composeFileDestination} pull` }) - await executeDockerCmd({ dockerId: destinationDocker.id, command: `docker compose -f ${composeFileDestination} up --build -d` }) + await startServiceContainers(destinationDocker.id, composeFileDestination) const changePermissionOn = persistentStorage.map((p) => p.path); if (changePermissionOn.length > 0) { @@ -1171,23 +1047,6 @@ async function startVscodeService(request: FastifyRequest) { return errorHandler({ status, message }) } } -async function stopVscodeService(request: FastifyRequest) { - try { - const { id } = request.params; - const teamId = request.user.teamId; - const service = await getServiceFromDB({ id, teamId }); - const { destinationDockerId, destinationDocker } = service; - if (destinationDockerId) { - const found = await checkContainer({ dockerId: destinationDocker.id, container: id }); - if (found) { - await removeContainer({ id, dockerId: destinationDocker.id }); - } - } - return {} - } catch ({ status, message }) { - return errorHandler({ status, message }) - } -} async function startWordpressService(request: FastifyRequest) { try { @@ -1195,6 +1054,7 @@ async function startWordpressService(request: FastifyRequest) const teamId = request.user.teamId; const service = await getServiceFromDB({ id, teamId }); const { + arch, type, version, destinationDockerId, @@ -1244,6 +1104,10 @@ async function startWordpressService(request: FastifyRequest) } } }; + if (isARM(arch)) { + config.mysql.image = 'mysql:5.7' + config.mysql.volume = `${id}-mysql-data:/var/lib/mysql` + } if (serviceSecret.length > 0) { serviceSecret.forEach((secret) => { config.wordpress.environmentVariables[secret.name] = secret.value; @@ -1260,18 +1124,9 @@ async function startWordpressService(request: FastifyRequest) image: config.wordpress.image, environment: config.wordpress.environmentVariables, volumes, - networks: [network], - restart: 'always', ...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}), labels: makeLabelForServices('wordpress'), - deploy: { - restart_policy: { - condition: 'on-failure', - delay: '5s', - max_attempts: 3, - window: '120s' - } - } + ...defaultServiceComposeConfiguration(network), } }, networks: { @@ -1288,16 +1143,7 @@ async function startWordpressService(request: FastifyRequest) 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' - } - } + ...defaultServiceComposeConfiguration(network), }; composeFile.volumes[config.mysql.volume.split(':')[0]] = { @@ -1307,61 +1153,13 @@ async function startWordpressService(request: FastifyRequest) const composeFileDestination = `${workdir}/docker-compose.yaml`; await fs.writeFile(composeFileDestination, yaml.dump(composeFile)); - await executeDockerCmd({ dockerId: destinationDocker.id, command: `docker compose -f ${composeFileDestination} pull` }) - await executeDockerCmd({ dockerId: destinationDocker.id, command: `docker compose -f ${composeFileDestination} up --build -d` }) + await startServiceContainers(destinationDocker.id, composeFileDestination) return {} } catch ({ status, message }) { return errorHandler({ status, message }) } } -async function stopWordpressService(request: FastifyRequest) { - try { - const { id } = request.params; - const teamId = request.user.teamId; - const service = await getServiceFromDB({ id, teamId }); - const { - destinationDockerId, - destinationDocker, - wordpress: { ftpEnabled } - } = service; - if (destinationDockerId) { - try { - const found = await checkContainer({ dockerId: destinationDocker.id, container: id }); - if (found) { - await removeContainer({ id, dockerId: destinationDocker.id }); - } - } catch (error) { - console.error(error); - } - try { - const found = await checkContainer({ dockerId: destinationDocker.id, container: `${id}-mysql` }); - if (found) { - await removeContainer({ id: `${id}-mysql`, dockerId: destinationDocker.id }); - } - } catch (error) { - console.error(error); - } - try { - if (ftpEnabled) { - const found = await checkContainer({ dockerId: destinationDocker.id, container: `${id}-ftp` }); - if (found) { - await removeContainer({ id: `${id}-ftp`, dockerId: destinationDocker.id }); - } - await prisma.wordpress.update({ - where: { serviceId: id }, - data: { ftpEnabled: false } - }); - } - } catch (error) { - console.error(error); - } - } - return {} - } catch ({ status, message }) { - return errorHandler({ status, message }) - } -} async function startVaultwardenService(request: FastifyRequest) { try { @@ -1395,19 +1193,10 @@ async function startVaultwardenService(request: FastifyRequest container_name: id, image: config.image, environment: config.environmentVariables, - networks: [network], volumes, - restart: 'always', ...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}), labels: makeLabelForServices('vaultWarden'), - deploy: { - restart_policy: { - condition: 'on-failure', - delay: '5s', - max_attempts: 3, - window: '120s' - } - } + ...defaultServiceComposeConfiguration(network), } }, networks: { @@ -1420,35 +1209,13 @@ async function startVaultwardenService(request: FastifyRequest const composeFileDestination = `${workdir}/docker-compose.yaml`; await fs.writeFile(composeFileDestination, yaml.dump(composeFile)); - await executeDockerCmd({ dockerId: destinationDocker.id, command: `docker compose -f ${composeFileDestination} pull` }) - await executeDockerCmd({ dockerId: destinationDocker.id, command: `docker compose -f ${composeFileDestination} up --build -d` }) + await startServiceContainers(destinationDocker.id, composeFileDestination) return {} } catch ({ status, message }) { return errorHandler({ status, message }) } } -async function stopVaultwardenService(request: FastifyRequest) { - try { - const { id } = request.params; - const teamId = request.user.teamId; - const service = await getServiceFromDB({ id, teamId }); - const { destinationDockerId, destinationDocker } = service; - if (destinationDockerId) { - try { - const found = await checkContainer({ dockerId: destinationDocker.id, container: id }); - if (found) { - await removeContainer({ id, dockerId: destinationDocker.id }); - } - } catch (error) { - console.error(error); - } - } - return {} - } catch ({ status, message }) { - return errorHandler({ status, message }) - } -} async function startLanguageToolService(request: FastifyRequest) { try { @@ -1481,20 +1248,11 @@ async function startLanguageToolService(request: FastifyRequest) { - try { - const { id } = request.params; - const teamId = request.user.teamId; - const service = await getServiceFromDB({ id, teamId }); - const { destinationDockerId, destinationDocker } = service; - if (destinationDockerId) { - try { - const found = await checkContainer({ dockerId: destinationDocker.id, container: id }); - if (found) { - await removeContainer({ id, dockerId: destinationDocker.id }); - } - } catch (error) { - console.error(error); - } - } - return {} - } catch ({ status, message }) { - return errorHandler({ status, message }) - } -} async function startN8nService(request: FastifyRequest) { try { @@ -1569,20 +1305,11 @@ async function startN8nService(request: FastifyRequest) { [id]: { container_name: id, image: config.image, - networks: [network], volumes, environment: config.environmentVariables, - restart: 'always', labels: makeLabelForServices('n8n'), ...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}), - deploy: { - restart_policy: { - condition: 'on-failure', - delay: '5s', - max_attempts: 3, - window: '120s' - } - } + ...defaultServiceComposeConfiguration(network), } }, networks: { @@ -1595,35 +1322,13 @@ async function startN8nService(request: FastifyRequest) { const composeFileDestination = `${workdir}/docker-compose.yaml`; await fs.writeFile(composeFileDestination, yaml.dump(composeFile)); - await executeDockerCmd({ dockerId: destinationDocker.id, command: `docker compose -f ${composeFileDestination} pull` }) - await executeDockerCmd({ dockerId: destinationDocker.id, command: `docker compose -f ${composeFileDestination} up --build -d` }) + await startServiceContainers(destinationDocker.id, composeFileDestination) return {} } catch ({ status, message }) { return errorHandler({ status, message }) } } -async function stopN8nService(request: FastifyRequest) { - try { - const { id } = request.params; - const teamId = request.user.teamId; - const service = await getServiceFromDB({ id, teamId }); - const { destinationDockerId, destinationDocker } = service; - if (destinationDockerId) { - try { - const found = await checkContainer({ dockerId: destinationDocker.id, container: id }); - if (found) { - await removeContainer({ id, dockerId: destinationDocker.id }); - } - } catch (error) { - console.error(error); - } - } - return {} - } catch ({ status, message }) { - return errorHandler({ status, message }) - } -} async function startUptimekumaService(request: FastifyRequest) { try { @@ -1655,20 +1360,11 @@ async function startUptimekumaService(request: FastifyRequest) [id]: { container_name: id, image: config.image, - networks: [network], volumes, environment: config.environmentVariables, - restart: 'always', ...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}), labels: makeLabelForServices('uptimekuma'), - deploy: { - restart_policy: { - condition: 'on-failure', - delay: '5s', - max_attempts: 3, - window: '120s' - } - } + ...defaultServiceComposeConfiguration(network), } }, networks: { @@ -1681,35 +1377,13 @@ async function startUptimekumaService(request: FastifyRequest) const composeFileDestination = `${workdir}/docker-compose.yaml`; await fs.writeFile(composeFileDestination, yaml.dump(composeFile)); - await executeDockerCmd({ dockerId: destinationDocker.id, command: `docker compose -f ${composeFileDestination} pull` }) - await executeDockerCmd({ dockerId: destinationDocker.id, command: `docker compose -f ${composeFileDestination} up --build -d` }) + await startServiceContainers(destinationDocker.id, composeFileDestination) return {} } catch ({ status, message }) { return errorHandler({ status, message }) } } -async function stopUptimekumaService(request: FastifyRequest) { - try { - const { id } = request.params; - const teamId = request.user.teamId; - const service = await getServiceFromDB({ id, teamId }); - const { destinationDockerId, destinationDocker } = service; - if (destinationDockerId) { - try { - const found = await checkContainer({ dockerId: destinationDocker.id, container: id }); - if (found) { - await removeContainer({ id, dockerId: destinationDocker.id }); - } - } catch (error) { - console.error(error); - } - } - return {} - } catch ({ status, message }) { - return errorHandler({ status, message }) - } -} async function startGhostService(request: FastifyRequest) { try { @@ -1784,37 +1458,19 @@ async function startGhostService(request: FastifyRequest) { [id]: { container_name: id, image: config.ghost.image, - networks: [network], volumes, environment: config.ghost.environmentVariables, - restart: 'always', ...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}), labels: makeLabelForServices('ghost'), depends_on: [`${id}-mariadb`], - deploy: { - restart_policy: { - condition: 'on-failure', - delay: '5s', - max_attempts: 3, - window: '120s' - } - } + ...defaultServiceComposeConfiguration(network), }, [`${id}-mariadb`]: { container_name: `${id}-mariadb`, image: config.mariadb.image, - networks: [network], volumes: [config.mariadb.volume], environment: config.mariadb.environmentVariables, - restart: 'always', - deploy: { - restart_policy: { - condition: 'on-failure', - delay: '5s', - max_attempts: 3, - window: '120s' - } - } + ...defaultServiceComposeConfiguration(network), } }, networks: { @@ -1832,39 +1488,13 @@ async function startGhostService(request: FastifyRequest) { const composeFileDestination = `${workdir}/docker-compose.yaml`; await fs.writeFile(composeFileDestination, yaml.dump(composeFile)); - await executeDockerCmd({ dockerId: destinationDocker.id, command: `docker compose -f ${composeFileDestination} pull` }) - await executeDockerCmd({ dockerId: destinationDocker.id, command: `docker compose -f ${composeFileDestination} up --build -d` }) + await startServiceContainers(destinationDocker.id, composeFileDestination) return {} } catch ({ status, message }) { return errorHandler({ status, message }) } } -async function stopGhostService(request: FastifyRequest) { - try { - const { id } = request.params; - const teamId = request.user.teamId; - const service = await getServiceFromDB({ id, teamId }); - const { destinationDockerId, destinationDocker } = service; - if (destinationDockerId) { - try { - let found = await checkContainer({ dockerId: destinationDocker.id, container: id }); - if (found) { - await removeContainer({ id, dockerId: destinationDocker.id }); - } - found = await checkContainer({ dockerId: destinationDocker.id, container: `${id}-mariadb` }); - if (found) { - await removeContainer({ id: `${id}-mariadb`, dockerId: destinationDocker.id }); - } - } catch (error) { - console.error(error); - } - } - return {} - } catch ({ status, message }) { - return errorHandler({ status, message }) - } -} async function startMeilisearchService(request: FastifyRequest) { try { @@ -1902,20 +1532,11 @@ async function startMeilisearchService(request: FastifyRequest [id]: { container_name: id, image: config.image, - networks: [network], environment: config.environmentVariables, - restart: 'always', ...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}), volumes, labels: makeLabelForServices('meilisearch'), - deploy: { - restart_policy: { - condition: 'on-failure', - delay: '5s', - max_attempts: 3, - window: '120s' - } - } + ...defaultServiceComposeConfiguration(network), } }, networks: { @@ -1927,29 +1548,7 @@ async function startMeilisearchService(request: FastifyRequest }; const composeFileDestination = `${workdir}/docker-compose.yaml`; await fs.writeFile(composeFileDestination, yaml.dump(composeFile)); - await executeDockerCmd({ dockerId: destinationDocker.id, command: `docker compose -f ${composeFileDestination} pull` }) - await executeDockerCmd({ dockerId: destinationDocker.id, command: `docker compose -f ${composeFileDestination} up --build -d` }) - return {} - } catch ({ status, message }) { - return errorHandler({ status, message }) - } -} -async function stopMeilisearchService(request: FastifyRequest) { - try { - const { id } = request.params; - const teamId = request.user.teamId; - const service = await getServiceFromDB({ id, teamId }); - const { destinationDockerId, destinationDocker } = service; - if (destinationDockerId) { - try { - const found = await checkContainer({ dockerId: destinationDocker.id, container: id }); - if (found) { - await removeContainer({ id, dockerId: destinationDocker.id }); - } - } catch (error) { - console.error(error); - } - } + await startServiceContainers(destinationDocker.id, composeFileDestination) return {} } catch ({ status, message }) { return errorHandler({ status, message }) @@ -2099,36 +1698,18 @@ async function startUmamiService(request: FastifyRequest) { container_name: id, image: config.umami.image, environment: config.umami.environmentVariables, - networks: [network], volumes, - restart: 'always', ...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}), labels: makeLabelForServices('umami'), - deploy: { - restart_policy: { - condition: 'on-failure', - delay: '5s', - max_attempts: 3, - window: '120s' - } - }, - depends_on: [`${id}-postgresql`] + depends_on: [`${id}-postgresql`], + ...defaultServiceComposeConfiguration(network), }, [`${id}-postgresql`]: { build: workdir, container_name: `${id}-postgresql`, environment: config.postgresql.environmentVariables, - networks: [network], volumes: [config.postgresql.volume], - restart: 'always', - deploy: { - restart_policy: { - condition: 'on-failure', - delay: '5s', - max_attempts: 3, - window: '120s' - } - } + ...defaultServiceComposeConfiguration(network), } }, networks: { @@ -2145,37 +1726,7 @@ async function startUmamiService(request: FastifyRequest) { }; const composeFileDestination = `${workdir}/docker-compose.yaml`; await fs.writeFile(composeFileDestination, yaml.dump(composeFile)); - await executeDockerCmd({ dockerId: destinationDocker.id, command: `docker compose -f ${composeFileDestination} pull` }) - await executeDockerCmd({ dockerId: destinationDocker.id, command: `docker compose -f ${composeFileDestination} up --build -d` }) - return {} - } catch ({ status, message }) { - return errorHandler({ status, message }) - } -} -async function stopUmamiService(request: FastifyRequest) { - try { - const { id } = request.params; - const teamId = request.user.teamId; - const service = await getServiceFromDB({ id, teamId }); - const { destinationDockerId, destinationDocker } = service; - if (destinationDockerId) { - try { - const found = await checkContainer({ dockerId: destinationDocker.id, container: id }); - if (found) { - await removeContainer({ id, dockerId: destinationDocker.id }); - } - } catch (error) { - console.error(error); - } - try { - const found = await checkContainer({ dockerId: destinationDocker.id, container: `${id}-postgresql` }); - if (found) { - await removeContainer({ id: `${id}-postgresql`, dockerId: destinationDocker.id }); - } - } catch (error) { - console.error(error); - } - } + await startServiceContainers(destinationDocker.id, composeFileDestination) return {} } catch ({ status, message }) { return errorHandler({ status, message }) @@ -2234,36 +1785,18 @@ async function startHasuraService(request: FastifyRequest) { container_name: id, image: config.hasura.image, environment: config.hasura.environmentVariables, - networks: [network], volumes, - restart: 'always', labels: makeLabelForServices('hasura'), ...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}), - deploy: { - restart_policy: { - condition: 'on-failure', - delay: '5s', - max_attempts: 3, - window: '120s' - } - }, - depends_on: [`${id}-postgresql`] + depends_on: [`${id}-postgresql`], + ...defaultServiceComposeConfiguration(network), }, [`${id}-postgresql`]: { image: config.postgresql.image, container_name: `${id}-postgresql`, environment: config.postgresql.environmentVariables, - networks: [network], volumes: [config.postgresql.volume], - restart: 'always', - deploy: { - restart_policy: { - condition: 'on-failure', - delay: '5s', - max_attempts: 3, - window: '120s' - } - } + ...defaultServiceComposeConfiguration(network), } }, networks: { @@ -2281,43 +1814,13 @@ async function startHasuraService(request: FastifyRequest) { const composeFileDestination = `${workdir}/docker-compose.yaml`; await fs.writeFile(composeFileDestination, yaml.dump(composeFile)); - await executeDockerCmd({ dockerId: destinationDocker.id, command: `docker compose -f ${composeFileDestination} pull` }) - await executeDockerCmd({ dockerId: destinationDocker.id, command: `docker compose -f ${composeFileDestination} up --build -d` }) + await startServiceContainers(destinationDocker.id, composeFileDestination) return {} } catch ({ status, message }) { return errorHandler({ status, message }) } } -async function stopHasuraService(request: FastifyRequest) { - try { - const { id } = request.params; - const teamId = request.user.teamId; - const service = await getServiceFromDB({ id, teamId }); - const { destinationDockerId, destinationDocker } = service; - if (destinationDockerId) { - try { - const found = await checkContainer({ dockerId: destinationDocker.id, container: id }); - if (found) { - await removeContainer({ id, dockerId: destinationDocker.id }); - } - } catch (error) { - console.error(error); - } - try { - const found = await checkContainer({ dockerId: destinationDocker.id, container: `${id}-postgresql` }); - if (found) { - await removeContainer({ id: `${id}-postgresql`, dockerId: destinationDocker.id }); - } - } catch (error) { - console.error(error); - } - } - return {} - } catch ({ status, message }) { - return errorHandler({ status, message }) - } -} async function startFiderService(request: FastifyRequest) { try { @@ -2395,36 +1898,18 @@ async function startFiderService(request: FastifyRequest) { container_name: id, image: config.fider.image, environment: config.fider.environmentVariables, - networks: [network], volumes, - restart: 'always', labels: makeLabelForServices('fider'), ...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}), - deploy: { - restart_policy: { - condition: 'on-failure', - delay: '5s', - max_attempts: 3, - window: '120s' - } - }, - depends_on: [`${id}-postgresql`] + depends_on: [`${id}-postgresql`], + ...defaultServiceComposeConfiguration(network), }, [`${id}-postgresql`]: { image: config.postgresql.image, container_name: `${id}-postgresql`, environment: config.postgresql.environmentVariables, - networks: [network], volumes: [config.postgresql.volume], - restart: 'always', - deploy: { - restart_policy: { - condition: 'on-failure', - delay: '5s', - max_attempts: 3, - window: '120s' - } - } + ...defaultServiceComposeConfiguration(network), } }, networks: { @@ -2442,43 +1927,14 @@ async function startFiderService(request: FastifyRequest) { const composeFileDestination = `${workdir}/docker-compose.yaml`; await fs.writeFile(composeFileDestination, yaml.dump(composeFile)); - await executeDockerCmd({ dockerId: destinationDocker.id, command: `docker compose -f ${composeFileDestination} pull` }) - await executeDockerCmd({ dockerId: destinationDocker.id, command: `docker compose -f ${composeFileDestination} up --build -d` }) + await startServiceContainers(destinationDocker.id, composeFileDestination) return {} } catch ({ status, message }) { return errorHandler({ status, message }) } } -async function stopFiderService(request: FastifyRequest) { - try { - const { id } = request.params; - const teamId = request.user.teamId; - const service = await getServiceFromDB({ id, teamId }); - const { destinationDockerId, destinationDocker } = service; - if (destinationDockerId) { - try { - const found = await checkContainer({ dockerId: destinationDocker.id, container: id }); - if (found) { - await removeContainer({ id, dockerId: destinationDocker.id }); - } - } catch (error) { - console.error(error); - } - try { - const found = await checkContainer({ dockerId: destinationDocker.id, container: `${id}-postgresql` }); - if (found) { - await removeContainer({ id: `${id}-postgresql`, dockerId: destinationDocker.id }); - } - } catch (error) { - console.error(error); - } - } - return {} - } catch ({ status, message }) { - return errorHandler({ status, message }) - } -} + async function startAppWriteService(request: FastifyRequest) { try { const { id } = request.params; @@ -2486,7 +1942,7 @@ async function startAppWriteService(request: FastifyRequest) { const { version, fqdn, destinationDocker, secrets, exposePort, network, port, workdir, image, appwrite } = await defaultServiceConfigurations({ id, teamId }) let isStatsEnabled = false - if (secrets._APP_USAGE_STATS) { + if (secrets.find(s => s === '_APP_USAGE_STATS=enabled')) { isStatsEnabled = true } const { @@ -2503,7 +1959,6 @@ async function startAppWriteService(request: FastifyRequest) { const dockerCompose = { [id]: { - ...defaultServiceComposeConfiguration(network), image: `${image}:${version}`, container_name: id, labels: makeLabelForServices('appwrite'), @@ -2533,16 +1988,16 @@ async function startAppWriteService(request: FastifyRequest) { `_APP_DB_USER=${mariadbUser}`, `_APP_DB_PASS=${mariadbPassword}`, `_APP_INFLUXDB_HOST=${id}-influxdb`, - "_APP_INFLUXDB_PORT=8806", + "_APP_INFLUXDB_PORT=8086", `_APP_EXECUTOR_SECRET=${executorSecret}`, `_APP_EXECUTOR_HOST=http://${id}-executor/v1`, `_APP_STATSD_HOST=${id}-telegraf`, "_APP_STATSD_PORT=8125", ...secrets - ] + ], + ...defaultServiceComposeConfiguration(network), }, [`${id}-realtime`]: { - ...defaultServiceComposeConfiguration(network), image: `${image}:${version}`, container_name: `${id}-realtime`, entrypoint: "realtime", @@ -2562,10 +2017,11 @@ async function startAppWriteService(request: FastifyRequest) { `_APP_DB_USER=${mariadbUser}`, `_APP_DB_PASS=${mariadbPassword}`, ...secrets - ] + ], + ...defaultServiceComposeConfiguration(network), }, [`${id}-worker-audits`]: { - ...defaultServiceComposeConfiguration(network), + image: `${image}:${version}`, container_name: `${id}-worker-audits`, labels: makeLabelForServices('appwrite'), @@ -2585,10 +2041,10 @@ async function startAppWriteService(request: FastifyRequest) { `_APP_DB_USER=${mariadbUser}`, `_APP_DB_PASS=${mariadbPassword}`, ...secrets - ] + ], + ...defaultServiceComposeConfiguration(network), }, [`${id}-worker-webhooks`]: { - ...defaultServiceComposeConfiguration(network), image: `${image}:${version}`, container_name: `${id}-worker-webhooks`, labels: makeLabelForServices('appwrite'), @@ -2603,10 +2059,10 @@ async function startAppWriteService(request: FastifyRequest) { `_APP_REDIS_HOST=${id}-redis`, "_APP_REDIS_PORT=6379", ...secrets - ] + ], + ...defaultServiceComposeConfiguration(network), }, [`${id}-worker-deletes`]: { - ...defaultServiceComposeConfiguration(network), image: `${image}:${version}`, container_name: `${id}-worker-deletes`, labels: makeLabelForServices('appwrite'), @@ -2636,10 +2092,10 @@ async function startAppWriteService(request: FastifyRequest) { `_APP_EXECUTOR_SECRET=${executorSecret}`, `_APP_EXECUTOR_HOST=http://${id}-executor/v1`, ...secrets - ] + ], + ...defaultServiceComposeConfiguration(network), }, [`${id}-worker-databases`]: { - ...defaultServiceComposeConfiguration(network), image: `${image}:${version}`, container_name: `${id}-worker-databases`, labels: makeLabelForServices('appwrite'), @@ -2659,10 +2115,10 @@ async function startAppWriteService(request: FastifyRequest) { `_APP_DB_USER=${mariadbUser}`, `_APP_DB_PASS=${mariadbPassword}`, ...secrets - ] + ], + ...defaultServiceComposeConfiguration(network), }, [`${id}-worker-builds`]: { - ...defaultServiceComposeConfiguration(network), image: `${image}:${version}`, container_name: `${id}-worker-builds`, labels: makeLabelForServices('appwrite'), @@ -2684,10 +2140,10 @@ async function startAppWriteService(request: FastifyRequest) { `_APP_DB_USER=${mariadbUser}`, `_APP_DB_PASS=${mariadbPassword}`, ...secrets - ] + ], + ...defaultServiceComposeConfiguration(network), }, [`${id}-worker-certificates`]: { - ...defaultServiceComposeConfiguration(network), image: `${image}:${version}`, container_name: `${id}-worker-certificates`, labels: makeLabelForServices('appwrite'), @@ -2713,10 +2169,10 @@ async function startAppWriteService(request: FastifyRequest) { `_APP_DB_USER=${mariadbUser}`, `_APP_DB_PASS=${mariadbPassword}`, ...secrets - ] + ], + ...defaultServiceComposeConfiguration(network), }, [`${id}-worker-functions`]: { - ...defaultServiceComposeConfiguration(network), image: `${image}:${version}`, container_name: `${id}-worker-functions`, labels: makeLabelForServices('appwrite'), @@ -2739,10 +2195,10 @@ async function startAppWriteService(request: FastifyRequest) { `_APP_EXECUTOR_SECRET=${executorSecret}`, `_APP_EXECUTOR_HOST=http://${id}-executor/v1`, ...secrets - ] + ], + ...defaultServiceComposeConfiguration(network), }, [`${id}-executor`]: { - ...defaultServiceComposeConfiguration(network), image: `${image}:${version}`, container_name: `${id}-executor`, labels: makeLabelForServices('appwrite'), @@ -2763,10 +2219,10 @@ async function startAppWriteService(request: FastifyRequest) { "_APP_ENV=production", `_APP_EXECUTOR_SECRET=${executorSecret}`, ...secrets - ] + ], + ...defaultServiceComposeConfiguration(network), }, [`${id}-worker-mails`]: { - ...defaultServiceComposeConfiguration(network), image: `${image}:${version}`, container_name: `${id}-worker-mails`, labels: makeLabelForServices('appwrite'), @@ -2780,10 +2236,10 @@ async function startAppWriteService(request: FastifyRequest) { `_APP_REDIS_HOST=${id}-redis`, "_APP_REDIS_PORT=6379", ...secrets - ] + ], + ...defaultServiceComposeConfiguration(network), }, [`${id}-worker-messaging`]: { - ...defaultServiceComposeConfiguration(network), image: `${image}:${version}`, container_name: `${id}-worker-messaging`, labels: makeLabelForServices('appwrite'), @@ -2796,10 +2252,10 @@ async function startAppWriteService(request: FastifyRequest) { `_APP_REDIS_HOST=${id}-redis`, "_APP_REDIS_PORT=6379", ...secrets - ] + ], + ...defaultServiceComposeConfiguration(network), }, [`${id}-maintenance`]: { - ...defaultServiceComposeConfiguration(network), image: `${image}:${version}`, container_name: `${id}-maintenance`, labels: makeLabelForServices('appwrite'), @@ -2820,10 +2276,10 @@ async function startAppWriteService(request: FastifyRequest) { `_APP_DB_USER=${mariadbUser}`, `_APP_DB_PASS=${mariadbPassword}`, ...secrets - ] + ], + ...defaultServiceComposeConfiguration(network), }, [`${id}-schedule`]: { - ...defaultServiceComposeConfiguration(network), image: `${image}:${version}`, container_name: `${id}-schedule`, labels: makeLabelForServices('appwrite'), @@ -2836,10 +2292,10 @@ async function startAppWriteService(request: FastifyRequest) { `_APP_REDIS_HOST=${id}-redis`, "_APP_REDIS_PORT=6379", ...secrets - ] + ], + ...defaultServiceComposeConfiguration(network), }, [`${id}-mariadb`]: { - ...defaultServiceComposeConfiguration(network), "image": "mariadb:10.7", container_name: `${id}-mariadb`, labels: makeLabelForServices('appwrite'), @@ -2853,23 +2309,23 @@ async function startAppWriteService(request: FastifyRequest) { `MYSQL_PASSWORD=${mariadbPassword}`, `MYSQL_DATABASE=${mariadbDatabase}` ], - "command": "mysqld --innodb-flush-method=fsync" + "command": "mysqld --innodb-flush-method=fsync", + ...defaultServiceComposeConfiguration(network), }, [`${id}-redis`]: { - ...defaultServiceComposeConfiguration(network), "image": "redis:6.2-alpine", container_name: `${id}-redis`, "command": `redis-server --maxmemory 512mb --maxmemory-policy allkeys-lru --maxmemory-samples 5\n`, "volumes": [ `${id}-redis:/data:rw` - ] + ], + ...defaultServiceComposeConfiguration(network), }, }; if (isStatsEnabled) { - dockerCompose.id.depends_on.push(`${id}-influxdb`); + dockerCompose[id].depends_on.push(`${id}-influxdb`); dockerCompose[`${id}-usage`] = { - ...defaultServiceComposeConfiguration(network), image: `${image}:${version}`, container_name: `${id}-usage`, labels: makeLabelForServices('appwrite'), @@ -2887,28 +2343,29 @@ async function startAppWriteService(request: FastifyRequest) { `_APP_DB_USER=${mariadbUser}`, `_APP_DB_PASS=${mariadbPassword}`, `_APP_INFLUXDB_HOST=${id}-influxdb`, - "_APP_INFLUXDB_PORT=8806", + "_APP_INFLUXDB_PORT=8086", `_APP_REDIS_HOST=${id}-redis`, "_APP_REDIS_PORT=6379", ...secrets - ] + ], + ...defaultServiceComposeConfiguration(network), } dockerCompose[`${id}-influxdb`] = { - ...defaultServiceComposeConfiguration(network), "image": "appwrite/influxdb:1.5.0", container_name: `${id}-influxdb`, "volumes": [ `${id}-influxdb:/var/lib/influxdb:rw` - ] + ], + ...defaultServiceComposeConfiguration(network), } dockerCompose[`${id}-telegraf`] = { - ...defaultServiceComposeConfiguration(network), "image": "appwrite/telegraf:1.4.0", container_name: `${id}-telegraf`, "environment": [ `_APP_INFLUXDB_HOST=${id}-influxdb`, - "_APP_INFLUXDB_PORT=8806", - ] + "_APP_INFLUXDB_PORT=8086", + ], + ...defaultServiceComposeConfiguration(network), } } @@ -2954,32 +2411,37 @@ async function startAppWriteService(request: FastifyRequest) { const composeFileDestination = `${workdir}/docker-compose.yaml`; await fs.writeFile(composeFileDestination, yaml.dump(composeFile)); - await executeDockerCmd({ dockerId: destinationDocker.id, command: `docker compose -f ${composeFileDestination} pull` }) - await executeDockerCmd({ dockerId: destinationDocker.id, command: `docker compose -f ${composeFileDestination} up --build -d` }) + await startServiceContainers(destinationDocker.id, composeFileDestination) return {} } catch ({ status, message }) { return errorHandler({ status, message }) } } -async function stopAppWriteService(request: FastifyRequest) { +async function startServiceContainers(dockerId, composeFileDestination) { + await executeDockerCmd({ dockerId, command: `docker compose -f ${composeFileDestination} pull` }) + await executeDockerCmd({ dockerId, command: `docker compose -f ${composeFileDestination} create` }) + await executeDockerCmd({ dockerId, command: `docker compose -f ${composeFileDestination} start` }) + await asyncSleep(1000); + await executeDockerCmd({ dockerId, command: `docker compose -f ${composeFileDestination} up -d` }) +} +async function stopServiceContainers(request: FastifyRequest) { try { - // TODO: Fix async for of const { id } = request.params; const teamId = request.user.teamId; - const service = await getServiceFromDB({ id, teamId }); - const { destinationDockerId, destinationDocker } = service; - const containers = [`${id}-mariadb`, `${id}-redis`, `${id}-influxdb`, `${id}-telegraf`, id, `${id}-realtime`, `${id}-worker-audits`, `${id}worker-webhooks`, `${id}-worker-deletes`, `${id}-worker-databases`, `${id}-worker-builds`, `${id}-worker-certificates`, `${id}-worker-functions`, `${id}-worker-mails`, `${id}-worker-messaging`, `${id}-maintenance`, `${id}-schedule`, `${id}-executor`, `${id}-usage`] + const { destinationDockerId } = await getServiceFromDB({ id, teamId }); if (destinationDockerId) { - for (const container of containers) { - const found = await checkContainer({ dockerId: destinationDocker.id, container }); - if (found) { - await removeContainer({ id, dockerId: destinationDocker.id }); - } - - } + await executeDockerCmd({ + dockerId: destinationDockerId, + command: `docker ps -a --filter 'label=com.docker.compose.project=${id}' --format {{.ID}}|xargs -n 1 docker stop -t 0` + }) + await executeDockerCmd({ + dockerId: destinationDockerId, + command: `docker ps -a --filter 'label=com.docker.compose.project=${id}' --format {{.ID}}|xargs -n 1 docker rm --force` + }) + return {} } - return {} + throw { status: 500, message: 'Could not stop containers.' } } catch ({ status, message }) { return errorHandler({ status, message }) } @@ -3104,44 +2566,13 @@ async function startMoodleService(request: FastifyRequest) { const composeFileDestination = `${workdir}/docker-compose.yaml`; await fs.writeFile(composeFileDestination, yaml.dump(composeFile)); - await executeDockerCmd({ dockerId: destinationDocker.id, command: `docker compose -f ${composeFileDestination} pull` }) - await executeDockerCmd({ dockerId: destinationDocker.id, command: `docker compose -f ${composeFileDestination} up --build -d` }) + await startServiceContainers(destinationDocker.id, composeFileDestination) return {} } catch ({ status, message }) { return errorHandler({ status, message }) } } -async function stopMoodleService(request: FastifyRequest) { - try { - const { id } = request.params; - const teamId = request.user.teamId; - const service = await getServiceFromDB({ id, teamId }); - const { destinationDockerId, destinationDocker } = service; - if (destinationDockerId) { - try { - const found = await checkContainer({ dockerId: destinationDocker.id, container: id }); - if (found) { - await removeContainer({ id, dockerId: destinationDocker.id }); - } - } catch (error) { - console.error(error); - } - try { - const found = await checkContainer({ dockerId: destinationDocker.id, container: `${id}-mariadb` }); - if (found) { - await removeContainer({ id: `${id}-mariadb`, dockerId: destinationDocker.id }); - } - } catch (error) { - console.error(error); - } - } - return {} - } catch ({ status, message }) { - return errorHandler({ status, message }) - } -} - export async function activatePlausibleUsers(request: FastifyRequest, reply: FastifyReply) { try { diff --git a/apps/ui/src/lib/components/svg/services/Appwrite.svelte b/apps/ui/src/lib/components/svg/services/Appwrite.svelte new file mode 100644 index 000000000..9a774d0d3 --- /dev/null +++ b/apps/ui/src/lib/components/svg/services/Appwrite.svelte @@ -0,0 +1,21 @@ + + + + + + diff --git a/apps/ui/src/lib/components/svg/services/ServiceIcons.svelte b/apps/ui/src/lib/components/svg/services/ServiceIcons.svelte index 00e1bcf6e..c5f537736 100644 --- a/apps/ui/src/lib/components/svg/services/ServiceIcons.svelte +++ b/apps/ui/src/lib/components/svg/services/ServiceIcons.svelte @@ -32,6 +32,8 @@ {:else if type === 'fider'} +{:else if type === 'appwrite'} + {:else if type === 'moodle'} {/if} diff --git a/apps/ui/src/lib/components/svg/services/index.ts b/apps/ui/src/lib/components/svg/services/index.ts index e4f5bc749..1e47a5def 100644 --- a/apps/ui/src/lib/components/svg/services/index.ts +++ b/apps/ui/src/lib/components/svg/services/index.ts @@ -1,18 +1,18 @@ //@ts-nocheck export { default as PlausibleAnalytics } from './PlausibleAnalytics.svelte'; -export { default as NocoDb } from './NocoDB.svelte'; -export { default as MinIo } from './MinIO.svelte'; -export { default as VsCodeServer } from './VSCodeServer.svelte'; -export { default as Wordpress } from './Wordpress.svelte'; -export { default as VaultWarden } from './VaultWarden.svelte'; -export { default as LanguageTool } from './LanguageTool.svelte'; -export { default as N8n } from './N8n.svelte'; -export { default as UptimeKuma } from './UptimeKuma.svelte'; -export { default as Ghost } from './Ghost.svelte'; -export { default as MeiliSearch } from './MeiliSearch.svelte'; -export { default as Umami } from './Umami.svelte'; -export { default as Hasura } from './Hasura.svelte'; -export { default as Fider } from './Fider.svelte'; -export { default as Appwrite } from './Moodle.svelte'; -export { default as Moodle } from './Moodle.svelte'; +export { default as NocoDb } from './NocoDB.svelte'; +export { default as MinIo } from './MinIO.svelte'; +export { default as VsCodeServer } from './VSCodeServer.svelte'; +export { default as Wordpress } from './Wordpress.svelte'; +export { default as VaultWarden } from './VaultWarden.svelte'; +export { default as LanguageTool } from './LanguageTool.svelte'; +export { default as N8n } from './N8n.svelte'; +export { default as UptimeKuma } from './UptimeKuma.svelte'; +export { default as Ghost } from './Ghost.svelte'; +export { default as MeiliSearch } from './MeiliSearch.svelte'; +export { default as Umami } from './Umami.svelte'; +export { default as Hasura } from './Hasura.svelte'; +export { default as Fider } from './Fider.svelte'; +export { default as Appwrite } from './Appwrite.svelte'; +export { default as Moodle } from './Moodle.svelte'; diff --git a/apps/ui/src/routes/services/[id]/_ServiceLinks.svelte b/apps/ui/src/routes/services/[id]/_ServiceLinks.svelte index cad074ee5..9303a0fb2 100644 --- a/apps/ui/src/routes/services/[id]/_ServiceLinks.svelte +++ b/apps/ui/src/routes/services/[id]/_ServiceLinks.svelte @@ -55,7 +55,7 @@ -{:else if service.type === 'appwrote'} +{:else if service.type === 'appwrite'} diff --git a/apps/ui/src/routes/services/[id]/_Services/_Wordpress.svelte b/apps/ui/src/routes/services/[id]/_Services/_Wordpress.svelte index 61368c983..4d72fafd2 100644 --- a/apps/ui/src/routes/services/[id]/_Services/_Wordpress.svelte +++ b/apps/ui/src/routes/services/[id]/_Services/_Wordpress.svelte @@ -22,7 +22,7 @@ function generateUrl(publicPort: any) { return browser ? `sftp://${ - settings.fqdn ? getDomain(settings.fqdn) : window.location.hostname + settings?.fqdn ? getDomain(settings.fqdn) : window.location.hostname }:${publicPort}` : 'Loading...'; } From fb2a86ba3f5b318e8521e658b392fadf5a805983 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Tue, 16 Aug 2022 09:13:58 +0000 Subject: [PATCH 02/14] fix ui --- apps/ui/src/lib/components/svg/services/Appwrite.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/ui/src/lib/components/svg/services/Appwrite.svelte b/apps/ui/src/lib/components/svg/services/Appwrite.svelte index 9a774d0d3..fbabd5168 100644 --- a/apps/ui/src/lib/components/svg/services/Appwrite.svelte +++ b/apps/ui/src/lib/components/svg/services/Appwrite.svelte @@ -4,7 +4,7 @@ From 6150a008d50fd629bdba688321081a35273ed521 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Tue, 16 Aug 2022 09:38:34 +0000 Subject: [PATCH 03/14] fixes --- apps/api/src/lib/common.ts | 4 ++-- apps/ui/src/lib/common.ts | 4 ++-- .../applications/[id]/configuration/destination.svelte | 10 +++++++++- .../databases/[id]/configuration/destination.svelte | 10 +++++++++- apps/ui/src/routes/index.svelte | 2 +- apps/ui/src/routes/services/[id]/__layout.svelte | 1 - .../services/[id]/configuration/destination.svelte | 10 +++++++++- .../routes/services/[id]/configuration/version.svelte | 8 ++++++++ 8 files changed, 40 insertions(+), 9 deletions(-) diff --git a/apps/api/src/lib/common.ts b/apps/api/src/lib/common.ts index 6170d380c..d67125db3 100644 --- a/apps/api/src/lib/common.ts +++ b/apps/api/src/lib/common.ts @@ -260,8 +260,8 @@ export const supportedServiceTypesAndVersions = [ fancyName: 'Hasura', baseImage: 'hasura/graphql-engine', images: ['postgres:12-alpine'], - versions: ['latest', 'v2.8.4', 'v2.5.1'], - recommendedVersion: 'v2.8.4', + versions: ['latest', 'v2.10.0', 'v2.5.1'], + recommendedVersion: 'v2.10.0', ports: { main: 8080 } diff --git a/apps/ui/src/lib/common.ts b/apps/ui/src/lib/common.ts index 32485a522..08b863d57 100644 --- a/apps/ui/src/lib/common.ts +++ b/apps/ui/src/lib/common.ts @@ -131,8 +131,8 @@ export const supportedServiceTypesAndVersions = [ fancyName: 'Hasura', baseImage: 'hasura/graphql-engine', images: ['postgres:12-alpine'], - versions: ['latest', 'v2.5.1'], - recommendedVersion: 'v2.5.1', + versions: ['latest', 'v2.10.0', 'v2.5.1'], + recommendedVersion: 'v2.10.0', ports: { main: 8080 } diff --git a/apps/ui/src/routes/applications/[id]/configuration/destination.svelte b/apps/ui/src/routes/applications/[id]/configuration/destination.svelte index 2bfe98a5c..5265ec452 100644 --- a/apps/ui/src/routes/applications/[id]/configuration/destination.svelte +++ b/apps/ui/src/routes/applications/[id]/configuration/destination.svelte @@ -31,6 +31,7 @@ import { t } from '$lib/translations'; import { appSession } from '$lib/store'; import { errorNotification } from '$lib/common'; + import { onMount } from 'svelte/types/runtime/internal/lifecycle'; const { id } = $page.params; const from = $page.url.searchParams.get('from'); @@ -55,6 +56,11 @@ return errorNotification(error); } } + onMount(async () => { + if (destinations.length === 1) { + await handleSubmit(destinations[0].id); + } + });
@@ -65,7 +71,9 @@
{#if !destinations || ownDestinations.length === 0}
-
{$t('application.configuration.no_configurable_destination')}
+
+ {$t('application.configuration.no_configurable_destination')} +
{ + if (destinations.length === 1) { + await handleSubmit(destinations[0].id); + } + });
@@ -55,7 +61,9 @@
{#if !destinations || destinations.length === 0}
-
{$t('application.configuration.no_configurable_destination')}
+
+ {$t('application.configuration.no_configurable_destination')} +
{ + if (destinations.length === 1) { + await handleSubmit(destinations[0].id); + } + }); async function handleSubmit(destinationId: any) { try { await post(`/services/${id}/configuration/destination`, { destinationId }); @@ -54,7 +60,9 @@
{#if !destinations || destinations.length === 0}
-
{$t('application.configuration.no_configurable_destination')}
+
+ {$t('application.configuration.no_configurable_destination')} +
name === type )?.recommendedVersion; + + onMount(async () => { + if (versions.length === 1) { + await handleSubmit(versions[0]); + } + }); + async function handleSubmit(version: any) { try { await post(`/services/${id}/configuration/version`, { version }); From 186c5897a0a4ed18c2cb0f0bcfe49e2a23b9324b Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Tue, 16 Aug 2022 09:40:07 +0000 Subject: [PATCH 04/14] fix: autoimport + readme --- README.md | 2 +- .../routes/applications/[id]/configuration/destination.svelte | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 40d7ac2dc..a8d066030 100644 --- a/README.md +++ b/README.md @@ -115,6 +115,7 @@ If you have a new database you would like to add, raise an idea [here](https://f ### Services You quickly need to host a self-hostable, open-source service? You can do it with a few clicks! +- [Appwrite](https://appwrite.io) - [WordPress](https://docs.coollabs.io/coolify/services/wordpress) - [Ghost](https://ghost.org) - [Plausible Analytics](https://docs.coollabs.io/coolify/services/plausible-analytics) @@ -130,7 +131,6 @@ You quickly need to host a self-hostable, open-source service? You can do it wit - [Fider](https://fider.io) - [Hasura](https://hasura.io) - If you have a new service you would like to add, raise an idea [here](https://feedback.coolify.io/) to get feedback from the community! ## Migration from v1 diff --git a/apps/ui/src/routes/applications/[id]/configuration/destination.svelte b/apps/ui/src/routes/applications/[id]/configuration/destination.svelte index 5265ec452..2f0efe2d3 100644 --- a/apps/ui/src/routes/applications/[id]/configuration/destination.svelte +++ b/apps/ui/src/routes/applications/[id]/configuration/destination.svelte @@ -31,7 +31,7 @@ import { t } from '$lib/translations'; import { appSession } from '$lib/store'; import { errorNotification } from '$lib/common'; - import { onMount } from 'svelte/types/runtime/internal/lifecycle'; + import { onMount } from 'svelte'; const { id } = $page.params; const from = $page.url.searchParams.get('from'); From 2590efba4bf83f4ef5decb3fcd584c2b0d1a9897 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Tue, 16 Aug 2022 09:52:47 +0000 Subject: [PATCH 05/14] fix: services import --- apps/ui/src/routes/services/index.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/ui/src/routes/services/index.svelte b/apps/ui/src/routes/services/index.svelte index cb9f4ad55..44b8e6381 100644 --- a/apps/ui/src/routes/services/index.svelte +++ b/apps/ui/src/routes/services/index.svelte @@ -102,7 +102,7 @@ {#each otherServices as service}
- +
{service.name}
From bb01cfb330b3d5954b3c7f5f1c6255d557fefd44 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Tue, 16 Aug 2022 11:08:23 +0000 Subject: [PATCH 06/14] remove console.log --- apps/api/src/lib/docker.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/api/src/lib/docker.ts b/apps/api/src/lib/docker.ts index 3244c2475..aa6a29cfd 100644 --- a/apps/api/src/lib/docker.ts +++ b/apps/api/src/lib/docker.ts @@ -16,7 +16,6 @@ export function formatLabelsOnDocker(data) { export async function checkContainer({ dockerId, container, remove = false }: { dockerId: string, container: string, remove?: boolean }): Promise { let containerFound = false; try { - console.log('checking ', container) const { stdout } = await executeDockerCmd({ dockerId, command: From a7fe446550d1efdec93eb1723f5e75e4ebe964fa Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Tue, 16 Aug 2022 13:58:37 +0200 Subject: [PATCH 07/14] feat: Heroku deployments --- apps/api/src/jobs/deployApplication.ts | 8 ++ apps/api/src/lib/buildPacks/common.ts | 19 +++++ apps/ui/src/lib/common.ts | 2 +- apps/ui/src/lib/components/Toast.svelte | 7 +- apps/ui/src/lib/components/Toasts.svelte | 5 +- .../svg/applications/ApplicationIcons.svelte | 2 + .../components/svg/applications/Heroku.svelte | 23 ++++++ .../lib/components/svg/applications/index.ts | 2 +- apps/ui/src/lib/templates.ts | 77 +++++++++++++------ .../[id]/configuration/buildpack.svelte | 21 ++++- .../src/routes/applications/[id]/index.svelte | 63 +++++++-------- apps/ui/src/tailwind.css | 2 +- 12 files changed, 166 insertions(+), 65 deletions(-) create mode 100644 apps/ui/src/lib/components/svg/applications/Heroku.svelte diff --git a/apps/api/src/jobs/deployApplication.ts b/apps/api/src/jobs/deployApplication.ts index 9782067d1..ff87ebe7c 100644 --- a/apps/api/src/jobs/deployApplication.ts +++ b/apps/api/src/jobs/deployApplication.ts @@ -152,6 +152,13 @@ import * as buildpacks from '../lib/buildPacks'; .createHash('sha256') .update( JSON.stringify({ + pythonWSGI, + pythonModule, + pythonVariable, + deploymentType, + denoOptions, + baseImage, + baseBuildImage, buildPack, port, exposePort, @@ -291,6 +298,7 @@ import * as buildpacks from '../lib/buildPacks'; } }; }); + console.log({port}) const composeFile = { version: '3.8', services: { diff --git a/apps/api/src/lib/buildPacks/common.ts b/apps/api/src/lib/buildPacks/common.ts index 62aa271c1..6684664d6 100644 --- a/apps/api/src/lib/buildPacks/common.ts +++ b/apps/api/src/lib/buildPacks/common.ts @@ -252,6 +252,20 @@ export function setDefaultBaseImage(buildPack: string | null, deploymentType: st label: 'python:3.7-slim-bullseye' } ]; + const herokuVersions = [ + { + value: 'heroku/builder:22', + label: 'heroku/builder:22' + }, + { + value: 'heroku/buildpacks:20', + label: 'heroku/buildpacks:20' + }, + { + value: 'heroku/builder-classic:22', + label: 'heroku/builder-classic:22' + }, + ] let payload: any = { baseImage: null, baseBuildImage: null, @@ -299,6 +313,11 @@ export function setDefaultBaseImage(buildPack: string | null, deploymentType: st payload.baseBuildImage = 'node:18'; payload.baseBuildImages = nodeVersions; } + if (buildPack === 'heroku') { + payload.baseImage = 'heroku/buildpacks:20'; + payload.baseImages = herokuVersions; + + } return payload; } diff --git a/apps/ui/src/lib/common.ts b/apps/ui/src/lib/common.ts index 08b863d57..3834422e5 100644 --- a/apps/ui/src/lib/common.ts +++ b/apps/ui/src/lib/common.ts @@ -229,7 +229,7 @@ export const staticDeployments = [ 'astro', 'eleventy' ]; -export const notNodeDeployments = ['php', 'docker', 'rust', 'python', 'deno', 'laravel']; +export const notNodeDeployments = ['php', 'docker', 'rust', 'python', 'deno', 'laravel', 'heroku']; export function generateRemoteEngine(destination: any) { diff --git a/apps/ui/src/lib/components/Toast.svelte b/apps/ui/src/lib/components/Toast.svelte index 282bc159f..b0586a51f 100644 --- a/apps/ui/src/lib/components/Toast.svelte +++ b/apps/ui/src/lib/components/Toast.svelte @@ -5,16 +5,17 @@
dispatch('click')} on:mouseover={() => dispatch('pause')} on:focus={() => dispatch('pause')} on:mouseout={() => dispatch('resume')} on:blur={() => dispatch('resume')} - class="alert shadow-lg text-white rounded" + class="alert shadow-lg text-white rounded hover:scale-105 transition-all duration-100 cursor-pointer" class:bg-coollabs={type === 'success'} class:alert-error={type === 'error'} class:alert-info={type === 'info'} > - + {/if}
diff --git a/apps/ui/src/lib/components/Toasts.svelte b/apps/ui/src/lib/components/Toasts.svelte index 2e53c6287..1c7c8cbc0 100644 --- a/apps/ui/src/lib/components/Toasts.svelte +++ b/apps/ui/src/lib/components/Toasts.svelte @@ -2,7 +2,7 @@ import { fade } from 'svelte/transition'; import Toast from './Toast.svelte'; - import { pauseToast, resumeToast, toasts } from '$lib/store'; + import { dismissToast, pauseToast, resumeToast, toasts } from '$lib/store'; {#if $toasts} @@ -12,7 +12,8 @@ resumeToast(toast.id)} - on:pause={() => pauseToast(toast.id)}>{@html toast.message} pauseToast(toast.id)} + on:click={() => dismissToast(toast.id)}>{@html toast.message} {/each} diff --git a/apps/ui/src/lib/components/svg/applications/ApplicationIcons.svelte b/apps/ui/src/lib/components/svg/applications/ApplicationIcons.svelte index 379b775ce..0980063c6 100644 --- a/apps/ui/src/lib/components/svg/applications/ApplicationIcons.svelte +++ b/apps/ui/src/lib/components/svg/applications/ApplicationIcons.svelte @@ -38,4 +38,6 @@ {:else if application.buildPack?.toLowerCase() === 'laravel'} +{:else if application.buildPack?.toLowerCase() === 'heroku'} + {/if} diff --git a/apps/ui/src/lib/components/svg/applications/Heroku.svelte b/apps/ui/src/lib/components/svg/applications/Heroku.svelte new file mode 100644 index 000000000..25a221ee2 --- /dev/null +++ b/apps/ui/src/lib/components/svg/applications/Heroku.svelte @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/apps/ui/src/lib/components/svg/applications/index.ts b/apps/ui/src/lib/components/svg/applications/index.ts index 12b712f4c..ee2236357 100644 --- a/apps/ui/src/lib/components/svg/applications/index.ts +++ b/apps/ui/src/lib/components/svg/applications/index.ts @@ -16,4 +16,4 @@ export { default as Astro } from './Astro.svelte'; export { default as Eleventy } from './Eleventy.svelte'; export { default as Deno } from './Deno.svelte'; export { default as Laravel } from './Laravel.svelte'; - +export { default as Heroku } from './Heroku.svelte'; diff --git a/apps/ui/src/lib/templates.ts b/apps/ui/src/lib/templates.ts index ecd669e8e..c4ec05ad6 100644 --- a/apps/ui/src/lib/templates.ts +++ b/apps/ui/src/lib/templates.ts @@ -170,6 +170,16 @@ export function findBuildPack(pack: string, packageManager = 'npm') { port: 80 }; } + if (pack === 'heroku') { + return { + ...metaData, + installCommand: null, + buildCommand: null, + startCommand: null, + publishDirectory: null, + port: 5000 + }; + } return { name: 'node', fancyName: 'Node.js', @@ -187,118 +197,137 @@ export const buildPacks = [ name: 'node', fancyName: 'Node.js', hoverColor: 'hover:bg-green-700', - color: 'bg-green-700' + color: 'bg-green-700', + isCoolifyBuildPack: true, }, { name: 'static', fancyName: 'Static', hoverColor: 'hover:bg-orange-700', - color: 'bg-orange-700' + color: 'bg-orange-700', + isCoolifyBuildPack: true, }, { name: 'php', fancyName: 'PHP', hoverColor: 'hover:bg-indigo-700', - color: 'bg-indigo-700' + color: 'bg-indigo-700', + isCoolifyBuildPack: true, }, { name: 'laravel', fancyName: 'Laravel', hoverColor: 'hover:bg-indigo-700', - color: 'bg-indigo-700' + color: 'bg-indigo-700', + isCoolifyBuildPack: true, }, { name: 'docker', fancyName: 'Docker', hoverColor: 'hover:bg-sky-700', - color: 'bg-sky-700' + color: 'bg-sky-700', + isCoolifyBuildPack: true, }, { name: 'svelte', fancyName: 'Svelte', hoverColor: 'hover:bg-orange-700', - color: 'bg-orange-700' + color: 'bg-orange-700', + isCoolifyBuildPack: true, }, { name: 'vuejs', fancyName: 'VueJS', hoverColor: 'hover:bg-green-700', - color: 'bg-green-700' + color: 'bg-green-700', + isCoolifyBuildPack: true, }, { name: 'nuxtjs', fancyName: 'NuxtJS', hoverColor: 'hover:bg-green-700', - color: 'bg-green-700' + color: 'bg-green-700', + isCoolifyBuildPack: true, }, { name: 'gatsby', fancyName: 'Gatsby', hoverColor: 'hover:bg-blue-700', - color: 'bg-blue-700' + color: 'bg-blue-700', + isCoolifyBuildPack: true, }, { name: 'astro', fancyName: 'Astro', hoverColor: 'hover:bg-pink-700', - color: 'bg-pink-700' + color: 'bg-pink-700', + isCoolifyBuildPack: true, }, { name: 'eleventy', fancyName: 'Eleventy', hoverColor: 'hover:bg-red-700', - color: 'bg-red-700' + color: 'bg-red-700', + isCoolifyBuildPack: true, }, { name: 'react', fancyName: 'React', hoverColor: 'hover:bg-blue-700', - color: 'bg-blue-700' + color: 'bg-blue-700', + isCoolifyBuildPack: true, }, { name: 'preact', fancyName: 'Preact', hoverColor: 'hover:bg-blue-700', - color: 'bg-blue-700' + color: 'bg-blue-700', + isCoolifyBuildPack: true, }, { name: 'nextjs', fancyName: 'NextJS', hoverColor: 'hover:bg-blue-700', - color: 'bg-blue-700' + color: 'bg-blue-700', + isCoolifyBuildPack: true, }, { name: 'nestjs', fancyName: 'NestJS', hoverColor: 'hover:bg-red-700', - color: 'bg-red-700' + color: 'bg-red-700', + isCoolifyBuildPack: true, }, { name: 'rust', fancyName: 'Rust', hoverColor: 'hover:bg-pink-700', - color: 'bg-pink-700' + color: 'bg-pink-700', + isCoolifyBuildPack: true, }, { name: 'python', fancyName: 'Python', hoverColor: 'hover:bg-green-700', - color: 'bg-green-700' + color: 'bg-green-700', + isCoolifyBuildPack: true, }, { name: 'deno', fancyName: 'Deno', hoverColor: 'hover:bg-green-700', - color: 'bg-green-700' + color: 'bg-green-700', + isCoolifyBuildPack: true, }, - // { - // name: 'heroku', - // fancyName: 'Heroku Buildpack', - // hoverColor: 'hover:bg-indigo-700', - // color: 'bg-indigo-700' - // } + { + name: 'heroku', + fancyName: 'Heroku', + hoverColor: 'hover:bg-purple-700', + color: 'bg-purple-700', + isHerokuBuildPack: true, + } ]; export const scanningTemplates = { '@sveltejs/kit': { diff --git a/apps/ui/src/routes/applications/[id]/configuration/buildpack.svelte b/apps/ui/src/routes/applications/[id]/configuration/buildpack.svelte index 7330bbbd0..e187d95bd 100644 --- a/apps/ui/src/routes/applications/[id]/configuration/buildpack.svelte +++ b/apps/ui/src/routes/applications/[id]/configuration/buildpack.svelte @@ -30,7 +30,6 @@ import { page } from '$app/stores'; import { get } from '$lib/api'; import { appSession } from '$lib/store'; - import { browser } from '$app/env'; import { t } from '$lib/translations'; import { buildPacks, findBuildPack, scanningTemplates } from '$lib/templates'; import { errorNotification } from '$lib/common'; @@ -263,11 +262,27 @@
{:else} -
- + {#if isDisabled} + + {:else} + + {/if}
+ {#if isDisabled} + + {:else} + {/if}
{/if} - {#if application.buildPack !== 'laravel'} + {#if application.buildPack !== 'laravel' && application.buildPack !== 'heroku'}