mirror of
https://github.com/tiennm99/coolify.git
synced 2026-10-12 12:13:41 +00:00
fixes
This commit is contained in:
1 parent
aa27aeafa1
commit
dc626bd4f0
20 files changed
+422
-97
No files matched your search
+110
-11
@@ -1,5 +1,6 @@
|
||||
- templateVersion: 1.0.0
|
||||
defaultVersion: 1.0.3
|
||||
type: appwrite
|
||||
name: Appwrite
|
||||
documentation: https://appwrite.io/docs
|
||||
description: Secure Backend Server for Web, Mobile & Flutter Developers.
|
||||
@@ -1035,6 +1036,7 @@
|
||||
The default value is 15 minutes.
|
||||
- templateVersion: 1.0.0
|
||||
defaultVersion: latest
|
||||
type: weblate
|
||||
name: Weblate
|
||||
description: ''
|
||||
services:
|
||||
@@ -1087,7 +1089,7 @@
|
||||
label: Weblate Admin Password
|
||||
defaultValue: $$generate_password
|
||||
description: ''
|
||||
showOnUI: true
|
||||
showOnConfiguration: true
|
||||
- id: $$config_postgres_user
|
||||
main: $$id-postgresql
|
||||
name: POSTGRES_USER
|
||||
@@ -1100,7 +1102,7 @@
|
||||
label: PostgreSQL Password
|
||||
defaultValue: $$generate_password
|
||||
description: ''
|
||||
showOnUI: true
|
||||
showOnConfiguration: true
|
||||
- id: $$config_postgres_db
|
||||
main: $$id-postgresql
|
||||
name: POSTGRES_DB
|
||||
@@ -1109,6 +1111,7 @@
|
||||
description: ''
|
||||
- templateVersion: 1.0.0
|
||||
defaultVersion: 2022.10.14-1a5b0965
|
||||
type: searxng
|
||||
name: SearXNG
|
||||
description: ''
|
||||
services:
|
||||
@@ -1181,6 +1184,7 @@
|
||||
description: ''
|
||||
- templateVersion: 1.0.0
|
||||
defaultVersion: v2.0.6
|
||||
type: glitchtip
|
||||
name: GlitchTip
|
||||
description: ''
|
||||
services:
|
||||
@@ -1344,6 +1348,7 @@
|
||||
description: ''
|
||||
- templateVersion: 1.0.0
|
||||
defaultVersion: v2.13.0
|
||||
type: hasura
|
||||
name: Hasura
|
||||
description: 'Instant realtime GraphQL APIs on any Postgres application, existing or new.'
|
||||
services:
|
||||
@@ -1388,7 +1393,7 @@
|
||||
label: Hasura Admin Password
|
||||
defaultValue: $$generate_password
|
||||
description: ''
|
||||
showOnUI: true
|
||||
showOnConfiguration: true
|
||||
- id: $$config_postgres_user
|
||||
name: POSTGRES_USER
|
||||
label: PostgreSQL User
|
||||
@@ -1406,6 +1411,7 @@
|
||||
description: ''
|
||||
- templateVersion: 1.0.0
|
||||
defaultVersion: postgresql-v1.38.0
|
||||
type: umami
|
||||
name: Umami
|
||||
description: >-
|
||||
Umami is a simple, easy to use, self-hosted web analytics solution. The goal
|
||||
@@ -1606,9 +1612,10 @@
|
||||
label: Initial Admin Password
|
||||
defaultValue: $$generate_password
|
||||
description: ''
|
||||
showOnUI: true
|
||||
showOnConfiguration: true
|
||||
- templateVersion: 1.0.0
|
||||
defaultVersion: v0.29.1
|
||||
type: meilisearch
|
||||
name: MeiliSearch
|
||||
description: >-
|
||||
MeiliSearch is a lightning Fast, Ultra Relevant, and Typo-Tolerant Search
|
||||
@@ -1634,9 +1641,10 @@
|
||||
label: Master Key
|
||||
defaultValue: $$generate_hex(64)
|
||||
description: ''
|
||||
showOnUI: true
|
||||
showOnConfiguration: true
|
||||
- templateVersion: 1.0.0
|
||||
defaultVersion: latest
|
||||
type: ghost
|
||||
name: Ghost
|
||||
description: >-
|
||||
Ghost is a free and open source blogging platform written in JavaScript and
|
||||
@@ -1749,8 +1757,9 @@
|
||||
description: ''
|
||||
- templateVersion: 1.0.0
|
||||
defaultVersion: php8.1
|
||||
name: WordPress
|
||||
description: WordPress is a content management system based on PHP.
|
||||
type: wordpress
|
||||
name: WordPress (with MySQL)
|
||||
description: WordPress is a content management system based on PHP with new MySQL database.
|
||||
services:
|
||||
$$id:
|
||||
name: WordPress
|
||||
@@ -1789,53 +1798,138 @@
|
||||
label: WordPress DB Host
|
||||
defaultValue: $$id-mysql
|
||||
description: ''
|
||||
readonly: true
|
||||
- id: $$config_wordpress_db_user
|
||||
name: WORDPRESS_DB_USER
|
||||
label: WordPress DB User
|
||||
defaultValue: $$config_mysql_user
|
||||
description: ''
|
||||
readonly: true
|
||||
- id: $$secret_wordpress_db_password
|
||||
name: WORDPRESS_DB_PASSWORD
|
||||
label: WordPress DB Password
|
||||
defaultValue: $$secret_mysql_password
|
||||
description: ''
|
||||
readonly: true
|
||||
- id: $$config_wordpress_db_name
|
||||
name: WORDPRESS_DB_NAME
|
||||
label: WordPress DB Name
|
||||
defaultValue: $$config_mysql_database
|
||||
description: ''
|
||||
readonly: true
|
||||
- id: $$config_wordpress_config_extra
|
||||
name: WORDPRESS_CONFIG_EXTRA
|
||||
label: WordPress Config Extra
|
||||
defaultValue: ''
|
||||
description: ''
|
||||
type: 'textarea'
|
||||
placeholder: |
|
||||
define('WP_DEBUG', true);
|
||||
define('WP_DEBUG_LOG', true);
|
||||
define('WP_DEBUG_DISPLAY', false);
|
||||
@ini_set('display_errors', 0);
|
||||
- id: $$secret_mysql_root_password
|
||||
name: MYSQL_ROOT_PASSWORD
|
||||
label: MySQL Root Password
|
||||
defaultValue: $$generate_password
|
||||
description: ''
|
||||
readonly: true
|
||||
- id: $$config_mysql_root_user
|
||||
name: MYSQL_ROOT_USER
|
||||
label: MySQL Root User
|
||||
defaultValue: $$generate_username
|
||||
description: ''
|
||||
readonly: true
|
||||
- id: $$config_mysql_database
|
||||
name: MYSQL_DATABASE
|
||||
label: MySQL Database
|
||||
defaultValue: wordpress
|
||||
description: ''
|
||||
readonly: true
|
||||
- id: $$config_mysql_user
|
||||
name: MYSQL_USER
|
||||
label: MySQL User
|
||||
defaultValue: $$generate_username
|
||||
description: ''
|
||||
readonly: true
|
||||
- id: $$secret_mysql_password
|
||||
name: MYSQL_PASSWORD
|
||||
label: MySQL Password
|
||||
defaultValue: $$generate_password
|
||||
description: ''
|
||||
readonly: true
|
||||
- templateVersion: 1.0.0
|
||||
defaultVersion: php8.1
|
||||
type: wordpress-only
|
||||
name: WordPress (without MySQL)
|
||||
description: WordPress is a content management system based on PHP without MySQL.
|
||||
services:
|
||||
$$id:
|
||||
name: WordPress
|
||||
documentation: 'Taken from https://docs.docker.com/compose/wordpress/'
|
||||
image: 'wordpress:$$core_version'
|
||||
volumes:
|
||||
- '$$id-wordpress-data:/var/www/html'
|
||||
environment:
|
||||
- WORDPRESS_DB_HOST=$$config_wordpress_db_host
|
||||
- WORDPRESS_DB_PORT=$$config_wordpress_db_port
|
||||
- WORDPRESS_DB_USER=$$config_wordpress_db_user
|
||||
- WORDPRESS_DB_PASSWORD=$$secret_wordpress_db_password
|
||||
- WORDPRESS_DB_NAME=$$config_wordpress_db_name
|
||||
- WORDPRESS_CONFIG_EXTRA=$$config_wordpress_config_extra
|
||||
ports:
|
||||
- '80'
|
||||
variables:
|
||||
- id: $$config_wordpress_db_host
|
||||
name: WORDPRESS_DB_HOST
|
||||
label: Database Host
|
||||
defaultValue: ''
|
||||
description: ''
|
||||
placeholder: 'db.coollabs.io'
|
||||
required: true
|
||||
- id: $$config_wordpress_db_port
|
||||
name: WORDPRESS_DB_PORT
|
||||
label: Database Port
|
||||
defaultValue: ''
|
||||
description: ''
|
||||
placeholder: '3306'
|
||||
required: true
|
||||
- id: $$config_wordpress_db_user
|
||||
name: WORDPRESS_DB_USER
|
||||
label: Database User
|
||||
defaultValue: ''
|
||||
description: ''
|
||||
placeholder: 'wordpress'
|
||||
required: true
|
||||
- id: $$secret_wordpress_db_password
|
||||
name: WORDPRESS_DB_PASSWORD
|
||||
label: Database Password
|
||||
defaultValue: ''
|
||||
description: ''
|
||||
placeholder: 'supers3cr3tpassw0rd!'
|
||||
required: true
|
||||
showOnConfiguration: true
|
||||
- id: $$config_wordpress_db_name
|
||||
name: WORDPRESS_DB_NAME
|
||||
label: Database Name
|
||||
defaultValue: ''
|
||||
description: ''
|
||||
placeholder: 'wordpress'
|
||||
required: true
|
||||
- id: $$config_wordpress_config_extra
|
||||
name: WORDPRESS_CONFIG_EXTRA
|
||||
label: Extra Config
|
||||
defaultValue: ''
|
||||
description: ''
|
||||
type: 'textarea'
|
||||
placeholder: |
|
||||
define('WP_DEBUG', true);
|
||||
define('WP_DEBUG_LOG', true);
|
||||
define('WP_DEBUG_DISPLAY', false);
|
||||
@ini_set('display_errors', 0);
|
||||
- templateVersion: 1.0.0
|
||||
defaultVersion: 4.7.1
|
||||
type: vscodeserver
|
||||
name: VSCode Server
|
||||
description: >-
|
||||
vscode-server by Coder is VS Code running on a remote server, accessible
|
||||
@@ -1861,9 +1955,10 @@
|
||||
label: Password
|
||||
defaultValue: $$generate_password
|
||||
description: ''
|
||||
showOnUI: true
|
||||
showOnConfiguration: true
|
||||
- templateVersion: 1.0.0
|
||||
defaultVersion: RELEASE.2022-10-15T19-57-03Z
|
||||
type: minio
|
||||
name: MinIO
|
||||
description: ' MinIO is a cloud storage server compatible with Amazon S3'
|
||||
services:
|
||||
@@ -1915,9 +2010,10 @@
|
||||
label: Root User Password
|
||||
defaultValue: $$generate_password
|
||||
description: ''
|
||||
showOnUI: true
|
||||
showOnConfiguration: true
|
||||
- templateVersion: 1.0.0
|
||||
defaultVersion: 0.21.1
|
||||
type: fider
|
||||
name: Fider
|
||||
description: Fider is a platform to collect and organize customer feedback.
|
||||
services:
|
||||
@@ -2032,6 +2128,7 @@
|
||||
description: ''
|
||||
- templateVersion: 1.0.0
|
||||
defaultVersion: 0.198.1
|
||||
type: n8nio
|
||||
name: n8n.io
|
||||
description: n8n is a free and open node based Workflow Automation Tool.
|
||||
services:
|
||||
@@ -2056,6 +2153,7 @@
|
||||
description: ''
|
||||
- templateVersion: 1.0.0
|
||||
defaultVersion: stable
|
||||
type: plausibleanalytics
|
||||
name: Plausible Analytics
|
||||
description: Plausible is a lightweight and open-source website analytics tool.
|
||||
services:
|
||||
@@ -2157,7 +2255,7 @@
|
||||
label: Admin User Password
|
||||
defaultValue: $$generate_password
|
||||
description: This is the admin password. Please change it.
|
||||
showOnUI: true
|
||||
showOnConfiguration: true
|
||||
- id: $$secret_secret_key_base
|
||||
name: SECRET_KEY_BASE
|
||||
label: Secret Key Base
|
||||
@@ -2185,7 +2283,7 @@
|
||||
label: PostgreSQL Password
|
||||
defaultValue: $$generate_password
|
||||
description: ''
|
||||
showOnUI: true
|
||||
showOnConfiguration: true
|
||||
- id: $$config_postgresql_database
|
||||
main: $$id-postgresql
|
||||
name: POSTGRESQL_DATABASE
|
||||
@@ -2199,6 +2297,7 @@
|
||||
description: This is the default script name.
|
||||
- templateVersion: 1.0.0
|
||||
defaultVersion: 0.98.1
|
||||
type: nocodb
|
||||
name: NocoDB
|
||||
description: >-
|
||||
The Open Source Airtable Alternative - Turns any MySQL, PostgreSQL, SQL
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
-- RedefineTables
|
||||
PRAGMA foreign_keys=OFF;
|
||||
CREATE TABLE "new_Wordpress" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"extraConfig" TEXT,
|
||||
"tablePrefix" TEXT,
|
||||
"ownMysql" BOOLEAN NOT NULL DEFAULT false,
|
||||
"mysqlHost" TEXT,
|
||||
"mysqlPort" INTEGER,
|
||||
"mysqlUser" TEXT,
|
||||
"mysqlPassword" TEXT,
|
||||
"mysqlRootUser" TEXT,
|
||||
"mysqlRootUserPassword" TEXT,
|
||||
"mysqlDatabase" TEXT,
|
||||
"mysqlPublicPort" INTEGER,
|
||||
"ftpEnabled" BOOLEAN NOT NULL DEFAULT false,
|
||||
"ftpUser" TEXT,
|
||||
"ftpPassword" TEXT,
|
||||
"ftpPublicPort" INTEGER,
|
||||
"ftpHostKey" TEXT,
|
||||
"ftpHostKeyPrivate" TEXT,
|
||||
"serviceId" TEXT NOT NULL,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" DATETIME NOT NULL,
|
||||
CONSTRAINT "Wordpress_serviceId_fkey" FOREIGN KEY ("serviceId") REFERENCES "Service" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
);
|
||||
INSERT INTO "new_Wordpress" ("createdAt", "extraConfig", "ftpEnabled", "ftpHostKey", "ftpHostKeyPrivate", "ftpPassword", "ftpPublicPort", "ftpUser", "id", "mysqlDatabase", "mysqlHost", "mysqlPassword", "mysqlPort", "mysqlPublicPort", "mysqlRootUser", "mysqlRootUserPassword", "mysqlUser", "ownMysql", "serviceId", "tablePrefix", "updatedAt") SELECT "createdAt", "extraConfig", "ftpEnabled", "ftpHostKey", "ftpHostKeyPrivate", "ftpPassword", "ftpPublicPort", "ftpUser", "id", "mysqlDatabase", "mysqlHost", "mysqlPassword", "mysqlPort", "mysqlPublicPort", "mysqlRootUser", "mysqlRootUserPassword", "mysqlUser", "ownMysql", "serviceId", "tablePrefix", "updatedAt" FROM "Wordpress";
|
||||
DROP TABLE "Wordpress";
|
||||
ALTER TABLE "new_Wordpress" RENAME TO "Wordpress";
|
||||
CREATE UNIQUE INDEX "Wordpress_serviceId_key" ON "Wordpress"("serviceId");
|
||||
PRAGMA foreign_key_check;
|
||||
PRAGMA foreign_keys=ON;
|
||||
@@ -480,10 +480,10 @@ model Wordpress {
|
||||
ownMysql Boolean @default(false)
|
||||
mysqlHost String?
|
||||
mysqlPort Int?
|
||||
mysqlUser String
|
||||
mysqlPassword String
|
||||
mysqlRootUser String
|
||||
mysqlRootUserPassword String
|
||||
mysqlUser String?
|
||||
mysqlPassword String?
|
||||
mysqlRootUser String?
|
||||
mysqlRootUserPassword String?
|
||||
mysqlDatabase String?
|
||||
mysqlPublicPort Int?
|
||||
ftpEnabled Boolean @default(false)
|
||||
|
||||
@@ -8,6 +8,7 @@ const template = yaml.load(templateYml)
|
||||
const newTemplate = {
|
||||
"templateVersion": "1.0.0",
|
||||
"defaultVersion": "latest",
|
||||
"type": "",
|
||||
"name": "",
|
||||
"description": "",
|
||||
"services": {
|
||||
@@ -18,6 +19,7 @@ const newTemplate = {
|
||||
const version = template.caproverOneClickApp.variables.find(v => v.id === '$$cap_APP_VERSION' || v.id === '$$cap_version').defaultValue || 'latest'
|
||||
|
||||
newTemplate.name = template.caproverOneClickApp.displayName
|
||||
newTemplate.type = template.caproverOneClickApp.displayName.replaceAll(' ', '').toLowerCase()
|
||||
newTemplate.documentation = template.caproverOneClickApp.documentation
|
||||
newTemplate.description = template.caproverOneClickApp.description
|
||||
newTemplate.defaultVersion = version
|
||||
|
||||
@@ -7,19 +7,32 @@ const templates = await fs.readFile('../devTemplates.yaml', 'utf8');
|
||||
const devTemplates = yaml.load(templates);
|
||||
for (const template of devTemplates) {
|
||||
let image = template.services['$$id'].image.replaceAll(':$$core_version', '');
|
||||
const name = template.name
|
||||
if (!image.includes('/')) {
|
||||
image = `library/${image}`;
|
||||
}
|
||||
repositories.push({ image, name: name.toLowerCase().replaceAll(' ', '') });
|
||||
repositories.push({ image, name: template.type });
|
||||
}
|
||||
const services = []
|
||||
|
||||
const numberOfTags = 30;
|
||||
// const semverRegex = new RegExp(/^v?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/g)
|
||||
const semverRegex = new RegExp(/^v?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/g)
|
||||
for (const repository of repositories) {
|
||||
console.log('Querying', repository.name, 'at', repository.image);
|
||||
let semverRegex = new RegExp(/^v?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/g)
|
||||
if (repository.name.startsWith('wordpress')) {
|
||||
semverRegex = new RegExp(/^v?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)-php(0|[1-9]\d*)$/g)
|
||||
}
|
||||
if (repository.name.startsWith('minio')) {
|
||||
semverRegex = new RegExp(/^RELEASE.*$/g)
|
||||
}
|
||||
if (repository.name.startsWith('fider')) {
|
||||
semverRegex = new RegExp(/^v?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)-([0-9]+)$/g)
|
||||
}
|
||||
if (repository.name.startsWith('searxng')) {
|
||||
semverRegex = new RegExp(/^\d{4}[\.\-](0?[1-9]|[12][0-9]|3[01])[\.\-](0?[1-9]|1[012]).*$/)
|
||||
}
|
||||
if (repository.name.startsWith('umami')) {
|
||||
semverRegex = new RegExp(/^postgresql-v?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)-([0-9]+)$/g)
|
||||
}
|
||||
if (repository.image.includes('ghcr.io')) {
|
||||
const { execaCommand } = await import('execa');
|
||||
const { stdout } = await execaCommand(`docker run --rm quay.io/skopeo/stable list-tags docker://${repository.image}`);
|
||||
|
||||
+3
-1
@@ -317,7 +317,9 @@ async function wordpress(service: any, template: any) {
|
||||
]
|
||||
await migrateSettings(settings, service, template);
|
||||
await migrateSecrets(secrets, service);
|
||||
|
||||
if (ownMysql) {
|
||||
await prisma.service.update({ where: { id: service.id }, data: { type: "wordpress-only" } })
|
||||
}
|
||||
// Remove old service data
|
||||
// await prisma.service.update({ where: { id: service.id }, data: { wordpress: { delete: true } } })
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ export function getAPIUrl() {
|
||||
if (process.env.CODESANDBOX_HOST) {
|
||||
return `https://${process.env.CODESANDBOX_HOST.replace(/\$PORT/, '3001')}`;
|
||||
}
|
||||
return isDev ? 'http://localhost:3001' : 'http://localhost:3000';
|
||||
return isDev ? 'http://host.docker.internal:3001' : 'http://localhost:3000';
|
||||
}
|
||||
|
||||
export function getUIUrl() {
|
||||
@@ -1447,12 +1447,13 @@ export async function getServiceFromDB({
|
||||
persistentStorage: true,
|
||||
serviceSecret: true,
|
||||
serviceSetting: true,
|
||||
wordpress: true
|
||||
}
|
||||
});
|
||||
if (!body) {
|
||||
return null
|
||||
}
|
||||
body.type = fixType(body.type);
|
||||
// body.type = fixType(body.type);
|
||||
|
||||
if (body?.serviceSecret.length > 0) {
|
||||
body.serviceSecret = body.serviceSecret.map((s) => {
|
||||
@@ -1460,6 +1461,9 @@ export async function getServiceFromDB({
|
||||
return s;
|
||||
});
|
||||
}
|
||||
if (body.wordpress) {
|
||||
body.wordpress.ftpPassword = decrypt(body.wordpress.ftpPassword);
|
||||
}
|
||||
|
||||
return { ...body, settings };
|
||||
}
|
||||
|
||||
@@ -42,11 +42,16 @@ export async function startService(request: FastifyRequest<ServiceStartStop>) {
|
||||
const template: any = await parseAndFindServiceTemplates(service, workdir, true)
|
||||
const network = destinationDockerId && destinationDocker.network;
|
||||
const config = {};
|
||||
for (const service in template.services) {
|
||||
const isWordpress = type === 'wordpress';
|
||||
for (const s in template.services) {
|
||||
if (isWordpress && service.wordpress.ownMysql && s.name === 'MySQL') {
|
||||
console.log('skipping predefined mysql')
|
||||
continue;
|
||||
}
|
||||
let newEnvironments = []
|
||||
if (arm) {
|
||||
if (template.services[service]?.environmentArm?.length > 0) {
|
||||
for (const environment of template.services[service].environmentArm) {
|
||||
if (template.services[s]?.environmentArm?.length > 0) {
|
||||
for (const environment of template.services[s].environmentArm) {
|
||||
const [env, value] = environment.split("=");
|
||||
if (!value.startsWith('$$secret') && value !== '') {
|
||||
newEnvironments.push(`${env}=${value}`)
|
||||
@@ -54,8 +59,8 @@ export async function startService(request: FastifyRequest<ServiceStartStop>) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (template.services[service]?.environment?.length > 0) {
|
||||
for (const environment of template.services[service].environment) {
|
||||
if (template.services[s]?.environment?.length > 0) {
|
||||
for (const environment of template.services[s].environment) {
|
||||
const [env, value] = environment.split("=");
|
||||
if (!value.startsWith('$$secret') && value !== '') {
|
||||
newEnvironments.push(`${env}=${value}`)
|
||||
@@ -68,7 +73,7 @@ export async function startService(request: FastifyRequest<ServiceStartStop>) {
|
||||
for (const secret of secrets) {
|
||||
const { name, value } = secret
|
||||
if (value) {
|
||||
const foundEnv = !!template.services[service].environment?.find(env => env.startsWith(`${name}=`))
|
||||
const foundEnv = !!template.services[s].environment?.find(env => env.startsWith(`${name}=`))
|
||||
const foundNewEnv = !!newEnvironments?.find(env => env.startsWith(`${name}=`))
|
||||
if (foundEnv && !foundNewEnv) {
|
||||
newEnvironments.push(`${name}=${decrypt(value)}`)
|
||||
@@ -76,7 +81,7 @@ export async function startService(request: FastifyRequest<ServiceStartStop>) {
|
||||
}
|
||||
}
|
||||
const customVolumes = await prisma.servicePersistentStorage.findMany({ where: { serviceId: id } })
|
||||
let volumes = arm ? template.services[service].volumesArm : template.services[service].volumes
|
||||
let volumes = arm ? template.services[s].volumesArm : template.services[s].volumes
|
||||
if (customVolumes.length > 0) {
|
||||
for (const customVolume of customVolumes) {
|
||||
const { volumeName, path, containerId } = customVolume
|
||||
@@ -85,41 +90,58 @@ export async function startService(request: FastifyRequest<ServiceStartStop>) {
|
||||
}
|
||||
}
|
||||
}
|
||||
config[service] = {
|
||||
container_name: service,
|
||||
build: template.services[service].build || undefined,
|
||||
command: template.services[service].command,
|
||||
entrypoint: template.services[service]?.entrypoint,
|
||||
image: arm ? template.services[service].imageArm : template.services[service].image,
|
||||
expose: template.services[service].ports,
|
||||
if (isWordpress) {
|
||||
const { wordpress: { mysqlHost, mysqlPort, mysqlUser, mysqlPassword, mysqlDatabase, ownMysql } } = service
|
||||
console.log({ mysqlHost, mysqlPort, mysqlUser, mysqlPassword, mysqlDatabase, ownMysql })
|
||||
if (ownMysql) {
|
||||
let envsToRemove = ['WORDPRESS_DB_HOST', 'WORDPRESS_DB_USER', 'WORDPRESS_DB_PASSWORD', 'WORDPRESS_DB_NAME']
|
||||
for (const env of newEnvironments) {
|
||||
if (envsToRemove.includes(env.split('=')[0])) {
|
||||
console.log('removing', env)
|
||||
newEnvironments = newEnvironments.filter(e => e !== env)
|
||||
}
|
||||
}
|
||||
newEnvironments.push(`WORDPRESS_DB_HOST=${mysqlHost}:${mysqlPort}`)
|
||||
newEnvironments.push(`WORDPRESS_DB_USER=${mysqlUser}`)
|
||||
newEnvironments.push(`WORDPRESS_DB_PASSWORD=${mysqlPassword}`)
|
||||
newEnvironments.push(`WORDPRESS_DB_NAME=${mysqlDatabase}`)
|
||||
}
|
||||
}
|
||||
config[s] = {
|
||||
container_name: s,
|
||||
build: template.services[s].build || undefined,
|
||||
command: template.services[s].command,
|
||||
entrypoint: template.services[s]?.entrypoint,
|
||||
image: arm ? template.services[s].imageArm : template.services[s].image,
|
||||
expose: template.services[s].ports,
|
||||
...(exposePort ? { ports: [`${exposePort}:${exposePort}`] } : {}),
|
||||
volumes,
|
||||
environment: newEnvironments,
|
||||
depends_on: template.services[service]?.depends_on,
|
||||
ulimits: template.services[service]?.ulimits,
|
||||
cap_drop: template.services[service]?.cap_drop,
|
||||
cap_add: template.services[service]?.cap_add,
|
||||
depends_on: template.services[s]?.depends_on,
|
||||
ulimits: template.services[s]?.ulimits,
|
||||
cap_drop: template.services[s]?.cap_drop,
|
||||
cap_add: template.services[s]?.cap_add,
|
||||
labels: makeLabelForServices(type),
|
||||
...defaultComposeConfiguration(network),
|
||||
}
|
||||
|
||||
// Generate files for builds
|
||||
if (template.services[service]?.files?.length > 0) {
|
||||
if (!template.services[service].build) {
|
||||
template.services[service].build = {
|
||||
if (template.services[s]?.files?.length > 0) {
|
||||
if (!template.services[s].build) {
|
||||
template.services[s].build = {
|
||||
context: workdir,
|
||||
dockerfile: `Dockerfile.${service}`
|
||||
dockerfile: `Dockerfile.${s}`
|
||||
}
|
||||
}
|
||||
let Dockerfile = `
|
||||
FROM ${template.services[service].image}`
|
||||
for (const file of template.services[service].files) {
|
||||
FROM ${template.services[s].image}`
|
||||
for (const file of template.services[s].files) {
|
||||
const { source, destination, content } = file;
|
||||
await fs.writeFile(source, content);
|
||||
Dockerfile += `
|
||||
COPY ./${path.basename(source)} ${destination}`
|
||||
}
|
||||
await fs.writeFile(`${workdir}/Dockerfile.${service}`, Dockerfile);
|
||||
await fs.writeFile(`${workdir}/Dockerfile.${servsice}`, Dockerfile);
|
||||
}
|
||||
}
|
||||
const { volumeMounts } = persistentVolumes(id, persistentStorage, config)
|
||||
|
||||
@@ -113,7 +113,7 @@ export async function getServiceStatus(request: FastifyRequest<OnlyId>) {
|
||||
}
|
||||
export async function parseAndFindServiceTemplates(service: any, workdir?: string, isDeploy: boolean = false) {
|
||||
const templates = await getTemplates()
|
||||
const foundTemplate = templates.find(t => fixType(t.name) === service.type)
|
||||
const foundTemplate = templates.find(t => fixType(t.type) === service.type)
|
||||
let parsedTemplate = {}
|
||||
if (foundTemplate) {
|
||||
if (!isDeploy) {
|
||||
@@ -130,16 +130,21 @@ export async function parseAndFindServiceTemplates(service: any, workdir?: strin
|
||||
for (const env of value.environment) {
|
||||
const [envKey, envValue] = env.split('=')
|
||||
const variable = foundTemplate.variables.find(v => v.name === envKey) || foundTemplate.variables.find(v => v.id === envValue)
|
||||
const id = variable.id.replaceAll('$$', '')
|
||||
const label = variable?.label
|
||||
const description = variable?.description
|
||||
const defaultValue = variable?.defaultValue
|
||||
const main = variable?.main || '$$id'
|
||||
if (envValue.startsWith('$$config') || variable?.showOnUI) {
|
||||
const type = variable?.type || 'input'
|
||||
const placeholder = variable?.placeholder || ''
|
||||
const readonly = variable?.readonly || false
|
||||
const required = variable?.required || false
|
||||
if (envValue.startsWith('$$config') || variable?.showOnConfiguration) {
|
||||
if (envValue.startsWith('$$config_coolify')) {
|
||||
continue
|
||||
}
|
||||
parsedTemplate[realKey].environment.push(
|
||||
{ name: envKey, value: envValue, main, label, description, defaultValue }
|
||||
{ id, name: envKey, value: envValue, main, label, description, defaultValue, type, placeholder, required, readonly }
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -203,6 +208,9 @@ export async function parseAndFindServiceTemplates(service: any, workdir?: strin
|
||||
if (value) {
|
||||
strParsedTemplate = strParsedTemplate.replaceAll(regexHashed, bcrypt.hashSync(value, 10) + "\"")
|
||||
strParsedTemplate = strParsedTemplate.replaceAll(regex, value + "\"")
|
||||
} else {
|
||||
strParsedTemplate = strParsedTemplate.replaceAll(regexHashed, "\"")
|
||||
strParsedTemplate = strParsedTemplate.replaceAll(regex, "\"")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -249,7 +257,7 @@ export async function saveServiceType(request: FastifyRequest<SaveServiceType>,
|
||||
const { id } = request.params;
|
||||
const { type } = request.body;
|
||||
const templates = await getTemplates()
|
||||
let foundTemplate = templates.find(t => fixType(t.name) === fixType(type))
|
||||
let foundTemplate = templates.find(t => fixType(t.type) === fixType(type))
|
||||
if (foundTemplate) {
|
||||
foundTemplate = JSON.parse(JSON.stringify(foundTemplate).replaceAll('$$id', id))
|
||||
if (foundTemplate.variables.length > 0) {
|
||||
@@ -307,6 +315,10 @@ export async function saveServiceType(request: FastifyRequest<SaveServiceType>,
|
||||
}
|
||||
}
|
||||
await prisma.service.update({ where: { id }, data: { type, version: foundTemplate.defaultVersion, templateVersion: foundTemplate.templateVersion } })
|
||||
|
||||
if (type.startsWith('wordpress')) {
|
||||
await prisma.service.update({ where: { id }, data: { wordpress: { create: {} } } })
|
||||
}
|
||||
return reply.code(201).send()
|
||||
} else {
|
||||
throw { status: 404, message: 'Service type not found.' }
|
||||
@@ -480,7 +492,7 @@ export async function saveService(request: FastifyRequest<SaveService>, reply: F
|
||||
}
|
||||
const templates = await getTemplates()
|
||||
const service = await prisma.service.findUnique({ where: { id } })
|
||||
const foundTemplate = templates.find(t => fixType(t.name) === fixType(service.type))
|
||||
const foundTemplate = templates.find(t => fixType(t.type) === fixType(service.type))
|
||||
for (const setting of serviceSetting) {
|
||||
let { id: settingId, name, value, changed = false, isNew = false, variableName } = setting
|
||||
if (changed) {
|
||||
@@ -506,11 +518,19 @@ export async function saveService(request: FastifyRequest<SaveService>, reply: F
|
||||
export async function getServiceSecrets(request: FastifyRequest<OnlyId>) {
|
||||
try {
|
||||
const { id } = request.params
|
||||
const teamId = request.user.teamId;
|
||||
const service = await getServiceFromDB({ id, teamId });
|
||||
let secrets = await prisma.serviceSecret.findMany({
|
||||
where: { serviceId: id },
|
||||
orderBy: { createdAt: 'desc' }
|
||||
});
|
||||
const templates = await getTemplates()
|
||||
const foundTemplate = templates.find(t => fixType(t.type) === service.type)
|
||||
secrets = secrets.map((secret) => {
|
||||
const foundVariable = foundTemplate?.variables.find(v => v.name === secret.name) || null
|
||||
if (foundVariable) {
|
||||
secret.readonly = foundVariable.readonly
|
||||
}
|
||||
secret.value = decrypt(secret.value);
|
||||
return secret;
|
||||
});
|
||||
|
||||
@@ -381,7 +381,7 @@ export async function traefikConfiguration(request, reply) {
|
||||
} = service;
|
||||
if (destinationDockerId) {
|
||||
const templates = await getTemplates();
|
||||
let found = templates.find((a) => fixType(a.name) === fixType(type));
|
||||
let found = templates.find((a) => a.type === type);
|
||||
if (found) {
|
||||
found = JSON.parse(JSON.stringify(found).replaceAll('$$id', id));
|
||||
for (const oneService of Object.keys(found.services)) {
|
||||
@@ -509,7 +509,7 @@ export async function traefikConfiguration(request, reply) {
|
||||
}
|
||||
} else {
|
||||
traefik.http.routers[`${id}-${port || 'default'}`] = generateHttpRouter(`${id}-${port || 'default'}`, nakedDomain, pathPrefix)
|
||||
traefik.http.routers[`${id}-${port || 'default'}-secure`] = generateProtocolRedirectRouter(`${id}-${port || 'default'}-secure`, nakedDomain, pathPrefix, 'https-to-http')
|
||||
traefik.http.routers[`${id}-${port || 'default'}-secure`] = generateProtocolRedirectRouter(`${id}-${port || 'default'}`, nakedDomain, pathPrefix, 'https-to-http')
|
||||
traefik.http.services[`${id}-${port || 'default'}`] = generateLoadBalancerService(id, port)
|
||||
|
||||
if (!dualCerts) {
|
||||
@@ -873,7 +873,7 @@ export async function remoteTraefikConfiguration(request: FastifyRequest<OnlyId>
|
||||
} = service;
|
||||
if (destinationDockerId) {
|
||||
const templates = await getTemplates();
|
||||
let found = templates.find((a) => fixType(a.name) === fixType(type));
|
||||
let found = templates.find((a) => a.type === type);
|
||||
if (found) {
|
||||
const port = found.ports.main;
|
||||
const publicPort = service[type]?.publicPort;
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
[{"name":"appwrite","image":"appwrite/appwrite","tags":["1.0.3","1.0.1","1.0.0","0.9.3","0.9.1","0.8.0","0.7.1","0.6.2","0.6.0","0.5.2","0.5.0","0.3.1","0.2.0","0.15.2","0.15.0","0.14.2","0.14.0","0.13.4","0.13.2","0.13.0","0.12.3","0.12.1","0.12.0","0.11.2","0.11.0","0.10.4","0.10.2","0.10.0","0.1.8","0.1.6","latest"]},{"name":"weblate","image":"weblate/weblate","tags":["latest","edge-2022-10-26-c69cfdd83ed1fad4a4d57398552b8c70894a6586","edge-2022-10-26-410b3aff37de5bbfacbc47642ce28b2518bee506","edge-2022-10-25-e09e2c29ed3748eb0fa248453635dd27768e8dd9","edge-2022-10-25-a059748c178cce0bc30bdc915d4ff8f0d13ce25c","edge-2022-10-24-94ae069cdcf9a171e812da32d760a436fa9b37ad","edge-2022-10-24-71d2011a1f6d2b60bb65af9f775bf75d4beaf8fd","edge-2022-10-19-acb8e82a0ea2c86fb7ce8f5cb1a81e2bc634583a","edge-2022-10-18-f54b83a0898bef9d14b00d885f675c2e4ebb68ca","edge-2022-10-17-eb9dc248720581052b4be4e3f1f372bce37edd62","edge-2022-10-17-e5a5f6cfdf7e500b7b357566971172fad022c1dc","edge-2022-10-17-da6d01ea005c29453e0111a45956d16bf2262f54","edge-2022-10-17-7a28d7f727778dd05b163fa40ec7903e2e07b20c","edge-2022-10-13-899ea7d8aef900ef216e231433fe15e8dc9a2af8","edge-2022-10-13-385a55156bdc918b0e78ce337322b8996455027a","edge-2022-10-12-5356be32da4b8beb16ba3ec0aa8763f6e08294ab","edge-2022-10-10-d087b31ef728a3a9c3563de9aa4b2ea189755fdf","edge-2022-10-07-f6d43c61fee0e58eb18dd6f80404fba272280c3f","edge-2022-10-05-b86e34a866f40446dc8cb1b48f5d56e621904a0c","edge-2022-10-05-82096af0a688d0104c1c5b973dfc1c6eef6f9d85","edge-2022-10-05-495225a1fd551be41301b53dcd5b10d0c97927bb","edge-2022-10-05-0bb3091700132894e51d806a140145a03489fc09","edge-2022-10-03-9255921fca690c5350ba16960d856c68b910e586","edge-2022-10-03-4b9d377a8289ede1a16b05836eeed0c3b0570dd9","edge-2022-10-01-482ba9c3f7862bca8b1e70d3d0a02806e075d120","edge-2022-09-28-934021ad5497df1c945e42187aaa7d71f6d8d91c","edge-2022-09-26-906b41dd035a8b3949f0afb2bb4d031b88a7b2bb","edge-2022-09-26-8b182a8450dc0541c474c76bf05c7deea16d4345","edge-2022-09-22-dd4d880d619cdca5f8163a1e396136674fe96383","edge-2022-09-19-d7dea01afaf51c9206c0d3d30dc19c31ef5be7df"]},{"name":"searxng","image":"searxng/searxng","tags":["latest-build-cache","latest","2022.10.25-affd8f75","2022.10.25-4783d6c9","2022.10.21-710a3a00","2022.10.14-e2dd5a80","2022.10.14-72f6367e","2022.10.14-4d4dfc58","2022.10.14-2eb81701","2022.10.14-1a5b0965","2022.10.14-096d9def","2022.10.11-a7337612","2022.10.07-84f61af8","2022.10.07-666cd1f6","2022.10.01-e9af772b","2022.10.01-901143f0","2022.10.01-14d0fb2c","2022.09.30-f4281b16","2022.09.30-62324655","2022.09.29-f3d25f9c","2022.09.29-a7d69323","2022.09.29-5f340154","2022.09.29-520a873a","2022.09.29-50607324","2022.09.28-a3148e51","2022.09.28-7097508a","2022.09.28-0e00af9c","2022.09.24-ddd380fc","2022.09.24-c808284f","2022.09.24-bfd6f618"]},{"name":"glitchtip","image":"glitchtip/glitchtip","tags":["v2.0.7","v2.0.5","v2.0.2","v2.0.0","v1.9.2","v1.9.0","v1.8.4","v1.8.2","v1.8.0","v1.7.1","v1.6.4","v1.6.2","v1.6.0","v1.5.3","v1.5.1","v1.4.1","v1.3.3","v1.3.1","v1.2.6","v1.2.4","v1.2.2","v1.2.0","v1.12.4","v1.12.2","v1.12.0","v1.10.3","v1.10.1","v1.1.2","v1.1.0","v1.0.8","latest"]},{"name":"hasura","image":"hasura/graphql-engine","tags":["v2.9.0","v2.8.4","v2.8.3","v2.8.2","v2.8.1","v2.8.0","v2.7.0","v2.6.2","v2.6.1","v2.6.0","v2.5.2","v2.5.1","v2.5.0","v2.4.0","v2.3.1","v2.3.0","v2.2.2","v2.2.1","v2.2.0","v2.13.0","v2.12.0","v2.11.2","v2.11.1","v2.11.0","v2.10.1","v2.10.0","v2.1.1","v2.1.0","v2.0.9","v2.0.8","latest"]},{"name":"umami","image":"ghcr.io/umami-software/umami","tags":["postgresql-v1.39.2","postgresql-v1.39.1","postgresql-v1.39.0","postgresql-v1.38.0","postgresql-v1.37.0","postgresql-v1.36.1","postgresql-v1.36.0","postgresql-v1.35.0","postgresql-v1.34.0","postgresql-v1.33.3","postgresql-latest","mysql-v1.39.2","mysql-v1.39.1","mysql-v1.39.0","mysql-v1.38.0","mysql-v1.37.0","mysql-v1.36.1","mysql-v1.36.0","mysql-v1.35.0","mysql-v1.34.0","mysql-v1.33.3","mysql-latest","latest"]},{"name":"meilisearch","image":"getmeili/meilisearch","tags":["v0.9.0","v0.8.3","v0.8.1","v0.29.1","v0.29.0","v0.28.1","v0.28.0","v0.27.1","v0.27.0","v0.26.1","v0.26.0","v0.25.1","v0.25.0","v0.23.1","v0.23.0","v0.21.1","v0.21.0","v0.20.0","v0.19.0","v0.18.1","v0.18.0","v0.17.0","v0.16.0","v0.14.1","v0.14.0","v0.12.0","v0.11.0","v0.10.0","0.14.1","latest"]},{"name":"ghost","image":"bitnami/ghost","tags":["5.7.1","5.7.0","5.5.0","5.4.1","5.4.0","5.3.1","5.3.0","5.20.0","5.2.4","5.2.3","5.2.2","5.2.1","5.19.3","5.19.2","5.19.1","5.19.0","5.18.0","5.17.2","5.17.1","5.17.0","5.16.2","5.16.1","5.16.0","5.15.0","5.14.2","5.14.1","5.14.0","5.13.2","5.13.1","5.13.0","latest"]},{"name":"wordpress","image":"library/wordpress","tags":["6.0.3","6.0.2","6.0.1","6.0.0","5.9.3","5.9.2","5.9.1","5.9.0","5.8.3","5.8.2","5.8.1","5.8.0","5.7.2","5.7.1","5.7.0","5.6.2","5.6.1","5.6.0","5.5.3","5.5.1","5.5.0","5.4.2","5.4.1","5.4.0","5.3.2","5.3.1","5.3.0","5.2.4","5.2.3","5.2.2","latest"]},{"name":"vscodeserver","image":"codercom/code-serverLine truncated
|
||||
[{"name":"appwrite","image":"appwrite/appwrite","tags":["1.0.3","1.0.1","1.0.0","0.9.3","0.9.1","0.8.0","0.7.1","0.6.2","0.6.0","0.5.2","0.5.0","0.3.1","0.2.0","0.15.2","0.15.0","0.14.2","0.14.0","0.13.4","0.13.2","0.13.0","0.12.3","0.12.1","0.12.0","0.11.2","0.11.0","0.10.4","0.10.2","0.10.0","0.1.8","0.1.6","latest"]},{"name":"weblate","image":"weblate/weblate","tags":["latest","edge-2022-10-26-c69cfdd83ed1fad4a4d57398552b8c70894a6586","edge-2022-10-26-410b3aff37de5bbfacbc47642ce28b2518bee506","edge-2022-10-25-e09e2c29ed3748eb0fa248453635dd27768e8dd9","edge-2022-10-25-a059748c178cce0bc30bdc915d4ff8f0d13ce25c","edge-2022-10-24-94ae069cdcf9a171e812da32d760a436fa9b37ad","edge-2022-10-24-71d2011a1f6d2b60bb65af9f775bf75d4beaf8fd","edge-2022-10-19-acb8e82a0ea2c86fb7ce8f5cb1a81e2bc634583a","edge-2022-10-18-f54b83a0898bef9d14b00d885f675c2e4ebb68ca","edge-2022-10-17-eb9dc248720581052b4be4e3f1f372bce37edd62","edge-2022-10-17-e5a5f6cfdf7e500b7b357566971172fad022c1dc","edge-2022-10-17-da6d01ea005c29453e0111a45956d16bf2262f54","edge-2022-10-17-7a28d7f727778dd05b163fa40ec7903e2e07b20c","edge-2022-10-13-899ea7d8aef900ef216e231433fe15e8dc9a2af8","edge-2022-10-13-385a55156bdc918b0e78ce337322b8996455027a","edge-2022-10-12-5356be32da4b8beb16ba3ec0aa8763f6e08294ab","edge-2022-10-10-d087b31ef728a3a9c3563de9aa4b2ea189755fdf","edge-2022-10-07-f6d43c61fee0e58eb18dd6f80404fba272280c3f","edge-2022-10-05-b86e34a866f40446dc8cb1b48f5d56e621904a0c","edge-2022-10-05-82096af0a688d0104c1c5b973dfc1c6eef6f9d85","edge-2022-10-05-495225a1fd551be41301b53dcd5b10d0c97927bb","edge-2022-10-05-0bb3091700132894e51d806a140145a03489fc09","edge-2022-10-03-9255921fca690c5350ba16960d856c68b910e586","edge-2022-10-03-4b9d377a8289ede1a16b05836eeed0c3b0570dd9","edge-2022-10-01-482ba9c3f7862bca8b1e70d3d0a02806e075d120","edge-2022-09-28-934021ad5497df1c945e42187aaa7d71f6d8d91c","edge-2022-09-26-906b41dd035a8b3949f0afb2bb4d031b88a7b2bb","edge-2022-09-26-8b182a8450dc0541c474c76bf05c7deea16d4345","edge-2022-09-22-dd4d880d619cdca5f8163a1e396136674fe96383","edge-2022-09-19-d7dea01afaf51c9206c0d3d30dc19c31ef5be7df"]},{"name":"searxng","image":"searxng/searxng","tags":["2022.10.28-c26fa335","2022.10.28-5db4ed5d","2022.10.28-5a181ea1","2022.10.25-affd8f75","2022.10.25-4783d6c9","2022.10.21-710a3a00","2022.10.14-e2dd5a80","2022.10.14-72f6367e","2022.10.14-4d4dfc58","2022.10.14-2eb81701","2022.10.14-1a5b0965","2022.10.14-096d9def","2022.10.11-a7337612","2022.10.07-84f61af8","2022.10.07-666cd1f6","2022.10.01-e9af772b","2022.10.01-901143f0","2022.10.01-14d0fb2c","2022.09.30-f4281b16","2022.09.30-62324655","2022.09.29-f3d25f9c","2022.09.29-a7d69323","2022.09.29-5f340154","2022.09.29-520a873a","2022.09.29-50607324","2022.09.28-a3148e51","2022.09.28-7097508a","2022.09.28-0e00af9c","2022.09.24-ddd380fc","2022.09.24-c808284f","latest"]},{"name":"glitchtip","image":"glitchtip/glitchtip","tags":["v2.0.7","v2.0.5","v2.0.2","v2.0.0","v1.9.2","v1.9.0","v1.8.4","v1.8.2","v1.8.0","v1.7.1","v1.6.4","v1.6.2","v1.6.0","v1.5.3","v1.5.1","v1.4.1","v1.3.3","v1.3.1","v1.2.6","v1.2.4","v1.2.2","v1.2.0","v1.12.4","v1.12.2","v1.12.0","v1.10.3","v1.10.1","v1.1.2","v1.1.0","v1.0.8","latest"]},{"name":"hasura","image":"hasura/graphql-engine","tags":["v2.9.0","v2.8.4","v2.8.3","v2.8.2","v2.8.1","v2.8.0","v2.7.0","v2.6.2","v2.6.1","v2.6.0","v2.5.2","v2.5.1","v2.5.0","v2.4.0","v2.3.1","v2.3.0","v2.2.2","v2.2.1","v2.2.0","v2.13.0","v2.12.0","v2.11.2","v2.11.1","v2.11.0","v2.10.1","v2.10.0","v2.1.1","v2.1.0","v2.0.9","v2.0.8","latest"]},{"name":"umami","image":"ghcr.io/umami-software/umami","tags":["postgresql-v1.39.3","postgresql-v1.39.2","postgresql-v1.39.1","postgresql-v1.39.0","postgresql-v1.38.0","postgresql-v1.37.0","postgresql-v1.36.1","postgresql-v1.36.0","postgresql-v1.35.0","postgresql-v1.34.0","postgresql-v1.33.3","postgresql-latest","mysql-v1.39.3","mysql-v1.39.2","mysql-v1.39.1","mysql-v1.39.0","mysql-v1.38.0","mysql-v1.37.0","mysql-v1.36.1","mysql-v1.36.0","mysql-v1.35.0","mysql-v1.34.0","mysql-v1.33.3","mysql-latest","latest"]},{"name":"meilisearch","image":"getmeili/meilisearch","tags":["v0.9.0","v0.8.3","v0.8.1","v0.29.1","v0.29.0","v0.28.1","v0.28.0","v0.27.1","v0.27.0","v0.26.1","v0.26.0","v0.25.1","v0.25.0","v0.23.1","v0.23.0","v0.21.1","v0.21.0","v0.20.0","v0.19.0","v0.18.1","v0.18.0","v0.17.0","v0.16.0","v0.14.1","v0.14.0","v0.12.0","v0.11.0","v0.10.0","0.14.1","latest"]},{"name":"ghost","image":"bitnami/ghost","tags":["5.7.1","5.7.0","5.5.0","5.4.1","5.4.0","5.3.1","5.3.0","5.20.0","5.2.4","5.2.3","5.2.2","5.2.1","5.19.3","5.19.2","5.19.1","5.19.0","5.18.0","5.17.2","5.17.1","5.17.0","5.16.2","5.16.1","5.16.0","5.15.0","5.14.2","5.14.1","5.14.0","5.13.2","5.13.1","5.13.0","latest"]},{"name":"wordpress","image":"library/wordpress","tags":["php8.1-fpm-alpine","php8.1-fpm","php8.1-apache","php8.1","php8.0-fpm-alpine","php8.0-fpm","php8.0-apache","php8.0","php7.4-fpm-alpine","php7.4-fpm","php7.4-apache","php7.4","php7.3-fpm-alpine","php7.3-fpm","php7.3-apache","php7.3","php7.2-fpmLine truncated
|
||||
@@ -1 +1 @@
|
||||
[{"templateVersion":"1.0.0","defaultVersion":"1.0.3","name":"Appwrite","documentation":"https://appwrite.io/docs","description":"Secure Backend Server for Web, Mobile & Flutter Developers.","services":{"$$id":{"image":"appwrite/appwrite:$$core_version","environment":["_APP_ENV=$$config__app_env","_APP_WORKER_PER_CORE=$$config__app_worker_per_core","_APP_LOCALE=$$config__app_locale","_APP_CONSOLE_WHITELIST_ROOT=$$config__app_console_whitelist_root","_APP_CONSOLE_WHITELIST_EMAILS=$$config__app_console_whitelist_emails","_APP_CONSOLE_WHITELIST_IPS=$$config__app_console_whitelist_ips","_APP_SYSTEM_EMAIL_NAME=$$config__app_system_email_name","_APP_SYSTEM_EMAIL_ADDRESS=$$config__app_system_email_address","_APP_SYSTEM_SECURITY_EMAIL_ADDRESS=$$config__app_system_security_email_address","_APP_SYSTEM_RESPONSE_FORMAT=$$config__app_system_response_format","_APP_OPTIONS_ABUSE=$$config__app_options_abuse","_APP_OPTIONS_FORCE_HTTPS=$$config__app_options_force_https","_APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1","_APP_DOMAIN=$$generate_fqdn","_APP_DOMAIN_TARGET=$$generate_fqdn","_APP_REDIS_HOST=$$config__app_redis_host","_APP_REDIS_PORT=$$config__app_redis_port","_APP_REDIS_USER=$$config__app_redis_user","_APP_REDIS_PASS=$$secret__app_redis_pass","_APP_DB_HOST=$$config__app_db_host","_APP_DB_PORT=$$config__app_db_port","_APP_DB_SCHEMA=$$config__app_db_schema","_APP_DB_USER=$$config__app_db_user","_APP_DB_PASS=$$secret__app_db_pass","_APP_SMTP_HOST=$$config__app_smtp_host","_APP_SMTP_PORT=$$config__app_smtp_port","_APP_SMTP_SECURE=$$config__app_smtp_secure","_APP_SMTP_USERNAME=$$config__app_smtp_username","_APP_SMTP_PASSWORD=$$secret__app_smtp_password","_APP_USAGE_STATS=$$config__app_usage_stats","_APP_INFLUXDB_HOST=$$config__app_influxdb_host","_APP_INFLUXDB_PORT=$$config__app_influxdb_port","_APP_STORAGE_LIMIT=$$config__app_storage_limit","_APP_STORAGE_PREVIEW_LIMIT=$$config__app_storage_preview_limit","_APP_STORAGE_ANTIVIRUS=$$config__app_storage_antivirus_enabled","_APP_STORAGE_ANTIVIRUS_HOST=$$config__app_storage_antivirus_host","_APP_STORAGE_ANTIVIRUS_PORT=$$config__app_storage_antivirus_port","_APP_STORAGE_DEVICE=$$config__app_storage_device","_APP_STORAGE_S3_ACCESS_KEY=$$secret__app_storage_s3_access_key","_APP_STORAGE_S3_SECRET=$$secret__app_storage_s3_secret","_APP_STORAGE_S3_REGION=$$config__app_storage_s3_region","_APP_STORAGE_S3_BUCKET=$$config__app_storage_s3_bucket","_APP_STORAGE_DO_SPACES_ACCESS_KEY=$$secret__app_storage_do_spaces_access_key","_APP_STORAGE_DO_SPACES_SECRET=$$secret__app_storage_do_spaces_secret","_APP_STORAGE_DO_SPACES_REGION=$$config__app_storage_do_spaces_region","_APP_STORAGE_DO_SPACES_BUCKET=$$config__app_storage_do_spaces_bucket","_APP_STORAGE_BACKBLAZE_ACCESS_KEY=$$secret__app_storage_backblaze_access_key","_APP_STORAGE_BACKBLAZE_SECRET=$$secret__app_storage_backblaze_secret","_APP_STORAGE_BACKBLAZE_REGION=$$config__app_storage_backblaze_region","_APP_STORAGE_BACKBLAZE_BUCKET=$$config__app_storage_backblaze_bucket","_APP_STORAGE_LINODE_ACCESS_KEY=$$secret__app_storage_linode_access_key","_APP_STORAGE_LINODE_SECRET=$$secret__app_storage_linode_secret","_APP_STORAGE_LINODE_REGION=$$config__app_storage_linode_region","_APP_STORAGE_LINODE_BUCKET=$$config__app_storage_linode_bucket","_APP_STORAGE_WASABI_ACCESS_KEY=$$secret__app_storage_wasabi_access_key","_APP_STORAGE_WASABI_SECRET=$$secret__app_storage_wasabi_secret","_APP_STORAGE_WASABI_REGION=$$config__app_storage_wasabi_region","_APP_STORAGE_WASABI_BUCKET=$$config__app_storage_wasabi_bucket","_APP_FUNCTIONS_SIZE_LIMIT=$$config__app_functions_size_limit","_APP_FUNCTIONS_TIMEOUT=$$config__app_functions_timeout","_APP_FUNCTIONS_BUILD_TIMEOUT=$$config__app_functions_build_timeout","_APP_FUNCTIONS_CONTAINERS=$$config__app_functions_containers","_APP_FUNCTIONS_CPUS=$$config__app_functions_cpus","_APP_FUNCTIONS_MEMORY=$$config__app_functions_memory_allocated","_APP_FUNCTIONS_MEMORY_SWAP=$$config__app_functions_memory_swap","_APP_FUNCTIONS_RUNTIMES=$$config__app_functions_runtimes","_APP_EXECUTOR_SECRET=$$secret__app_executor_secret","_APP_EXECUTOR_HOST=$$config__app_executor_host","_APP_LOGGING_PROVIDER=$$config__app_logging_provider","_APP_LOGGING_CONFIG=$$config__app_logging_config","_APP_STATSD_HOST=$$config__app_statsd_host","_APP_STATSD_PORT=$$config__app_statsd_port","_APP_MAINTENANCE_INTERVAL=$$config__app_maintenance_interval","_APP_MAINTENANCE_RETENTION_EXECUTION=$$config__app_maintenance_retention_execution","_APP_MAINTENANCE_RETENTION_CACHE=$$config__app_maintenance_retention_cache","_APP_MAINTENANCE_RETENTION_ABUSE=$$config__app_maintenance_retention_abuse","_APP_MAINTENANCE_RETENTION_AUDIT=$$config__app_maintenance_retention_audit","_APP_SMS_PROVIDER=$$config__app_sms_provider","_APP_SMS_FROM=$$config__app_sms_from","OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network"],"volumes":["$$id-uploads:/storage/uploads","$$id-cache:/storage/cache","$$id-config:/storage/config","$$id-certificates:/storage/certificates","$$id-functiLine truncated
|
||||
[{"templateVersion":"1.0.0","defaultVersion":"1.0.3","type":"appwrite","name":"Appwrite","documentation":"https://appwrite.io/docs","description":"Secure Backend Server for Web, Mobile & Flutter Developers.","services":{"$$id":{"image":"appwrite/appwrite:$$core_version","environment":["_APP_ENV=$$config__app_env","_APP_WORKER_PER_CORE=$$config__app_worker_per_core","_APP_LOCALE=$$config__app_locale","_APP_CONSOLE_WHITELIST_ROOT=$$config__app_console_whitelist_root","_APP_CONSOLE_WHITELIST_EMAILS=$$config__app_console_whitelist_emails","_APP_CONSOLE_WHITELIST_IPS=$$config__app_console_whitelist_ips","_APP_SYSTEM_EMAIL_NAME=$$config__app_system_email_name","_APP_SYSTEM_EMAIL_ADDRESS=$$config__app_system_email_address","_APP_SYSTEM_SECURITY_EMAIL_ADDRESS=$$config__app_system_security_email_address","_APP_SYSTEM_RESPONSE_FORMAT=$$config__app_system_response_format","_APP_OPTIONS_ABUSE=$$config__app_options_abuse","_APP_OPTIONS_FORCE_HTTPS=$$config__app_options_force_https","_APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1","_APP_DOMAIN=$$generate_fqdn","_APP_DOMAIN_TARGET=$$generate_fqdn","_APP_REDIS_HOST=$$config__app_redis_host","_APP_REDIS_PORT=$$config__app_redis_port","_APP_REDIS_USER=$$config__app_redis_user","_APP_REDIS_PASS=$$secret__app_redis_pass","_APP_DB_HOST=$$config__app_db_host","_APP_DB_PORT=$$config__app_db_port","_APP_DB_SCHEMA=$$config__app_db_schema","_APP_DB_USER=$$config__app_db_user","_APP_DB_PASS=$$secret__app_db_pass","_APP_SMTP_HOST=$$config__app_smtp_host","_APP_SMTP_PORT=$$config__app_smtp_port","_APP_SMTP_SECURE=$$config__app_smtp_secure","_APP_SMTP_USERNAME=$$config__app_smtp_username","_APP_SMTP_PASSWORD=$$secret__app_smtp_password","_APP_USAGE_STATS=$$config__app_usage_stats","_APP_INFLUXDB_HOST=$$config__app_influxdb_host","_APP_INFLUXDB_PORT=$$config__app_influxdb_port","_APP_STORAGE_LIMIT=$$config__app_storage_limit","_APP_STORAGE_PREVIEW_LIMIT=$$config__app_storage_preview_limit","_APP_STORAGE_ANTIVIRUS=$$config__app_storage_antivirus_enabled","_APP_STORAGE_ANTIVIRUS_HOST=$$config__app_storage_antivirus_host","_APP_STORAGE_ANTIVIRUS_PORT=$$config__app_storage_antivirus_port","_APP_STORAGE_DEVICE=$$config__app_storage_device","_APP_STORAGE_S3_ACCESS_KEY=$$secret__app_storage_s3_access_key","_APP_STORAGE_S3_SECRET=$$secret__app_storage_s3_secret","_APP_STORAGE_S3_REGION=$$config__app_storage_s3_region","_APP_STORAGE_S3_BUCKET=$$config__app_storage_s3_bucket","_APP_STORAGE_DO_SPACES_ACCESS_KEY=$$secret__app_storage_do_spaces_access_key","_APP_STORAGE_DO_SPACES_SECRET=$$secret__app_storage_do_spaces_secret","_APP_STORAGE_DO_SPACES_REGION=$$config__app_storage_do_spaces_region","_APP_STORAGE_DO_SPACES_BUCKET=$$config__app_storage_do_spaces_bucket","_APP_STORAGE_BACKBLAZE_ACCESS_KEY=$$secret__app_storage_backblaze_access_key","_APP_STORAGE_BACKBLAZE_SECRET=$$secret__app_storage_backblaze_secret","_APP_STORAGE_BACKBLAZE_REGION=$$config__app_storage_backblaze_region","_APP_STORAGE_BACKBLAZE_BUCKET=$$config__app_storage_backblaze_bucket","_APP_STORAGE_LINODE_ACCESS_KEY=$$secret__app_storage_linode_access_key","_APP_STORAGE_LINODE_SECRET=$$secret__app_storage_linode_secret","_APP_STORAGE_LINODE_REGION=$$config__app_storage_linode_region","_APP_STORAGE_LINODE_BUCKET=$$config__app_storage_linode_bucket","_APP_STORAGE_WASABI_ACCESS_KEY=$$secret__app_storage_wasabi_access_key","_APP_STORAGE_WASABI_SECRET=$$secret__app_storage_wasabi_secret","_APP_STORAGE_WASABI_REGION=$$config__app_storage_wasabi_region","_APP_STORAGE_WASABI_BUCKET=$$config__app_storage_wasabi_bucket","_APP_FUNCTIONS_SIZE_LIMIT=$$config__app_functions_size_limit","_APP_FUNCTIONS_TIMEOUT=$$config__app_functions_timeout","_APP_FUNCTIONS_BUILD_TIMEOUT=$$config__app_functions_build_timeout","_APP_FUNCTIONS_CONTAINERS=$$config__app_functions_containers","_APP_FUNCTIONS_CPUS=$$config__app_functions_cpus","_APP_FUNCTIONS_MEMORY=$$config__app_functions_memory_allocated","_APP_FUNCTIONS_MEMORY_SWAP=$$config__app_functions_memory_swap","_APP_FUNCTIONS_RUNTIMES=$$config__app_functions_runtimes","_APP_EXECUTOR_SECRET=$$secret__app_executor_secret","_APP_EXECUTOR_HOST=$$config__app_executor_host","_APP_LOGGING_PROVIDER=$$config__app_logging_provider","_APP_LOGGING_CONFIG=$$config__app_logging_config","_APP_STATSD_HOST=$$config__app_statsd_host","_APP_STATSD_PORT=$$config__app_statsd_port","_APP_MAINTENANCE_INTERVAL=$$config__app_maintenance_interval","_APP_MAINTENANCE_RETENTION_EXECUTION=$$config__app_maintenance_retention_execution","_APP_MAINTENANCE_RETENTION_CACHE=$$config__app_maintenance_retention_cache","_APP_MAINTENANCE_RETENTION_ABUSE=$$config__app_maintenance_retention_abuse","_APP_MAINTENANCE_RETENTION_AUDIT=$$config__app_maintenance_retention_audit","_APP_SMS_PROVIDER=$$config__app_sms_provider","_APP_SMS_FROM=$$config__app_sms_from","OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network"],"volumes":["$$id-uploads:/storage/uploads","$$id-cache:/storage/cache","$$id-config:/storage/config","$$id-certificates:/storage/certificLine truncated
|
||||
@@ -2,7 +2,12 @@
|
||||
export let type: string;
|
||||
export let isAbsolute = true;
|
||||
import * as Icons from '$lib/components/svg/services';
|
||||
const name: any = type && type[0].toUpperCase() + type.substring(1).toLowerCase();
|
||||
const name: any =
|
||||
type &&
|
||||
(type[0].toUpperCase() + type.substring(1).toLowerCase())
|
||||
.replaceAll('.', '')
|
||||
.replaceAll(' ', '')
|
||||
.split('-')[0];
|
||||
</script>
|
||||
|
||||
<svelte:component this={Icons[name.replace('.','').replaceAll(' ','')]} {isAbsolute} />
|
||||
<svelte:component this={Icons[name]} {isAbsolute} />
|
||||
@@ -41,7 +41,7 @@
|
||||
"saving": "Saving...",
|
||||
"name": "Name",
|
||||
"value": "Value",
|
||||
"action": "Action",
|
||||
"action": "Actions",
|
||||
"is_required": "is required.",
|
||||
"add": "Add",
|
||||
"set": "Set",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script lang="ts">
|
||||
export let name = '';
|
||||
export let value = '';
|
||||
export let readonly = false;
|
||||
export let isNewSecret = false;
|
||||
|
||||
import { page } from '$app/stores';
|
||||
@@ -55,19 +56,20 @@
|
||||
bind:value={name}
|
||||
required
|
||||
placeholder="EXAMPLE_VARIABLE"
|
||||
readonly={!isNewSecret}
|
||||
readonly={!isNewSecret || readonly}
|
||||
class="w-full"
|
||||
class:bg-coolblack={!isNewSecret}
|
||||
class:border={!isNewSecret}
|
||||
class:border-dashed={!isNewSecret}
|
||||
class:border-coolgray-300={!isNewSecret}
|
||||
class:cursor-not-allowed={!isNewSecret}
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<CopyPasswordField
|
||||
id={isNewSecret ? 'secretValue' : 'secretValueNew'}
|
||||
name={isNewSecret ? 'secretValue' : 'secretValueNew'}
|
||||
disabled={readonly}
|
||||
{readonly}
|
||||
isPasswordField={true}
|
||||
bind:value
|
||||
placeholder="J$#@UIO%HO#$U%H"
|
||||
@@ -80,7 +82,7 @@
|
||||
<div class="flex items-center justify-center">
|
||||
<button class="btn btn-sm btn-primary" on:click={() => saveSecret(true)}>Add</button>
|
||||
</div>
|
||||
{:else}
|
||||
{:else if !readonly}
|
||||
<div class="flex flex-row justify-center space-x-2">
|
||||
<div class="flex items-center justify-center">
|
||||
<button class="btn btn-sm btn-primary" on:click={() => saveSecret(false)}>Set</button>
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
<script lang="ts">
|
||||
import { post } from '$lib/api';
|
||||
import { page } from '$app/stores';
|
||||
import { status } from '$lib/store';
|
||||
import CopyPasswordField from '$lib/components/CopyPasswordField.svelte';
|
||||
import Setting from '$lib/components/Setting.svelte';
|
||||
import { browser } from '$app/env';
|
||||
import { errorNotification, getDomain } from '$lib/common';
|
||||
|
||||
export let service: any;
|
||||
const { id } = $page.params;
|
||||
const settings = service.settings;
|
||||
const { ipv4, ipv6 } = settings;
|
||||
|
||||
let ftpUrl = generateUrl(service.wordpress?.ftpPublicPort) || '';
|
||||
let ftpUser = service.wordpress?.ftpUser;
|
||||
let ftpPassword = service.wordpress?.ftpPassword;
|
||||
let ftpLoading = false;
|
||||
let ftpEnabled = service.wordpress?.ftpEnabled || false;
|
||||
|
||||
function generateUrl(publicPort: any) {
|
||||
return browser
|
||||
? `sftp://${settings?.fqdn ? getDomain(settings.fqdn) : ipv4 || ipv6}:${publicPort}`
|
||||
: 'Loading...';
|
||||
}
|
||||
async function changeSettings(name: any) {
|
||||
if (ftpLoading) return;
|
||||
if ($status.service.overallStatus === 'healthy') {
|
||||
ftpLoading = true;
|
||||
if (name === 'ftpEnabled') {
|
||||
ftpEnabled = !ftpEnabled;
|
||||
}
|
||||
|
||||
try {
|
||||
const {
|
||||
publicPort,
|
||||
ftpUser: user,
|
||||
ftpPassword: password
|
||||
} = await post(`/services/${id}/wordpress/ftp`, {
|
||||
ftpEnabled
|
||||
});
|
||||
ftpUrl = generateUrl(publicPort);
|
||||
ftpUser = user;
|
||||
ftpPassword = password;
|
||||
service.wordpress.ftpEnabled = ftpEnabled;
|
||||
} catch (error) {
|
||||
return errorNotification(error);
|
||||
} finally {
|
||||
ftpLoading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<Setting
|
||||
id="ftpEnabled"
|
||||
bind:setting={ftpEnabled}
|
||||
loading={ftpLoading}
|
||||
disabled={$status.service.overallStatus !== 'healthy'}
|
||||
on:click={() => changeSettings('ftpEnabled')}
|
||||
title="Enable sFTP connection to WordPress data"
|
||||
description="Enables an on-demand sFTP connection to the WordPress data directory. This is useful if you want to use sFTP to upload files."
|
||||
/>
|
||||
</div>
|
||||
{#if service.wordpress?.ftpEnabled}
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="ftpUrl">sFTP Connection URI</label>
|
||||
<CopyPasswordField id="ftpUrl" readonly disabled name="ftpUrl" value={ftpUrl} />
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="ftpUser">User</label>
|
||||
<CopyPasswordField id="ftpUser" readonly disabled name="ftpUser" value={ftpUser} />
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="ftpPassword">Password</label>
|
||||
<CopyPasswordField
|
||||
id="ftpPassword"
|
||||
isPasswordField
|
||||
readonly
|
||||
disabled
|
||||
name="ftpPassword"
|
||||
value={ftpPassword}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
@@ -41,7 +41,7 @@
|
||||
|
||||
async function handleSubmit(service: any) {
|
||||
try {
|
||||
await post(`/services/${id}/configuration/type`, { type: service.name });
|
||||
await post(`/services/${id}/configuration/type`, { type: service.type });
|
||||
return await goto(from || `/services/${id}`);
|
||||
} catch (error) {
|
||||
return errorNotification(error);
|
||||
@@ -50,8 +50,8 @@
|
||||
function doSearch() {
|
||||
filteredServices = services.filter(
|
||||
(service: any) =>
|
||||
service.name.toLowerCase().includes(search.toLowerCase()) ||
|
||||
service.labels?.some((label: string) => label.toLowerCase().includes(search.toLowerCase()))
|
||||
service.name.toLowerCase().includes(search.toLowerCase()) ||
|
||||
service.labels?.some((label: string) => label.toLowerCase().includes(search.toLowerCase()))
|
||||
);
|
||||
}
|
||||
function cleanupSearch() {
|
||||
@@ -62,6 +62,7 @@
|
||||
|
||||
<div class="container lg:mx-auto lg:p-0 px-8 pt-5">
|
||||
<div class="input-group flex w-full">
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div class="btn btn-square cursor-default no-animation hover:bg-error" on:click={cleanupSearch}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@@ -91,15 +92,15 @@
|
||||
<div class="container lg:mx-auto lg:pt-20 lg:p-0 px-8 pt-20">
|
||||
<div class="flex flex-wrap justify-center gap-8">
|
||||
{#each filteredServices as service}
|
||||
{#key service.name}
|
||||
<div class="p-2">
|
||||
<form on:submit|preventDefault={() => handleSubmit(service)}>
|
||||
<button type="submit" class="box-selection relative text-xl font-bold hover:bg-primary">
|
||||
<ServiceIcons type={service.name} />
|
||||
{service.name}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
{#key service.name}
|
||||
<div class="p-2">
|
||||
<form on:submit|preventDefault={() => handleSubmit(service)}>
|
||||
<button type="submit" class="box-selection relative text-xl font-bold hover:bg-primary">
|
||||
<ServiceIcons type={service.type} />
|
||||
{service.name}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
{/key}
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
import ServiceStatus from '$lib/components/ServiceStatus.svelte';
|
||||
import { saveForm } from './utils';
|
||||
import Select from 'svelte-select';
|
||||
import Wordpress from './_Services/wordpress.svelte';
|
||||
|
||||
const { id } = $page.params;
|
||||
$: isDisabled =
|
||||
@@ -86,7 +87,7 @@
|
||||
exposePort: service.exposePort
|
||||
});
|
||||
for (const setting of service.serviceSetting) {
|
||||
if (setting.variableName.startsWith('$$coolify_fqdn') && setting.value) {
|
||||
if (setting.variableName?.startsWith('$$coolify_fqdn') && setting.value) {
|
||||
for (let field of formData) {
|
||||
const [key, value] = field;
|
||||
if (setting.name === key) {
|
||||
@@ -413,7 +414,6 @@
|
||||
{template[oneService].name ||
|
||||
oneService.replace(`${id}-`, '').replace(id, service.type)}
|
||||
</div>
|
||||
|
||||
<ServiceStatus id={oneService} />
|
||||
</div>
|
||||
<div class="grid grid-flow-row gap-2 px-4">
|
||||
@@ -434,6 +434,8 @@
|
||||
name={variable.name}
|
||||
id={variable.name}
|
||||
value={service.fqdn}
|
||||
placeholder={variable.placeholder}
|
||||
required={variable?.required}
|
||||
/>
|
||||
{:else if variable.defaultValue === '$$generate_domain'}
|
||||
<CopyPasswordField
|
||||
@@ -442,6 +444,8 @@
|
||||
name={variable.name}
|
||||
id={variable.name}
|
||||
value={getDomain(service.fqdn) || ''}
|
||||
placeholder={variable.placeholder}
|
||||
required={variable?.required}
|
||||
/>
|
||||
{:else if variable.defaultValue === '$$generate_network'}
|
||||
<CopyPasswordField
|
||||
@@ -450,6 +454,8 @@
|
||||
name={variable.name}
|
||||
id={variable.name}
|
||||
value={service.destinationDocker.network}
|
||||
placeholder={variable.placeholder}
|
||||
required={variable?.required}
|
||||
/>
|
||||
{:else if variable.defaultValue === 'true' || variable.defaultValue === 'false'}
|
||||
{#if variable.value === 'true' || variable.value === 'false'}
|
||||
@@ -461,6 +467,8 @@
|
||||
name={variable.name}
|
||||
bind:value={variable.value}
|
||||
form="saveForm"
|
||||
placeholder={variable.placeholder}
|
||||
required={variable?.required}
|
||||
>
|
||||
<option value="true">enabled</option>
|
||||
<option value="false">disabled</option>
|
||||
@@ -474,6 +482,8 @@
|
||||
name={variable.name}
|
||||
bind:value={variable.defaultValue}
|
||||
form="saveForm"
|
||||
placeholder={variable.placeholder}
|
||||
required={variable?.required}
|
||||
>
|
||||
<option value="true">true</option>
|
||||
<option value="false"> false</option>
|
||||
@@ -487,21 +497,40 @@
|
||||
name={variable.name}
|
||||
id={variable.name}
|
||||
value={variable.value}
|
||||
placeholder={variable.placeholder}
|
||||
required={variable?.required}
|
||||
/>
|
||||
{:else if variable.type === 'textarea'}
|
||||
<textarea
|
||||
class="w-full"
|
||||
value={variable.value}
|
||||
readonly={isDisabled}
|
||||
disabled={isDisabled}
|
||||
class:resize-none={$status.service.overallStatus === 'healthy'}
|
||||
rows="5"
|
||||
name={variable.name}
|
||||
id={variable.name}
|
||||
placeholder={variable.placeholder}
|
||||
required={variable?.required}
|
||||
/>
|
||||
{:else}
|
||||
<CopyPasswordField
|
||||
placeholder={variable.defaultValue || 'optional'}
|
||||
isPasswordField={variable.id.startsWith('secret')}
|
||||
required={variable?.required}
|
||||
readonly={isDisabled}
|
||||
disabled={isDisabled}
|
||||
readonly={variable.readonly || isDisabled}
|
||||
disabled={variable.readonly || isDisabled}
|
||||
name={variable.name}
|
||||
id={variable.name}
|
||||
value={variable.value}
|
||||
placeholder={variable.placeholder}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
{#if template[oneService].name.toLowerCase() === 'wordpress' && service.type.startsWith('wordpress')}
|
||||
<Wordpress {service} />
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
|
||||
<script lang="ts">
|
||||
export let secrets: any;
|
||||
export let service: any;
|
||||
import Secret from './_Secret.svelte';
|
||||
import { page } from '$app/stores';
|
||||
import { get } from '$lib/api';
|
||||
@@ -84,7 +83,7 @@
|
||||
{#each secrets as secret}
|
||||
{#key secret.id}
|
||||
<tr>
|
||||
<Secret name={secret.name} value={secret.value} on:refresh={refreshSecrets} />
|
||||
<Secret name={secret.name} value={secret.value} readonly={secret.readonly} on:refresh={refreshSecrets} />
|
||||
</tr>
|
||||
{/key}
|
||||
{/each}
|
||||
|
||||
@@ -43,27 +43,36 @@ export async function saveSecret({
|
||||
|
||||
export async function saveForm(formData: any, service: any) {
|
||||
const settings = service.serviceSetting.map((setting: { name: string }) => setting.name);
|
||||
const secrets = service.serviceSecret.map((secret: { name: string }) => secret.name);
|
||||
const baseCoolifySetting = ['name', 'fqdn', 'exposePort', 'version'];
|
||||
for (let field of formData) {
|
||||
const [key, value] = field;
|
||||
service.serviceSetting = service.serviceSetting.map((setting: any) => {
|
||||
if (setting.name === key) {
|
||||
setting.changed = true;
|
||||
setting.value = value;
|
||||
}
|
||||
return setting;
|
||||
});
|
||||
if (!settings.includes(key) && !baseCoolifySetting.includes(key)) {
|
||||
service.serviceSetting.push({
|
||||
id: service.id,
|
||||
if (secrets.includes(key)) {
|
||||
await post(`/services/${service.id}/secrets`, {
|
||||
name: key,
|
||||
value: value,
|
||||
isNew: true
|
||||
value,
|
||||
});
|
||||
} else {
|
||||
service.serviceSetting = service.serviceSetting.map((setting: any) => {
|
||||
if (setting.name === key) {
|
||||
setting.changed = true;
|
||||
setting.value = value;
|
||||
}
|
||||
return setting;
|
||||
});
|
||||
if (!settings.includes(key) && !baseCoolifySetting.includes(key)) {
|
||||
service.serviceSetting.push({
|
||||
id: service.id,
|
||||
name: key,
|
||||
value: value,
|
||||
isNew: true
|
||||
});
|
||||
}
|
||||
if (baseCoolifySetting.includes(key)) {
|
||||
service[key] = value;
|
||||
}
|
||||
}
|
||||
if (baseCoolifySetting.includes(key)) {
|
||||
service[key] = value;
|
||||
}
|
||||
|
||||
}
|
||||
await post(`/services/${service.id}`, { ...service });
|
||||
const { service: reloadedService } = await get(`/services/${service.id}`);
|
||||
|
||||
Reference in new issue
Block a user