mirror of
https://github.com/ershisan99/coolify.git
synced 2025-12-25 20:49:28 +00:00
Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0b416cd03e | ||
|
|
857e0f251b | ||
|
|
f040c7c742 | ||
|
|
2e82c9d312 | ||
|
|
126923c33e | ||
|
|
26528d8bec | ||
|
|
f99da111f7 | ||
|
|
8c30472472 | ||
|
|
11131ebe06 | ||
|
|
8dd80589d6 | ||
|
|
51e27146f3 | ||
|
|
70717dcbe5 | ||
|
|
51cba32d8d | ||
|
|
b9076714cf | ||
|
|
b76caabd32 | ||
|
|
0922fd66a4 | ||
|
|
4e7e9b2cfc | ||
|
|
0c24134ac2 | ||
|
|
f96e418dd6 | ||
|
|
1627415cca | ||
|
|
d047c91399 | ||
|
|
8bec5550cf | ||
|
|
2962aa6166 | ||
|
|
d80f760c92 | ||
|
|
ce2c887469 | ||
|
|
4908463722 | ||
|
|
26d0ef9ac9 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,5 +1,6 @@
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
node_modules
|
node_modules
|
||||||
|
.pnpm-store
|
||||||
build
|
build
|
||||||
.svelte-kit
|
.svelte-kit
|
||||||
package
|
package
|
||||||
|
|||||||
4
.gitpod.Dockerfile
vendored
4
.gitpod.Dockerfile
vendored
@@ -1,2 +1,2 @@
|
|||||||
FROM gitpod/workspace-node:2022-06-20-19-54-55
|
FROM gitpod/workspace-full:2022-08-17-18-37-55
|
||||||
RUN (curl -sSL "https://github.com/buildpacks/pack/releases/download/v0.27.0/pack-v0.27.0-linux.tgz" | tar -C /usr/local/bin/ --no-same-owner -xzv pack)
|
RUN brew install buildpacks/tap/pack
|
||||||
10
.gitpod.yml
10
.gitpod.yml
@@ -1,11 +1,11 @@
|
|||||||
# This configuration file was automatically generated by Gitpod.
|
# This configuration file was automatically generated by Gitpod.
|
||||||
# Please adjust to your needs (see https://www.gitpod.io/docs/config-gitpod-file)
|
# Please adjust to your needs (see https://www.gitpod.io/docs/config-gitpod-file)
|
||||||
# and commit this file to your remote git repository to share the goodness with others.
|
# and commit this file to your remote git repository to share the goodness with others.
|
||||||
image:
|
#image:
|
||||||
file: .gitpod.Dockerfile
|
# file: .gitpod.Dockerfile
|
||||||
tasks:
|
#tasks:
|
||||||
- init: pnpm install && pnpm db:push && pnpm db:seed
|
# - init: pnpm install && pnpm db:push && pnpm db:seed
|
||||||
command: pnpm dev
|
# command: pnpm dev
|
||||||
|
|
||||||
ports:
|
ports:
|
||||||
- port: 3001
|
- port: 3001
|
||||||
|
|||||||
@@ -92,6 +92,7 @@ Deploy your resource to:
|
|||||||
- [Umami](https://github.com/mikecao/umami)
|
- [Umami](https://github.com/mikecao/umami)
|
||||||
- [Fider](https://fider.io)
|
- [Fider](https://fider.io)
|
||||||
- [Hasura](https://hasura.io)
|
- [Hasura](https://hasura.io)
|
||||||
|
- [GlitchTip](https://glitchtip.com)
|
||||||
|
|
||||||
## Migration from v1
|
## Migration from v1
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "GlitchTip" (
|
||||||
|
"id" TEXT NOT NULL PRIMARY KEY,
|
||||||
|
"postgresqlUser" TEXT NOT NULL,
|
||||||
|
"postgresqlPassword" TEXT NOT NULL,
|
||||||
|
"postgresqlDatabase" TEXT NOT NULL,
|
||||||
|
"postgresqlPublicPort" INTEGER,
|
||||||
|
"secretKeyBase" TEXT,
|
||||||
|
"defaultEmail" TEXT NOT NULL,
|
||||||
|
"defaultUsername" TEXT NOT NULL,
|
||||||
|
"defaultPassword" TEXT NOT NULL,
|
||||||
|
"defaultEmailFrom" TEXT NOT NULL DEFAULT 'glitchtip@domain.tdl',
|
||||||
|
"emailSmtpHost" TEXT DEFAULT 'domain.tdl',
|
||||||
|
"emailSmtpPort" INTEGER DEFAULT 25,
|
||||||
|
"emailSmtpUser" TEXT,
|
||||||
|
"emailSmtpPassword" TEXT,
|
||||||
|
"emailSmtpUseTls" BOOLEAN DEFAULT false,
|
||||||
|
"emailSmtpUseSsl" BOOLEAN DEFAULT false,
|
||||||
|
"emailBackend" TEXT,
|
||||||
|
"mailgunApiKey" TEXT,
|
||||||
|
"sendgridApiKey" TEXT,
|
||||||
|
"enableOpenUserRegistration" BOOLEAN NOT NULL DEFAULT true,
|
||||||
|
"serviceId" TEXT NOT NULL,
|
||||||
|
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" DATETIME NOT NULL,
|
||||||
|
CONSTRAINT "GlitchTip_serviceId_fkey" FOREIGN KEY ("serviceId") REFERENCES "Service" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "GlitchTip_serviceId_key" ON "GlitchTip"("serviceId");
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
-- RedefineTables
|
||||||
|
PRAGMA foreign_keys=OFF;
|
||||||
|
CREATE TABLE "new_GitSource" (
|
||||||
|
"id" TEXT NOT NULL PRIMARY KEY,
|
||||||
|
"name" TEXT NOT NULL,
|
||||||
|
"forPublic" BOOLEAN NOT NULL DEFAULT false,
|
||||||
|
"type" TEXT,
|
||||||
|
"apiUrl" TEXT,
|
||||||
|
"htmlUrl" TEXT,
|
||||||
|
"customPort" INTEGER NOT NULL DEFAULT 22,
|
||||||
|
"organization" TEXT,
|
||||||
|
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" DATETIME NOT NULL,
|
||||||
|
"githubAppId" TEXT,
|
||||||
|
"gitlabAppId" TEXT,
|
||||||
|
CONSTRAINT "GitSource_githubAppId_fkey" FOREIGN KEY ("githubAppId") REFERENCES "GithubApp" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
|
||||||
|
CONSTRAINT "GitSource_gitlabAppId_fkey" FOREIGN KEY ("gitlabAppId") REFERENCES "GitlabApp" ("id") ON DELETE SET NULL ON UPDATE CASCADE
|
||||||
|
);
|
||||||
|
INSERT INTO "new_GitSource" ("apiUrl", "createdAt", "customPort", "githubAppId", "gitlabAppId", "htmlUrl", "id", "name", "organization", "type", "updatedAt") SELECT "apiUrl", "createdAt", "customPort", "githubAppId", "gitlabAppId", "htmlUrl", "id", "name", "organization", "type", "updatedAt" FROM "GitSource";
|
||||||
|
DROP TABLE "GitSource";
|
||||||
|
ALTER TABLE "new_GitSource" RENAME TO "GitSource";
|
||||||
|
CREATE UNIQUE INDEX "GitSource_githubAppId_key" ON "GitSource"("githubAppId");
|
||||||
|
CREATE UNIQUE INDEX "GitSource_gitlabAppId_key" ON "GitSource"("gitlabAppId");
|
||||||
|
CREATE TABLE "new_ApplicationSettings" (
|
||||||
|
"id" TEXT NOT NULL PRIMARY KEY,
|
||||||
|
"applicationId" TEXT NOT NULL,
|
||||||
|
"dualCerts" BOOLEAN NOT NULL DEFAULT false,
|
||||||
|
"debug" BOOLEAN NOT NULL DEFAULT false,
|
||||||
|
"previews" BOOLEAN NOT NULL DEFAULT false,
|
||||||
|
"autodeploy" BOOLEAN NOT NULL DEFAULT true,
|
||||||
|
"isBot" BOOLEAN NOT NULL DEFAULT false,
|
||||||
|
"isPublicRepository" BOOLEAN NOT NULL DEFAULT false,
|
||||||
|
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" DATETIME NOT NULL,
|
||||||
|
CONSTRAINT "ApplicationSettings_applicationId_fkey" FOREIGN KEY ("applicationId") REFERENCES "Application" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
|
||||||
|
);
|
||||||
|
INSERT INTO "new_ApplicationSettings" ("applicationId", "autodeploy", "createdAt", "debug", "dualCerts", "id", "isBot", "previews", "updatedAt") SELECT "applicationId", "autodeploy", "createdAt", "debug", "dualCerts", "id", "isBot", "previews", "updatedAt" FROM "ApplicationSettings";
|
||||||
|
DROP TABLE "ApplicationSettings";
|
||||||
|
ALTER TABLE "new_ApplicationSettings" RENAME TO "ApplicationSettings";
|
||||||
|
CREATE UNIQUE INDEX "ApplicationSettings_applicationId_key" ON "ApplicationSettings"("applicationId");
|
||||||
|
PRAGMA foreign_key_check;
|
||||||
|
PRAGMA foreign_keys=ON;
|
||||||
@@ -119,16 +119,17 @@ model Application {
|
|||||||
}
|
}
|
||||||
|
|
||||||
model ApplicationSettings {
|
model ApplicationSettings {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
applicationId String @unique
|
applicationId String @unique
|
||||||
dualCerts Boolean @default(false)
|
dualCerts Boolean @default(false)
|
||||||
debug Boolean @default(false)
|
debug Boolean @default(false)
|
||||||
previews Boolean @default(false)
|
previews Boolean @default(false)
|
||||||
autodeploy Boolean @default(true)
|
autodeploy Boolean @default(true)
|
||||||
isBot Boolean @default(false)
|
isBot Boolean @default(false)
|
||||||
createdAt DateTime @default(now())
|
isPublicRepository Boolean @default(false)
|
||||||
updatedAt DateTime @updatedAt
|
createdAt DateTime @default(now())
|
||||||
application Application @relation(fields: [applicationId], references: [id])
|
updatedAt DateTime @updatedAt
|
||||||
|
application Application @relation(fields: [applicationId], references: [id])
|
||||||
}
|
}
|
||||||
|
|
||||||
model ApplicationPersistentStorage {
|
model ApplicationPersistentStorage {
|
||||||
@@ -238,6 +239,7 @@ model SshKey {
|
|||||||
model GitSource {
|
model GitSource {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
name String
|
name String
|
||||||
|
forPublic Boolean @default(false)
|
||||||
type String?
|
type String?
|
||||||
apiUrl String?
|
apiUrl String?
|
||||||
htmlUrl String?
|
htmlUrl String?
|
||||||
@@ -314,31 +316,32 @@ model DatabaseSettings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
model Service {
|
model Service {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
name String
|
name String
|
||||||
fqdn String?
|
fqdn String?
|
||||||
exposePort Int?
|
exposePort Int?
|
||||||
dualCerts Boolean @default(false)
|
dualCerts Boolean @default(false)
|
||||||
type String?
|
type String?
|
||||||
version String?
|
version String?
|
||||||
destinationDockerId String?
|
destinationDockerId String?
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
destinationDocker DestinationDocker? @relation(fields: [destinationDockerId], references: [id])
|
destinationDocker DestinationDocker? @relation(fields: [destinationDockerId], references: [id])
|
||||||
|
|
||||||
fider Fider?
|
fider Fider?
|
||||||
ghost Ghost?
|
ghost Ghost?
|
||||||
hasura Hasura?
|
glitchTip GlitchTip?
|
||||||
meiliSearch MeiliSearch?
|
hasura Hasura?
|
||||||
minio Minio?
|
meiliSearch MeiliSearch?
|
||||||
moodle Moodle?
|
minio Minio?
|
||||||
plausibleAnalytics PlausibleAnalytics?
|
moodle Moodle?
|
||||||
persistentStorage ServicePersistentStorage[]
|
plausibleAnalytics PlausibleAnalytics?
|
||||||
serviceSecret ServiceSecret[]
|
persistentStorage ServicePersistentStorage[]
|
||||||
umami Umami?
|
serviceSecret ServiceSecret[]
|
||||||
vscodeserver Vscodeserver?
|
umami Umami?
|
||||||
wordpress Wordpress?
|
vscodeserver Vscodeserver?
|
||||||
appwrite Appwrite?
|
wordpress Wordpress?
|
||||||
|
appwrite Appwrite?
|
||||||
|
|
||||||
teams Team[]
|
teams Team[]
|
||||||
}
|
}
|
||||||
@@ -515,3 +518,30 @@ model Appwrite {
|
|||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
service Service @relation(fields: [serviceId], references: [id])
|
service Service @relation(fields: [serviceId], references: [id])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
model GlitchTip {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
postgresqlUser String
|
||||||
|
postgresqlPassword String
|
||||||
|
postgresqlDatabase String
|
||||||
|
postgresqlPublicPort Int?
|
||||||
|
secretKeyBase String?
|
||||||
|
defaultEmail String
|
||||||
|
defaultUsername String
|
||||||
|
defaultPassword String
|
||||||
|
defaultEmailFrom String @default("glitchtip@domain.tdl")
|
||||||
|
emailSmtpHost String? @default("domain.tdl")
|
||||||
|
emailSmtpPort Int? @default(25)
|
||||||
|
emailSmtpUser String?
|
||||||
|
emailSmtpPassword String?
|
||||||
|
emailSmtpUseTls Boolean? @default(false)
|
||||||
|
emailSmtpUseSsl Boolean? @default(false)
|
||||||
|
emailBackend String?
|
||||||
|
mailgunApiKey String?
|
||||||
|
sendgridApiKey String?
|
||||||
|
enableOpenUserRegistration Boolean @default(true)
|
||||||
|
serviceId String @unique
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @updatedAt
|
||||||
|
service Service @relation(fields: [serviceId], references: [id])
|
||||||
|
}
|
||||||
|
|||||||
@@ -66,6 +66,34 @@ async function main() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
const github = await prisma.gitSource.findFirst({
|
||||||
|
where: { htmlUrl: 'https://github.com', forPublic: true }
|
||||||
|
});
|
||||||
|
const gitlab = await prisma.gitSource.findFirst({
|
||||||
|
where: { htmlUrl: 'https://gitlab.com', forPublic: true }
|
||||||
|
});
|
||||||
|
if (!github) {
|
||||||
|
await prisma.gitSource.create({
|
||||||
|
data: {
|
||||||
|
apiUrl: 'https://api.github.com',
|
||||||
|
htmlUrl: 'https://github.com',
|
||||||
|
forPublic: true,
|
||||||
|
name: 'Github Public',
|
||||||
|
type: 'github'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!gitlab) {
|
||||||
|
await prisma.gitSource.create({
|
||||||
|
data: {
|
||||||
|
apiUrl: 'https://gitlab.com/api/v4',
|
||||||
|
htmlUrl: 'https://gitlab.com',
|
||||||
|
forPublic: true,
|
||||||
|
name: 'Gitlab Public',
|
||||||
|
type: 'gitlab'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
main()
|
main()
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import fs from 'fs/promises';
|
|||||||
import yaml from 'js-yaml';
|
import yaml from 'js-yaml';
|
||||||
|
|
||||||
import { copyBaseConfigurationFiles, makeLabelForStandaloneApplication, saveBuildLog, setDefaultConfiguration } from '../lib/buildPacks/common';
|
import { copyBaseConfigurationFiles, makeLabelForStandaloneApplication, saveBuildLog, setDefaultConfiguration } from '../lib/buildPacks/common';
|
||||||
import { createDirectories, decrypt, executeDockerCmd, getDomain, prisma } from '../lib/common';
|
import { createDirectories, decrypt, defaultComposeConfiguration, executeDockerCmd, getDomain, prisma } from '../lib/common';
|
||||||
import * as importers from '../lib/importers';
|
import * as importers from '../lib/importers';
|
||||||
import * as buildpacks from '../lib/buildPacks';
|
import * as buildpacks from '../lib/buildPacks';
|
||||||
|
|
||||||
@@ -56,6 +56,7 @@ import * as buildpacks from '../lib/buildPacks';
|
|||||||
baseImage,
|
baseImage,
|
||||||
baseBuildImage,
|
baseBuildImage,
|
||||||
deploymentType,
|
deploymentType,
|
||||||
|
forceRebuild
|
||||||
} = message
|
} = message
|
||||||
let {
|
let {
|
||||||
branch,
|
branch,
|
||||||
@@ -69,6 +70,30 @@ import * as buildpacks from '../lib/buildPacks';
|
|||||||
dockerFileLocation,
|
dockerFileLocation,
|
||||||
denoMainFile
|
denoMainFile
|
||||||
} = message
|
} = message
|
||||||
|
const currentHash = crypto
|
||||||
|
.createHash('sha256')
|
||||||
|
.update(
|
||||||
|
JSON.stringify({
|
||||||
|
pythonWSGI,
|
||||||
|
pythonModule,
|
||||||
|
pythonVariable,
|
||||||
|
deploymentType,
|
||||||
|
denoOptions,
|
||||||
|
baseImage,
|
||||||
|
baseBuildImage,
|
||||||
|
buildPack,
|
||||||
|
port,
|
||||||
|
exposePort,
|
||||||
|
installCommand,
|
||||||
|
buildCommand,
|
||||||
|
startCommand,
|
||||||
|
secrets,
|
||||||
|
branch,
|
||||||
|
repository,
|
||||||
|
fqdn
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.digest('hex');
|
||||||
try {
|
try {
|
||||||
const { debug } = settings;
|
const { debug } = settings;
|
||||||
if (concurrency === 1) {
|
if (concurrency === 1) {
|
||||||
@@ -131,7 +156,8 @@ import * as buildpacks from '../lib/buildPacks';
|
|||||||
htmlUrl: gitSource.htmlUrl,
|
htmlUrl: gitSource.htmlUrl,
|
||||||
projectId,
|
projectId,
|
||||||
deployKeyId: gitSource.gitlabApp?.deployKeyId || null,
|
deployKeyId: gitSource.gitlabApp?.deployKeyId || null,
|
||||||
privateSshKey: decrypt(gitSource.gitlabApp?.privateSshKey) || null
|
privateSshKey: decrypt(gitSource.gitlabApp?.privateSshKey) || null,
|
||||||
|
forPublic: gitSource.forPublic
|
||||||
});
|
});
|
||||||
if (!commit) {
|
if (!commit) {
|
||||||
throw new Error('No commit found?');
|
throw new Error('No commit found?');
|
||||||
@@ -146,38 +172,10 @@ import * as buildpacks from '../lib/buildPacks';
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pullmergeRequestId) {
|
if (!pullmergeRequestId) {
|
||||||
const currentHash = crypto
|
|
||||||
//@ts-ignore
|
|
||||||
.createHash('sha256')
|
|
||||||
.update(
|
|
||||||
JSON.stringify({
|
|
||||||
pythonWSGI,
|
|
||||||
pythonModule,
|
|
||||||
pythonVariable,
|
|
||||||
deploymentType,
|
|
||||||
denoOptions,
|
|
||||||
baseImage,
|
|
||||||
baseBuildImage,
|
|
||||||
buildPack,
|
|
||||||
port,
|
|
||||||
exposePort,
|
|
||||||
installCommand,
|
|
||||||
buildCommand,
|
|
||||||
startCommand,
|
|
||||||
secrets,
|
|
||||||
branch,
|
|
||||||
repository,
|
|
||||||
fqdn
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.digest('hex');
|
|
||||||
|
|
||||||
if (configHash !== currentHash) {
|
if (configHash !== currentHash) {
|
||||||
await prisma.application.update({
|
|
||||||
where: { id: applicationId },
|
|
||||||
data: { configHash: currentHash }
|
|
||||||
});
|
|
||||||
deployNeeded = true;
|
deployNeeded = true;
|
||||||
if (configHash) {
|
if (configHash) {
|
||||||
await saveBuildLog({ line: 'Configuration changed.', buildId, applicationId });
|
await saveBuildLog({ line: 'Configuration changed.', buildId, applicationId });
|
||||||
@@ -200,8 +198,10 @@ import * as buildpacks from '../lib/buildPacks';
|
|||||||
//
|
//
|
||||||
}
|
}
|
||||||
await copyBaseConfigurationFiles(buildPack, workdir, buildId, applicationId, baseImage);
|
await copyBaseConfigurationFiles(buildPack, workdir, buildId, applicationId, baseImage);
|
||||||
|
|
||||||
|
if (forceRebuild) deployNeeded = true
|
||||||
if (!imageFound || deployNeeded) {
|
if (!imageFound || deployNeeded) {
|
||||||
// if (true) {
|
// if (true) {
|
||||||
if (buildpacks[buildPack])
|
if (buildpacks[buildPack])
|
||||||
await buildpacks[buildPack]({
|
await buildpacks[buildPack]({
|
||||||
dockerId: destinationDocker.id,
|
dockerId: destinationDocker.id,
|
||||||
@@ -250,7 +250,9 @@ import * as buildpacks from '../lib/buildPacks';
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
const envs = [];
|
const envs = [
|
||||||
|
`PORT=${port}`
|
||||||
|
];
|
||||||
if (secrets.length > 0) {
|
if (secrets.length > 0) {
|
||||||
secrets.forEach((secret) => {
|
secrets.forEach((secret) => {
|
||||||
if (pullmergeRequestId) {
|
if (pullmergeRequestId) {
|
||||||
@@ -306,23 +308,14 @@ import * as buildpacks from '../lib/buildPacks';
|
|||||||
container_name: imageId,
|
container_name: imageId,
|
||||||
volumes,
|
volumes,
|
||||||
env_file: envFound ? [`${workdir}/.env`] : [],
|
env_file: envFound ? [`${workdir}/.env`] : [],
|
||||||
networks: [destinationDocker.network],
|
|
||||||
labels,
|
labels,
|
||||||
depends_on: [],
|
depends_on: [],
|
||||||
restart: 'always',
|
|
||||||
expose: [port],
|
expose: [port],
|
||||||
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
||||||
// logging: {
|
// logging: {
|
||||||
// driver: 'fluentd',
|
// driver: 'fluentd',
|
||||||
// },
|
// },
|
||||||
deploy: {
|
...defaultComposeConfiguration(destinationDocker.network),
|
||||||
restart_policy: {
|
|
||||||
condition: 'on-failure',
|
|
||||||
delay: '5s',
|
|
||||||
max_attempts: 3,
|
|
||||||
window: '120s'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
networks: {
|
networks: {
|
||||||
@@ -345,6 +338,10 @@ import * as buildpacks from '../lib/buildPacks';
|
|||||||
}
|
}
|
||||||
await saveBuildLog({ line: 'Proxy will be updated shortly.', buildId, applicationId });
|
await saveBuildLog({ line: 'Proxy will be updated shortly.', buildId, applicationId });
|
||||||
await prisma.build.update({ where: { id: message.build_id }, data: { status: 'success' } });
|
await prisma.build.update({ where: { id: message.build_id }, data: { status: 'success' } });
|
||||||
|
if (!pullmergeRequestId) await prisma.application.update({
|
||||||
|
where: { id: applicationId },
|
||||||
|
data: { configHash: currentHash }
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import { checkContainer, removeContainer } from './docker';
|
|||||||
import { day } from './dayjs';
|
import { day } from './dayjs';
|
||||||
import * as serviceFields from './serviceFields'
|
import * as serviceFields from './serviceFields'
|
||||||
|
|
||||||
export const version = '3.5.1';
|
export const version = '3.7.0';
|
||||||
export const isDev = process.env.NODE_ENV === 'development';
|
export const isDev = process.env.NODE_ENV === 'development';
|
||||||
|
|
||||||
const algorithm = 'aes-256-ctr';
|
const algorithm = 'aes-256-ctr';
|
||||||
@@ -79,7 +79,8 @@ export const include: any = {
|
|||||||
hasura: true,
|
hasura: true,
|
||||||
fider: true,
|
fider: true,
|
||||||
moodle: true,
|
moodle: true,
|
||||||
appwrite: true
|
appwrite: true,
|
||||||
|
glitchTip: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const uniqueName = (): string => uniqueNamesGenerator(customConfig);
|
export const uniqueName = (): string => uniqueNamesGenerator(customConfig);
|
||||||
@@ -287,7 +288,7 @@ export const supportedServiceTypesAndVersions = [
|
|||||||
ports: {
|
ports: {
|
||||||
main: 80
|
main: 80
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
// {
|
// {
|
||||||
// name: 'moodle',
|
// name: 'moodle',
|
||||||
// fancyName: 'Moodle',
|
// fancyName: 'Moodle',
|
||||||
@@ -299,6 +300,17 @@ export const supportedServiceTypesAndVersions = [
|
|||||||
// main: 8080
|
// main: 8080
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
{
|
||||||
|
name: 'glitchTip',
|
||||||
|
fancyName: 'GlitchTip',
|
||||||
|
baseImage: 'glitchtip/glitchtip',
|
||||||
|
images: ['postgres:14-alpine', 'redis:7-alpine'],
|
||||||
|
versions: ['latest'],
|
||||||
|
recommendedVersion: 'latest',
|
||||||
|
ports: {
|
||||||
|
main: 8000
|
||||||
|
}
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export async function checkDoubleBranch(branch: string, projectId: number): Promise<boolean> {
|
export async function checkDoubleBranch(branch: string, projectId: number): Promise<boolean> {
|
||||||
@@ -1176,6 +1188,25 @@ export async function updatePasswordInDb(database, user, newPassword, isRoot) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
export async function checkExposedPort({ id, configuredPort, exposePort, dockerId, remoteIpAddress }: { id: string, configuredPort?: number, exposePort: number, dockerId: string, remoteIpAddress?: string }) {
|
||||||
|
if (exposePort < 1024 || exposePort > 65535) {
|
||||||
|
throw { status: 500, message: `Exposed Port needs to be between 1024 and 65535.` }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configuredPort) {
|
||||||
|
if (configuredPort !== exposePort) {
|
||||||
|
const availablePort = await getFreeExposedPort(id, exposePort, dockerId, remoteIpAddress);
|
||||||
|
if (availablePort.toString() !== exposePort.toString()) {
|
||||||
|
throw { status: 500, message: `Port ${exposePort} is already in use.` }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const availablePort = await getFreeExposedPort(id, exposePort, dockerId, remoteIpAddress);
|
||||||
|
if (availablePort.toString() !== exposePort.toString()) {
|
||||||
|
throw { status: 500, message: `Port ${exposePort} is already in use.` }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
export async function getFreeExposedPort(id, exposePort, dockerId, remoteIpAddress) {
|
export async function getFreeExposedPort(id, exposePort, dockerId, remoteIpAddress) {
|
||||||
const { default: getPort } = await import('get-port');
|
const { default: getPort } = await import('get-port');
|
||||||
const applicationUsed = await (
|
const applicationUsed = await (
|
||||||
@@ -1588,7 +1619,33 @@ export async function configureServiceType({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else if (type === 'glitchTip') {
|
||||||
|
const defaultUsername = cuid();
|
||||||
|
const defaultEmail = `${defaultUsername}@example.com`;
|
||||||
|
const defaultPassword = encrypt(generatePassword());
|
||||||
|
const postgresqlUser = cuid();
|
||||||
|
const postgresqlPassword = encrypt(generatePassword());
|
||||||
|
const postgresqlDatabase = 'glitchTip';
|
||||||
|
const secretKeyBase = encrypt(generatePassword(64));
|
||||||
|
|
||||||
|
await prisma.service.update({
|
||||||
|
where: { id },
|
||||||
|
data: {
|
||||||
|
type,
|
||||||
|
glitchTip: {
|
||||||
|
create: {
|
||||||
|
postgresqlDatabase,
|
||||||
|
postgresqlUser,
|
||||||
|
postgresqlPassword,
|
||||||
|
secretKeyBase,
|
||||||
|
defaultEmail,
|
||||||
|
defaultUsername,
|
||||||
|
defaultPassword,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
await prisma.service.update({
|
await prisma.service.update({
|
||||||
where: { id },
|
where: { id },
|
||||||
data: {
|
data: {
|
||||||
@@ -1610,6 +1667,7 @@ export async function removeService({ id }: { id: string }): Promise<void> {
|
|||||||
await prisma.minio.deleteMany({ where: { serviceId: id } });
|
await prisma.minio.deleteMany({ where: { serviceId: id } });
|
||||||
await prisma.vscodeserver.deleteMany({ where: { serviceId: id } });
|
await prisma.vscodeserver.deleteMany({ where: { serviceId: id } });
|
||||||
await prisma.wordpress.deleteMany({ where: { serviceId: id } });
|
await prisma.wordpress.deleteMany({ where: { serviceId: id } });
|
||||||
|
await prisma.glitchTip.deleteMany({ where: { serviceId: id } });
|
||||||
await prisma.moodle.deleteMany({ where: { serviceId: id } });
|
await prisma.moodle.deleteMany({ where: { serviceId: id } });
|
||||||
await prisma.appwrite.deleteMany({ where: { serviceId: id } });
|
await prisma.appwrite.deleteMany({ where: { serviceId: id } });
|
||||||
await prisma.service.delete({ where: { id } });
|
await prisma.service.delete({ where: { id } });
|
||||||
@@ -1750,7 +1808,7 @@ export function convertTolOldVolumeNames(type) {
|
|||||||
// export async function getAvailableServices(): Promise<any> {
|
// export async function getAvailableServices(): Promise<any> {
|
||||||
// const { data } = await axios.get(`https://gist.githubusercontent.com/andrasbacsai/4aac36d8d6214dbfc34fa78110554a50/raw/5b27e6c37d78aaeedc1148d797112c827a2f43cf/availableServices.json`)
|
// const { data } = await axios.get(`https://gist.githubusercontent.com/andrasbacsai/4aac36d8d6214dbfc34fa78110554a50/raw/5b27e6c37d78aaeedc1148d797112c827a2f43cf/availableServices.json`)
|
||||||
// return data
|
// return data
|
||||||
//
|
//
|
||||||
export async function cleanupDockerStorage(dockerId, lowDiskSpace, force) {
|
export async function cleanupDockerStorage(dockerId, lowDiskSpace, force) {
|
||||||
// Cleanup old coolify images
|
// Cleanup old coolify images
|
||||||
try {
|
try {
|
||||||
@@ -1813,4 +1871,18 @@ export function persistentVolumes(id, persistentStorage, config) {
|
|||||||
...composeVolumes
|
...composeVolumes
|
||||||
) || {}
|
) || {}
|
||||||
return { volumes, volumeMounts }
|
return { volumes, volumeMounts }
|
||||||
}
|
}
|
||||||
|
export function defaultComposeConfiguration(network: string): any {
|
||||||
|
return {
|
||||||
|
networks: [network],
|
||||||
|
restart: 'on-failure',
|
||||||
|
deploy: {
|
||||||
|
restart_policy: {
|
||||||
|
condition: 'on-failure',
|
||||||
|
delay: '5s',
|
||||||
|
max_attempts: 10,
|
||||||
|
window: '120s'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -71,7 +71,6 @@ export async function removeContainer({
|
|||||||
}): Promise<void> {
|
}): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const { stdout } = await executeDockerCmd({ dockerId, command: `docker inspect --format '{{json .State}}' ${id}` })
|
const { stdout } = await executeDockerCmd({ dockerId, command: `docker inspect --format '{{json .State}}' ${id}` })
|
||||||
console.log(id)
|
|
||||||
if (JSON.parse(stdout).Running) {
|
if (JSON.parse(stdout).Running) {
|
||||||
await executeDockerCmd({ dockerId, command: `docker stop -t 0 ${id}` })
|
await executeDockerCmd({ dockerId, command: `docker stop -t 0 ${id}` })
|
||||||
await executeDockerCmd({ dockerId, command: `docker rm ${id}` })
|
await executeDockerCmd({ dockerId, command: `docker rm ${id}` })
|
||||||
|
|||||||
@@ -12,7 +12,8 @@ export default async function ({
|
|||||||
htmlUrl,
|
htmlUrl,
|
||||||
branch,
|
branch,
|
||||||
buildId,
|
buildId,
|
||||||
customPort
|
customPort,
|
||||||
|
forPublic
|
||||||
}: {
|
}: {
|
||||||
applicationId: string;
|
applicationId: string;
|
||||||
workdir: string;
|
workdir: string;
|
||||||
@@ -23,41 +24,55 @@ export default async function ({
|
|||||||
branch: string;
|
branch: string;
|
||||||
buildId: string;
|
buildId: string;
|
||||||
customPort: number;
|
customPort: number;
|
||||||
|
forPublic?: boolean;
|
||||||
}): Promise<string> {
|
}): Promise<string> {
|
||||||
const { default: got } = await import('got')
|
const { default: got } = await import('got')
|
||||||
const url = htmlUrl.replace('https://', '').replace('http://', '');
|
const url = htmlUrl.replace('https://', '').replace('http://', '');
|
||||||
await saveBuildLog({ line: 'GitHub importer started.', buildId, applicationId });
|
await saveBuildLog({ line: 'GitHub importer started.', buildId, applicationId });
|
||||||
|
if (forPublic) {
|
||||||
|
await saveBuildLog({
|
||||||
|
line: `Cloning ${repository}:${branch} branch.`,
|
||||||
|
buildId,
|
||||||
|
applicationId
|
||||||
|
});
|
||||||
|
await asyncExecShell(
|
||||||
|
`git clone -q -b ${branch} https://${url}/${repository}.git ${workdir}/ && cd ${workdir} && git submodule update --init --recursive && git lfs pull && cd .. `
|
||||||
|
);
|
||||||
|
|
||||||
const body = await prisma.githubApp.findUnique({ where: { id: githubAppId } });
|
} else {
|
||||||
if (body.privateKey) body.privateKey = decrypt(body.privateKey);
|
const body = await prisma.githubApp.findUnique({ where: { id: githubAppId } });
|
||||||
const { privateKey, appId, installationId } = body
|
if (body.privateKey) body.privateKey = decrypt(body.privateKey);
|
||||||
|
const { privateKey, appId, installationId } = body
|
||||||
|
const githubPrivateKey = privateKey.replace(/\\n/g, '\n').replace(/"/g, '');
|
||||||
|
|
||||||
const githubPrivateKey = privateKey.replace(/\\n/g, '\n').replace(/"/g, '');
|
const payload = {
|
||||||
|
iat: Math.round(new Date().getTime() / 1000),
|
||||||
const payload = {
|
exp: Math.round(new Date().getTime() / 1000 + 60),
|
||||||
iat: Math.round(new Date().getTime() / 1000),
|
iss: appId
|
||||||
exp: Math.round(new Date().getTime() / 1000 + 60),
|
};
|
||||||
iss: appId
|
const jwtToken = jsonwebtoken.sign(payload, githubPrivateKey, {
|
||||||
};
|
algorithm: 'RS256'
|
||||||
const jwtToken = jsonwebtoken.sign(payload, githubPrivateKey, {
|
});
|
||||||
algorithm: 'RS256'
|
const { token } = await got
|
||||||
});
|
.post(`${apiUrl}/app/installations/${installationId}/access_tokens`, {
|
||||||
const { token } = await got
|
headers: {
|
||||||
.post(`${apiUrl}/app/installations/${installationId}/access_tokens`, {
|
Authorization: `Bearer ${jwtToken}`,
|
||||||
headers: {
|
Accept: 'application/vnd.github.machine-man-preview+json'
|
||||||
Authorization: `Bearer ${jwtToken}`,
|
}
|
||||||
Accept: 'application/vnd.github.machine-man-preview+json'
|
})
|
||||||
}
|
.json();
|
||||||
})
|
await saveBuildLog({
|
||||||
.json();
|
line: `Cloning ${repository}:${branch} branch.`,
|
||||||
await saveBuildLog({
|
buildId,
|
||||||
line: `Cloning ${repository}:${branch} branch.`,
|
applicationId
|
||||||
buildId,
|
});
|
||||||
applicationId
|
await asyncExecShell(
|
||||||
});
|
`git clone -q -b ${branch} https://x-access-token:${token}@${url}/${repository}.git --config core.sshCommand="ssh -p ${customPort}" ${workdir}/ && cd ${workdir} && git submodule update --init --recursive && git lfs pull && cd .. `
|
||||||
await asyncExecShell(
|
);
|
||||||
`git clone -q -b ${branch} https://x-access-token:${token}@${url}/${repository}.git --config core.sshCommand="ssh -p ${customPort}" ${workdir}/ && cd ${workdir} && git submodule update --init --recursive && git lfs pull && cd .. `
|
}
|
||||||
);
|
|
||||||
const { stdout: commit } = await asyncExecShell(`cd ${workdir}/ && git rev-parse HEAD`);
|
const { stdout: commit } = await asyncExecShell(`cd ${workdir}/ && git rev-parse HEAD`);
|
||||||
|
|
||||||
return commit.replace('\n', '');
|
return commit.replace('\n', '');
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -557,4 +557,117 @@ export const appwrite = [{
|
|||||||
isNumber: false,
|
isNumber: false,
|
||||||
isBoolean: false,
|
isBoolean: false,
|
||||||
isEncrypted: false
|
isEncrypted: false
|
||||||
}]
|
}]
|
||||||
|
|
||||||
|
export const glitchTip = [{
|
||||||
|
name: 'postgresqlUser',
|
||||||
|
isEditable: false,
|
||||||
|
isLowerCase: false,
|
||||||
|
isNumber: false,
|
||||||
|
isBoolean: false,
|
||||||
|
isEncrypted: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'postgresqlPassword',
|
||||||
|
isEditable: false,
|
||||||
|
isLowerCase: false,
|
||||||
|
isNumber: false,
|
||||||
|
isBoolean: false,
|
||||||
|
isEncrypted: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'postgresqlDatabase',
|
||||||
|
isEditable: false,
|
||||||
|
isLowerCase: false,
|
||||||
|
isNumber: false,
|
||||||
|
isBoolean: false,
|
||||||
|
isEncrypted: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'postgresqlPublicPort',
|
||||||
|
isEditable: false,
|
||||||
|
isLowerCase: false,
|
||||||
|
isNumber: true,
|
||||||
|
isBoolean: false,
|
||||||
|
isEncrypted: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'secretKeyBase',
|
||||||
|
isEditable: false,
|
||||||
|
isLowerCase: false,
|
||||||
|
isNumber: false,
|
||||||
|
isBoolean: false,
|
||||||
|
isEncrypted: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'defaultEmail',
|
||||||
|
isEditable: false,
|
||||||
|
isLowerCase: false,
|
||||||
|
isNumber: false,
|
||||||
|
isBoolean: false,
|
||||||
|
isEncrypted: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'defaultUsername',
|
||||||
|
isEditable: false,
|
||||||
|
isLowerCase: false,
|
||||||
|
isNumber: false,
|
||||||
|
isBoolean: false,
|
||||||
|
isEncrypted: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'defaultPassword',
|
||||||
|
isEditable: false,
|
||||||
|
isLowerCase: false,
|
||||||
|
isNumber: false,
|
||||||
|
isBoolean: false,
|
||||||
|
isEncrypted: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'defaultFromEmail',
|
||||||
|
isEditable: true,
|
||||||
|
isLowerCase: false,
|
||||||
|
isNumber: false,
|
||||||
|
isBoolean: false,
|
||||||
|
isEncrypted: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'emailUrl',
|
||||||
|
isEditable: true,
|
||||||
|
isLowerCase: false,
|
||||||
|
isNumber: false,
|
||||||
|
isBoolean: false,
|
||||||
|
isEncrypted: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'emailBackend',
|
||||||
|
isEditable: true,
|
||||||
|
isLowerCase: false,
|
||||||
|
isNumber: false,
|
||||||
|
isBoolean: false,
|
||||||
|
isEncrypted: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'mailgunApiKey',
|
||||||
|
isEditable: true,
|
||||||
|
isLowerCase: false,
|
||||||
|
isNumber: false,
|
||||||
|
isBoolean: false,
|
||||||
|
isEncrypted: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'sendgridApiKey',
|
||||||
|
isEditable: true,
|
||||||
|
isLowerCase: false,
|
||||||
|
isNumber: false,
|
||||||
|
isBoolean: false,
|
||||||
|
isEncrypted: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'enableOpenUserRegistration',
|
||||||
|
isEditable: true,
|
||||||
|
isLowerCase: false,
|
||||||
|
isNumber: false,
|
||||||
|
isBoolean: true,
|
||||||
|
isEncrypted: false
|
||||||
|
}]
|
||||||
|
|||||||
@@ -17,19 +17,4 @@ export async function defaultServiceConfigurations({ id, teamId }) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
return { ...service, network, port, workdir, image, secrets }
|
return { ...service, network, port, workdir, image, secrets }
|
||||||
}
|
|
||||||
|
|
||||||
export function defaultServiceComposeConfiguration(network: string): any {
|
|
||||||
return {
|
|
||||||
networks: [network],
|
|
||||||
restart: 'always',
|
|
||||||
deploy: {
|
|
||||||
restart_policy: {
|
|
||||||
condition: 'on-failure',
|
|
||||||
delay: '10s',
|
|
||||||
max_attempts: 10,
|
|
||||||
window: '120s'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -5,7 +5,7 @@ import axios from 'axios';
|
|||||||
import { FastifyReply } from 'fastify';
|
import { FastifyReply } from 'fastify';
|
||||||
import { day } from '../../../../lib/dayjs';
|
import { day } from '../../../../lib/dayjs';
|
||||||
import { setDefaultBaseImage, setDefaultConfiguration } from '../../../../lib/buildPacks/common';
|
import { setDefaultBaseImage, setDefaultConfiguration } from '../../../../lib/buildPacks/common';
|
||||||
import { checkDomainsIsValidInDNS, checkDoubleBranch, decrypt, encrypt, errorHandler, executeDockerCmd, generateSshKeyPair, getContainerUsage, getDomain, getFreeExposedPort, isDev, isDomainConfigured, listSettings, prisma, stopBuild, uniqueName } from '../../../../lib/common';
|
import { checkDomainsIsValidInDNS, checkDoubleBranch, checkExposedPort, decrypt, encrypt, errorHandler, executeDockerCmd, generateSshKeyPair, getContainerUsage, getDomain, getFreeExposedPort, isDev, isDomainConfigured, listSettings, prisma, stopBuild, uniqueName } from '../../../../lib/common';
|
||||||
import { checkContainer, formatLabelsOnDocker, isContainerExited, removeContainer } from '../../../../lib/docker';
|
import { checkContainer, formatLabelsOnDocker, isContainerExited, removeContainer } from '../../../../lib/docker';
|
||||||
import { scheduler } from '../../../../lib/scheduler';
|
import { scheduler } from '../../../../lib/scheduler';
|
||||||
|
|
||||||
@@ -238,6 +238,9 @@ export async function saveApplication(request: FastifyRequest<SaveApplication>,
|
|||||||
if (exposePort) {
|
if (exposePort) {
|
||||||
exposePort = Number(exposePort);
|
exposePort = Number(exposePort);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { destinationDockerId } = await prisma.application.findUnique({ where: { id } })
|
||||||
|
if (exposePort) await checkExposedPort({ id, exposePort, dockerId: destinationDockerId })
|
||||||
if (denoOptions) denoOptions = denoOptions.trim();
|
if (denoOptions) denoOptions = denoOptions.trim();
|
||||||
const defaultConfiguration = await setDefaultConfiguration({
|
const defaultConfiguration = await setDefaultConfiguration({
|
||||||
buildPack,
|
buildPack,
|
||||||
@@ -392,18 +395,7 @@ export async function checkDNS(request: FastifyRequest<CheckDNS>) {
|
|||||||
if (found) {
|
if (found) {
|
||||||
throw { status: 500, message: `Domain ${getDomain(fqdn).replace('www.', '')} is already in use!` }
|
throw { status: 500, message: `Domain ${getDomain(fqdn).replace('www.', '')} is already in use!` }
|
||||||
}
|
}
|
||||||
if (exposePort) {
|
if (exposePort) await checkExposedPort({ id, configuredPort, exposePort, dockerId, remoteIpAddress })
|
||||||
if (exposePort < 1024 || exposePort > 65535) {
|
|
||||||
throw { status: 500, message: `Exposed Port needs to be between 1024 and 65535.` }
|
|
||||||
}
|
|
||||||
|
|
||||||
if (configuredPort !== exposePort) {
|
|
||||||
const availablePort = await getFreeExposedPort(id, exposePort, dockerId, remoteIpAddress);
|
|
||||||
if (availablePort.toString() !== exposePort.toString()) {
|
|
||||||
throw { status: 500, message: `Port ${exposePort} is already in use.` }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (isDNSCheckEnabled && !isDev && !forceSave) {
|
if (isDNSCheckEnabled && !isDev && !forceSave) {
|
||||||
let hostname = request.hostname.split(':')[0];
|
let hostname = request.hostname.split(':')[0];
|
||||||
if (remoteEngine) hostname = remoteIpAddress;
|
if (remoteEngine) hostname = remoteIpAddress;
|
||||||
@@ -436,7 +428,7 @@ export async function deployApplication(request: FastifyRequest<DeployApplicatio
|
|||||||
try {
|
try {
|
||||||
const { id } = request.params
|
const { id } = request.params
|
||||||
const teamId = request.user?.teamId;
|
const teamId = request.user?.teamId;
|
||||||
const { pullmergeRequestId = null, branch } = request.body
|
const { pullmergeRequestId = null, branch, forceRebuild } = request.body
|
||||||
const buildId = cuid();
|
const buildId = cuid();
|
||||||
const application = await getApplicationFromDB(id, teamId);
|
const application = await getApplicationFromDB(id, teamId);
|
||||||
if (application) {
|
if (application) {
|
||||||
@@ -475,13 +467,15 @@ export async function deployApplication(request: FastifyRequest<DeployApplicatio
|
|||||||
type: 'manual',
|
type: 'manual',
|
||||||
...application,
|
...application,
|
||||||
sourceBranch: branch,
|
sourceBranch: branch,
|
||||||
pullmergeRequestId
|
pullmergeRequestId,
|
||||||
|
forceRebuild
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
scheduler.workers.get('deployApplication').postMessage({
|
scheduler.workers.get('deployApplication').postMessage({
|
||||||
build_id: buildId,
|
build_id: buildId,
|
||||||
type: 'manual',
|
type: 'manual',
|
||||||
...application
|
...application,
|
||||||
|
forceRebuild
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -499,11 +493,20 @@ export async function deployApplication(request: FastifyRequest<DeployApplicatio
|
|||||||
export async function saveApplicationSource(request: FastifyRequest<SaveApplicationSource>, reply: FastifyReply) {
|
export async function saveApplicationSource(request: FastifyRequest<SaveApplicationSource>, reply: FastifyReply) {
|
||||||
try {
|
try {
|
||||||
const { id } = request.params
|
const { id } = request.params
|
||||||
const { gitSourceId } = request.body
|
const { gitSourceId, forPublic, type } = request.body
|
||||||
await prisma.application.update({
|
if (forPublic) {
|
||||||
where: { id },
|
const publicGit = await prisma.gitSource.findFirst({ where: { type, forPublic } });
|
||||||
data: { gitSource: { connect: { id: gitSourceId } } }
|
await prisma.application.update({
|
||||||
});
|
where: { id },
|
||||||
|
data: { gitSource: { connect: { id: publicGit.id } } }
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await prisma.application.update({
|
||||||
|
where: { id },
|
||||||
|
data: { gitSource: { connect: { id: gitSourceId } } }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return reply.code(201).send()
|
return reply.code(201).send()
|
||||||
} catch ({ status, message }) {
|
} catch ({ status, message }) {
|
||||||
return errorHandler({ status, message })
|
return errorHandler({ status, message })
|
||||||
@@ -557,7 +560,7 @@ export async function checkRepository(request: FastifyRequest<CheckRepository>)
|
|||||||
export async function saveRepository(request, reply) {
|
export async function saveRepository(request, reply) {
|
||||||
try {
|
try {
|
||||||
const { id } = request.params
|
const { id } = request.params
|
||||||
let { repository, branch, projectId, autodeploy, webhookToken } = request.body
|
let { repository, branch, projectId, autodeploy, webhookToken, isPublicRepository = false } = request.body
|
||||||
|
|
||||||
repository = repository.toLowerCase();
|
repository = repository.toLowerCase();
|
||||||
branch = branch.toLowerCase();
|
branch = branch.toLowerCase();
|
||||||
@@ -565,17 +568,19 @@ export async function saveRepository(request, reply) {
|
|||||||
if (webhookToken) {
|
if (webhookToken) {
|
||||||
await prisma.application.update({
|
await prisma.application.update({
|
||||||
where: { id },
|
where: { id },
|
||||||
data: { repository, branch, projectId, gitSource: { update: { gitlabApp: { update: { webhookToken: webhookToken ? webhookToken : undefined } } } }, settings: { update: { autodeploy } } }
|
data: { repository, branch, projectId, gitSource: { update: { gitlabApp: { update: { webhookToken: webhookToken ? webhookToken : undefined } } } }, settings: { update: { autodeploy, isPublicRepository } } }
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
await prisma.application.update({
|
await prisma.application.update({
|
||||||
where: { id },
|
where: { id },
|
||||||
data: { repository, branch, projectId, settings: { update: { autodeploy } } }
|
data: { repository, branch, projectId, settings: { update: { autodeploy, isPublicRepository } } }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const isDouble = await checkDoubleBranch(branch, projectId);
|
if (!isPublicRepository) {
|
||||||
if (isDouble) {
|
const isDouble = await checkDoubleBranch(branch, projectId);
|
||||||
await prisma.applicationSettings.updateMany({ where: { application: { branch, projectId } }, data: { autodeploy: false } })
|
if (isDouble) {
|
||||||
|
await prisma.applicationSettings.updateMany({ where: { application: { branch, projectId } }, data: { autodeploy: false, isPublicRepository } })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return reply.code(201).send()
|
return reply.code(201).send()
|
||||||
} catch ({ status, message }) {
|
} catch ({ status, message }) {
|
||||||
@@ -607,7 +612,8 @@ export async function getBuildPack(request) {
|
|||||||
projectId: application.projectId,
|
projectId: application.projectId,
|
||||||
repository: application.repository,
|
repository: application.repository,
|
||||||
branch: application.branch,
|
branch: application.branch,
|
||||||
apiUrl: application.gitSource.apiUrl
|
apiUrl: application.gitSource.apiUrl,
|
||||||
|
isPublicRepository: application.settings.isPublicRepository
|
||||||
}
|
}
|
||||||
} catch ({ status, message }) {
|
} catch ({ status, message }) {
|
||||||
return errorHandler({ status, message })
|
return errorHandler({ status, message })
|
||||||
@@ -658,7 +664,6 @@ export async function saveSecret(request: FastifyRequest<SaveSecret>, reply: Fas
|
|||||||
throw { status: 500, message: `Secret ${name} already exists.` }
|
throw { status: 500, message: `Secret ${name} already exists.` }
|
||||||
} else {
|
} else {
|
||||||
value = encrypt(value.trim());
|
value = encrypt(value.trim());
|
||||||
console.log({value})
|
|
||||||
await prisma.secret.create({
|
await prisma.secret.create({
|
||||||
data: { name, value, isBuildSecret, isPRMRSecret, application: { connect: { id } } }
|
data: { name, value, isBuildSecret, isPRMRSecret, application: { connect: { id } } }
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -44,13 +44,13 @@ export interface CheckDNS extends OnlyId {
|
|||||||
}
|
}
|
||||||
export interface DeployApplication {
|
export interface DeployApplication {
|
||||||
Querystring: { domain: string }
|
Querystring: { domain: string }
|
||||||
Body: { pullmergeRequestId: string | null, branch: string }
|
Body: { pullmergeRequestId: string | null, branch: string, forceRebuild?: boolean }
|
||||||
}
|
}
|
||||||
export interface GetImages {
|
export interface GetImages {
|
||||||
Body: { buildPack: string, deploymentType: string }
|
Body: { buildPack: string, deploymentType: string }
|
||||||
}
|
}
|
||||||
export interface SaveApplicationSource extends OnlyId {
|
export interface SaveApplicationSource extends OnlyId {
|
||||||
Body: { gitSourceId: string }
|
Body: { gitSourceId?: string | null, forPublic?: boolean, type?: string }
|
||||||
}
|
}
|
||||||
export interface CheckRepository extends OnlyId {
|
export interface CheckRepository extends OnlyId {
|
||||||
Querystring: { repository: string, branch: string }
|
Querystring: { repository: string, branch: string }
|
||||||
@@ -115,7 +115,8 @@ export interface CancelDeployment {
|
|||||||
export interface DeployApplication extends OnlyId {
|
export interface DeployApplication extends OnlyId {
|
||||||
Body: {
|
Body: {
|
||||||
pullmergeRequestId: string | null,
|
pullmergeRequestId: string | null,
|
||||||
branch: string
|
branch: string,
|
||||||
|
forceRebuild?: boolean
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -79,7 +79,6 @@ export async function newDestination(request: FastifyRequest<NewDestination>, re
|
|||||||
|
|
||||||
let { name, network, engine, isCoolifyProxyUsed, remoteIpAddress, remoteUser, remotePort } = request.body
|
let { name, network, engine, isCoolifyProxyUsed, remoteIpAddress, remoteUser, remotePort } = request.body
|
||||||
if (id === 'new') {
|
if (id === 'new') {
|
||||||
console.log(engine)
|
|
||||||
if (engine) {
|
if (engine) {
|
||||||
const { stdout } = await asyncExecShell(`DOCKER_HOST=unix:///var/run/docker.sock docker network ls --filter 'name=^${network}$' --format '{{json .}}'`);
|
const { stdout } = await asyncExecShell(`DOCKER_HOST=unix:///var/run/docker.sock docker network ls --filter 'name=^${network}$' --format '{{json .}}'`);
|
||||||
if (stdout === '') {
|
if (stdout === '') {
|
||||||
|
|||||||
@@ -2,14 +2,14 @@ import type { FastifyReply, FastifyRequest } from 'fastify';
|
|||||||
import fs from 'fs/promises';
|
import fs from 'fs/promises';
|
||||||
import yaml from 'js-yaml';
|
import yaml from 'js-yaml';
|
||||||
import bcrypt from 'bcryptjs';
|
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, asyncSleep, isARM } 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, defaultComposeConfiguration, checkExposedPort } from '../../../../lib/common';
|
||||||
import { day } from '../../../../lib/dayjs';
|
import { day } from '../../../../lib/dayjs';
|
||||||
import { checkContainer, isContainerExited, removeContainer } from '../../../../lib/docker';
|
import { checkContainer, isContainerExited, removeContainer } from '../../../../lib/docker';
|
||||||
import cuid from 'cuid';
|
import cuid from 'cuid';
|
||||||
|
|
||||||
import type { OnlyId } from '../../../../types';
|
import type { OnlyId } from '../../../../types';
|
||||||
import type { ActivateWordpressFtp, CheckService, CheckServiceDomain, DeleteServiceSecret, DeleteServiceStorage, GetServiceLogs, SaveService, SaveServiceDestination, SaveServiceSecret, SaveServiceSettings, SaveServiceStorage, SaveServiceType, SaveServiceVersion, ServiceStartStop, SetWordpressSettings } from './types';
|
import type { ActivateWordpressFtp, CheckService, CheckServiceDomain, DeleteServiceSecret, DeleteServiceStorage, GetServiceLogs, SaveService, SaveServiceDestination, SaveServiceSecret, SaveServiceSettings, SaveServiceStorage, SaveServiceType, SaveServiceVersion, ServiceStartStop, SetWordpressSettings } from './types';
|
||||||
import { defaultServiceComposeConfiguration, defaultServiceConfigurations } from '../../../../lib/services';
|
import { defaultServiceConfigurations } from '../../../../lib/services';
|
||||||
|
|
||||||
// async function startServiceNew(request: FastifyRequest<OnlyId>) {
|
// async function startServiceNew(request: FastifyRequest<OnlyId>) {
|
||||||
// try {
|
// try {
|
||||||
@@ -30,7 +30,7 @@ import { defaultServiceComposeConfiguration, defaultServiceConfigurations } from
|
|||||||
// serviceSecret.forEach((secret) => {
|
// serviceSecret.forEach((secret) => {
|
||||||
// environmentVariables[secret.name] = secret.value;
|
// environmentVariables[secret.name] = secret.value;
|
||||||
// });
|
// });
|
||||||
// }
|
// }
|
||||||
// config.newVolumes = {}
|
// config.newVolumes = {}
|
||||||
// for (const service of Object.entries(config.services)) {
|
// for (const service of Object.entries(config.services)) {
|
||||||
// const name = service[0]
|
// const name = service[0]
|
||||||
@@ -98,7 +98,7 @@ import { defaultServiceComposeConfiguration, defaultServiceConfigurations } from
|
|||||||
|
|
||||||
// }
|
// }
|
||||||
// console.log(config.services)
|
// console.log(config.services)
|
||||||
// console.log(config.volumes)
|
// console.log(config.volumes)
|
||||||
|
|
||||||
// // config.services[id] = JSON.parse(JSON.stringify(config.services[type]))
|
// // config.services[id] = JSON.parse(JSON.stringify(config.services[type]))
|
||||||
// // config.services[id].container_name = id
|
// // config.services[id].container_name = id
|
||||||
@@ -378,18 +378,7 @@ export async function checkService(request: FastifyRequest<CheckService>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (exposePort) {
|
if (exposePort) await checkExposedPort({ id, configuredPort, exposePort, dockerId, remoteIpAddress })
|
||||||
if (exposePort < 1024 || exposePort > 65535) {
|
|
||||||
throw { status: 500, message: `Exposed Port needs to be between 1024 and 65535.` }
|
|
||||||
}
|
|
||||||
|
|
||||||
if (configuredPort !== exposePort) {
|
|
||||||
const availablePort = await getFreeExposedPort(id, exposePort, dockerId, remoteIpAddress);
|
|
||||||
if (availablePort.toString() !== exposePort.toString()) {
|
|
||||||
throw { status: 500, message: `Port ${exposePort} is already in use.` }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (isDNSCheckEnabled && !isDev && !forceSave) {
|
if (isDNSCheckEnabled && !isDev && !forceSave) {
|
||||||
let hostname = request.hostname.split(':')[0];
|
let hostname = request.hostname.split(':')[0];
|
||||||
if (remoteEngine) hostname = remoteIpAddress;
|
if (remoteEngine) hostname = remoteIpAddress;
|
||||||
@@ -591,6 +580,9 @@ export async function startService(request: FastifyRequest<ServiceStartStop>) {
|
|||||||
if (type === 'appwrite') {
|
if (type === 'appwrite') {
|
||||||
return await startAppWriteService(request)
|
return await startAppWriteService(request)
|
||||||
}
|
}
|
||||||
|
if (type === 'glitchTip') {
|
||||||
|
return await startGlitchTipService(request)
|
||||||
|
}
|
||||||
throw `Service type ${type} not supported.`
|
throw `Service type ${type} not supported.`
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw { status: 500, message: error?.message || error }
|
throw { status: 500, message: error?.message || error }
|
||||||
@@ -645,6 +637,9 @@ export async function stopService(request: FastifyRequest<ServiceStartStop>) {
|
|||||||
// if (type === 'moodle') {
|
// if (type === 'moodle') {
|
||||||
// return await stopMoodleService(request)
|
// return await stopMoodleService(request)
|
||||||
// }
|
// }
|
||||||
|
// if (type === 'glitchTip') {
|
||||||
|
// return await stopGlitchTipService(request)
|
||||||
|
// }
|
||||||
// throw `Service type ${type} not supported.`
|
// throw `Service type ${type} not supported.`
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw { status: 500, message: error?.message || error }
|
throw { status: 500, message: error?.message || error }
|
||||||
@@ -806,21 +801,21 @@ COPY ./init-db.sh /docker-entrypoint-initdb.d/init-db.sh`;
|
|||||||
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
||||||
depends_on: [`${id}-postgresql`, `${id}-clickhouse`],
|
depends_on: [`${id}-postgresql`, `${id}-clickhouse`],
|
||||||
labels: makeLabelForServices('plausibleAnalytics'),
|
labels: makeLabelForServices('plausibleAnalytics'),
|
||||||
...defaultServiceComposeConfiguration(network),
|
...defaultComposeConfiguration(network),
|
||||||
},
|
},
|
||||||
[`${id}-postgresql`]: {
|
[`${id}-postgresql`]: {
|
||||||
container_name: `${id}-postgresql`,
|
container_name: `${id}-postgresql`,
|
||||||
image: config.postgresql.image,
|
image: config.postgresql.image,
|
||||||
environment: config.postgresql.environmentVariables,
|
environment: config.postgresql.environmentVariables,
|
||||||
volumes: [config.postgresql.volume],
|
volumes: [config.postgresql.volume],
|
||||||
...defaultServiceComposeConfiguration(network),
|
...defaultComposeConfiguration(network),
|
||||||
},
|
},
|
||||||
[`${id}-clickhouse`]: {
|
[`${id}-clickhouse`]: {
|
||||||
build: workdir,
|
build: workdir,
|
||||||
container_name: `${id}-clickhouse`,
|
container_name: `${id}-clickhouse`,
|
||||||
environment: config.clickhouse.environmentVariables,
|
environment: config.clickhouse.environmentVariables,
|
||||||
volumes: [config.clickhouse.volume],
|
volumes: [config.clickhouse.volume],
|
||||||
...defaultServiceComposeConfiguration(network),
|
...defaultComposeConfiguration(network),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
networks: {
|
networks: {
|
||||||
@@ -881,7 +876,7 @@ async function startNocodbService(request: FastifyRequest<ServiceStartStop>) {
|
|||||||
environment: config.environmentVariables,
|
environment: config.environmentVariables,
|
||||||
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
||||||
labels: makeLabelForServices('nocodb'),
|
labels: makeLabelForServices('nocodb'),
|
||||||
...defaultServiceComposeConfiguration(network),
|
...defaultComposeConfiguration(network),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
networks: {
|
networks: {
|
||||||
@@ -953,7 +948,7 @@ async function startMinioService(request: FastifyRequest<ServiceStartStop>) {
|
|||||||
volumes,
|
volumes,
|
||||||
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
||||||
labels: makeLabelForServices('minio'),
|
labels: makeLabelForServices('minio'),
|
||||||
...defaultServiceComposeConfiguration(network),
|
...defaultComposeConfiguration(network),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
networks: {
|
networks: {
|
||||||
@@ -1019,7 +1014,7 @@ async function startVscodeService(request: FastifyRequest<ServiceStartStop>) {
|
|||||||
volumes,
|
volumes,
|
||||||
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
||||||
labels: makeLabelForServices('vscodeServer'),
|
labels: makeLabelForServices('vscodeServer'),
|
||||||
...defaultServiceComposeConfiguration(network),
|
...defaultComposeConfiguration(network),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
networks: {
|
networks: {
|
||||||
@@ -1116,7 +1111,7 @@ async function startWordpressService(request: FastifyRequest<ServiceStartStop>)
|
|||||||
|
|
||||||
const { volumes, volumeMounts } = persistentVolumes(id, persistentStorage, config.wordpress)
|
const { volumes, volumeMounts } = persistentVolumes(id, persistentStorage, config.wordpress)
|
||||||
|
|
||||||
let composeFile: ComposeFile = {
|
const composeFile: ComposeFile = {
|
||||||
version: '3.8',
|
version: '3.8',
|
||||||
services: {
|
services: {
|
||||||
[id]: {
|
[id]: {
|
||||||
@@ -1126,7 +1121,7 @@ async function startWordpressService(request: FastifyRequest<ServiceStartStop>)
|
|||||||
volumes,
|
volumes,
|
||||||
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
||||||
labels: makeLabelForServices('wordpress'),
|
labels: makeLabelForServices('wordpress'),
|
||||||
...defaultServiceComposeConfiguration(network),
|
...defaultComposeConfiguration(network),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
networks: {
|
networks: {
|
||||||
@@ -1143,7 +1138,7 @@ async function startWordpressService(request: FastifyRequest<ServiceStartStop>)
|
|||||||
image: config.mysql.image,
|
image: config.mysql.image,
|
||||||
volumes: [config.mysql.volume],
|
volumes: [config.mysql.volume],
|
||||||
environment: config.mysql.environmentVariables,
|
environment: config.mysql.environmentVariables,
|
||||||
...defaultServiceComposeConfiguration(network),
|
...defaultComposeConfiguration(network),
|
||||||
};
|
};
|
||||||
|
|
||||||
composeFile.volumes[config.mysql.volume.split(':')[0]] = {
|
composeFile.volumes[config.mysql.volume.split(':')[0]] = {
|
||||||
@@ -1196,7 +1191,7 @@ async function startVaultwardenService(request: FastifyRequest<ServiceStartStop>
|
|||||||
volumes,
|
volumes,
|
||||||
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
||||||
labels: makeLabelForServices('vaultWarden'),
|
labels: makeLabelForServices('vaultWarden'),
|
||||||
...defaultServiceComposeConfiguration(network),
|
...defaultComposeConfiguration(network),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
networks: {
|
networks: {
|
||||||
@@ -1252,7 +1247,7 @@ async function startLanguageToolService(request: FastifyRequest<ServiceStartStop
|
|||||||
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
||||||
volumes,
|
volumes,
|
||||||
labels: makeLabelForServices('languagetool'),
|
labels: makeLabelForServices('languagetool'),
|
||||||
...defaultServiceComposeConfiguration(network),
|
...defaultComposeConfiguration(network),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
networks: {
|
networks: {
|
||||||
@@ -1309,7 +1304,7 @@ async function startN8nService(request: FastifyRequest<ServiceStartStop>) {
|
|||||||
environment: config.environmentVariables,
|
environment: config.environmentVariables,
|
||||||
labels: makeLabelForServices('n8n'),
|
labels: makeLabelForServices('n8n'),
|
||||||
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
||||||
...defaultServiceComposeConfiguration(network),
|
...defaultComposeConfiguration(network),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
networks: {
|
networks: {
|
||||||
@@ -1364,7 +1359,7 @@ async function startUptimekumaService(request: FastifyRequest<ServiceStartStop>)
|
|||||||
environment: config.environmentVariables,
|
environment: config.environmentVariables,
|
||||||
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
||||||
labels: makeLabelForServices('uptimekuma'),
|
labels: makeLabelForServices('uptimekuma'),
|
||||||
...defaultServiceComposeConfiguration(network),
|
...defaultComposeConfiguration(network),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
networks: {
|
networks: {
|
||||||
@@ -1463,14 +1458,14 @@ async function startGhostService(request: FastifyRequest<ServiceStartStop>) {
|
|||||||
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
||||||
labels: makeLabelForServices('ghost'),
|
labels: makeLabelForServices('ghost'),
|
||||||
depends_on: [`${id}-mariadb`],
|
depends_on: [`${id}-mariadb`],
|
||||||
...defaultServiceComposeConfiguration(network),
|
...defaultComposeConfiguration(network),
|
||||||
},
|
},
|
||||||
[`${id}-mariadb`]: {
|
[`${id}-mariadb`]: {
|
||||||
container_name: `${id}-mariadb`,
|
container_name: `${id}-mariadb`,
|
||||||
image: config.mariadb.image,
|
image: config.mariadb.image,
|
||||||
volumes: [config.mariadb.volume],
|
volumes: [config.mariadb.volume],
|
||||||
environment: config.mariadb.environmentVariables,
|
environment: config.mariadb.environmentVariables,
|
||||||
...defaultServiceComposeConfiguration(network),
|
...defaultComposeConfiguration(network),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
networks: {
|
networks: {
|
||||||
@@ -1536,7 +1531,7 @@ async function startMeilisearchService(request: FastifyRequest<ServiceStartStop>
|
|||||||
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
||||||
volumes,
|
volumes,
|
||||||
labels: makeLabelForServices('meilisearch'),
|
labels: makeLabelForServices('meilisearch'),
|
||||||
...defaultServiceComposeConfiguration(network),
|
...defaultComposeConfiguration(network),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
networks: {
|
networks: {
|
||||||
@@ -1702,14 +1697,14 @@ async function startUmamiService(request: FastifyRequest<ServiceStartStop>) {
|
|||||||
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
||||||
labels: makeLabelForServices('umami'),
|
labels: makeLabelForServices('umami'),
|
||||||
depends_on: [`${id}-postgresql`],
|
depends_on: [`${id}-postgresql`],
|
||||||
...defaultServiceComposeConfiguration(network),
|
...defaultComposeConfiguration(network),
|
||||||
},
|
},
|
||||||
[`${id}-postgresql`]: {
|
[`${id}-postgresql`]: {
|
||||||
build: workdir,
|
build: workdir,
|
||||||
container_name: `${id}-postgresql`,
|
container_name: `${id}-postgresql`,
|
||||||
environment: config.postgresql.environmentVariables,
|
environment: config.postgresql.environmentVariables,
|
||||||
volumes: [config.postgresql.volume],
|
volumes: [config.postgresql.volume],
|
||||||
...defaultServiceComposeConfiguration(network),
|
...defaultComposeConfiguration(network),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
networks: {
|
networks: {
|
||||||
@@ -1789,14 +1784,14 @@ async function startHasuraService(request: FastifyRequest<ServiceStartStop>) {
|
|||||||
labels: makeLabelForServices('hasura'),
|
labels: makeLabelForServices('hasura'),
|
||||||
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
||||||
depends_on: [`${id}-postgresql`],
|
depends_on: [`${id}-postgresql`],
|
||||||
...defaultServiceComposeConfiguration(network),
|
...defaultComposeConfiguration(network),
|
||||||
},
|
},
|
||||||
[`${id}-postgresql`]: {
|
[`${id}-postgresql`]: {
|
||||||
image: config.postgresql.image,
|
image: config.postgresql.image,
|
||||||
container_name: `${id}-postgresql`,
|
container_name: `${id}-postgresql`,
|
||||||
environment: config.postgresql.environmentVariables,
|
environment: config.postgresql.environmentVariables,
|
||||||
volumes: [config.postgresql.volume],
|
volumes: [config.postgresql.volume],
|
||||||
...defaultServiceComposeConfiguration(network),
|
...defaultComposeConfiguration(network),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
networks: {
|
networks: {
|
||||||
@@ -1902,14 +1897,14 @@ async function startFiderService(request: FastifyRequest<ServiceStartStop>) {
|
|||||||
labels: makeLabelForServices('fider'),
|
labels: makeLabelForServices('fider'),
|
||||||
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
||||||
depends_on: [`${id}-postgresql`],
|
depends_on: [`${id}-postgresql`],
|
||||||
...defaultServiceComposeConfiguration(network),
|
...defaultComposeConfiguration(network),
|
||||||
},
|
},
|
||||||
[`${id}-postgresql`]: {
|
[`${id}-postgresql`]: {
|
||||||
image: config.postgresql.image,
|
image: config.postgresql.image,
|
||||||
container_name: `${id}-postgresql`,
|
container_name: `${id}-postgresql`,
|
||||||
environment: config.postgresql.environmentVariables,
|
environment: config.postgresql.environmentVariables,
|
||||||
volumes: [config.postgresql.volume],
|
volumes: [config.postgresql.volume],
|
||||||
...defaultServiceComposeConfiguration(network),
|
...defaultComposeConfiguration(network),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
networks: {
|
networks: {
|
||||||
@@ -1995,7 +1990,7 @@ async function startAppWriteService(request: FastifyRequest<ServiceStartStop>) {
|
|||||||
"_APP_STATSD_PORT=8125",
|
"_APP_STATSD_PORT=8125",
|
||||||
...secrets
|
...secrets
|
||||||
],
|
],
|
||||||
...defaultServiceComposeConfiguration(network),
|
...defaultComposeConfiguration(network),
|
||||||
},
|
},
|
||||||
[`${id}-realtime`]: {
|
[`${id}-realtime`]: {
|
||||||
image: `${image}:${version}`,
|
image: `${image}:${version}`,
|
||||||
@@ -2018,7 +2013,7 @@ async function startAppWriteService(request: FastifyRequest<ServiceStartStop>) {
|
|||||||
`_APP_DB_PASS=${mariadbPassword}`,
|
`_APP_DB_PASS=${mariadbPassword}`,
|
||||||
...secrets
|
...secrets
|
||||||
],
|
],
|
||||||
...defaultServiceComposeConfiguration(network),
|
...defaultComposeConfiguration(network),
|
||||||
},
|
},
|
||||||
[`${id}-worker-audits`]: {
|
[`${id}-worker-audits`]: {
|
||||||
|
|
||||||
@@ -2042,7 +2037,7 @@ async function startAppWriteService(request: FastifyRequest<ServiceStartStop>) {
|
|||||||
`_APP_DB_PASS=${mariadbPassword}`,
|
`_APP_DB_PASS=${mariadbPassword}`,
|
||||||
...secrets
|
...secrets
|
||||||
],
|
],
|
||||||
...defaultServiceComposeConfiguration(network),
|
...defaultComposeConfiguration(network),
|
||||||
},
|
},
|
||||||
[`${id}-worker-webhooks`]: {
|
[`${id}-worker-webhooks`]: {
|
||||||
image: `${image}:${version}`,
|
image: `${image}:${version}`,
|
||||||
@@ -2060,7 +2055,7 @@ async function startAppWriteService(request: FastifyRequest<ServiceStartStop>) {
|
|||||||
"_APP_REDIS_PORT=6379",
|
"_APP_REDIS_PORT=6379",
|
||||||
...secrets
|
...secrets
|
||||||
],
|
],
|
||||||
...defaultServiceComposeConfiguration(network),
|
...defaultComposeConfiguration(network),
|
||||||
},
|
},
|
||||||
[`${id}-worker-deletes`]: {
|
[`${id}-worker-deletes`]: {
|
||||||
image: `${image}:${version}`,
|
image: `${image}:${version}`,
|
||||||
@@ -2093,7 +2088,7 @@ async function startAppWriteService(request: FastifyRequest<ServiceStartStop>) {
|
|||||||
`_APP_EXECUTOR_HOST=http://${id}-executor/v1`,
|
`_APP_EXECUTOR_HOST=http://${id}-executor/v1`,
|
||||||
...secrets
|
...secrets
|
||||||
],
|
],
|
||||||
...defaultServiceComposeConfiguration(network),
|
...defaultComposeConfiguration(network),
|
||||||
},
|
},
|
||||||
[`${id}-worker-databases`]: {
|
[`${id}-worker-databases`]: {
|
||||||
image: `${image}:${version}`,
|
image: `${image}:${version}`,
|
||||||
@@ -2116,7 +2111,7 @@ async function startAppWriteService(request: FastifyRequest<ServiceStartStop>) {
|
|||||||
`_APP_DB_PASS=${mariadbPassword}`,
|
`_APP_DB_PASS=${mariadbPassword}`,
|
||||||
...secrets
|
...secrets
|
||||||
],
|
],
|
||||||
...defaultServiceComposeConfiguration(network),
|
...defaultComposeConfiguration(network),
|
||||||
},
|
},
|
||||||
[`${id}-worker-builds`]: {
|
[`${id}-worker-builds`]: {
|
||||||
image: `${image}:${version}`,
|
image: `${image}:${version}`,
|
||||||
@@ -2141,7 +2136,7 @@ async function startAppWriteService(request: FastifyRequest<ServiceStartStop>) {
|
|||||||
`_APP_DB_PASS=${mariadbPassword}`,
|
`_APP_DB_PASS=${mariadbPassword}`,
|
||||||
...secrets
|
...secrets
|
||||||
],
|
],
|
||||||
...defaultServiceComposeConfiguration(network),
|
...defaultComposeConfiguration(network),
|
||||||
},
|
},
|
||||||
[`${id}-worker-certificates`]: {
|
[`${id}-worker-certificates`]: {
|
||||||
image: `${image}:${version}`,
|
image: `${image}:${version}`,
|
||||||
@@ -2170,7 +2165,7 @@ async function startAppWriteService(request: FastifyRequest<ServiceStartStop>) {
|
|||||||
`_APP_DB_PASS=${mariadbPassword}`,
|
`_APP_DB_PASS=${mariadbPassword}`,
|
||||||
...secrets
|
...secrets
|
||||||
],
|
],
|
||||||
...defaultServiceComposeConfiguration(network),
|
...defaultComposeConfiguration(network),
|
||||||
},
|
},
|
||||||
[`${id}-worker-functions`]: {
|
[`${id}-worker-functions`]: {
|
||||||
image: `${image}:${version}`,
|
image: `${image}:${version}`,
|
||||||
@@ -2196,7 +2191,7 @@ async function startAppWriteService(request: FastifyRequest<ServiceStartStop>) {
|
|||||||
`_APP_EXECUTOR_HOST=http://${id}-executor/v1`,
|
`_APP_EXECUTOR_HOST=http://${id}-executor/v1`,
|
||||||
...secrets
|
...secrets
|
||||||
],
|
],
|
||||||
...defaultServiceComposeConfiguration(network),
|
...defaultComposeConfiguration(network),
|
||||||
},
|
},
|
||||||
[`${id}-executor`]: {
|
[`${id}-executor`]: {
|
||||||
image: `${image}:${version}`,
|
image: `${image}:${version}`,
|
||||||
@@ -2220,7 +2215,7 @@ async function startAppWriteService(request: FastifyRequest<ServiceStartStop>) {
|
|||||||
`_APP_EXECUTOR_SECRET=${executorSecret}`,
|
`_APP_EXECUTOR_SECRET=${executorSecret}`,
|
||||||
...secrets
|
...secrets
|
||||||
],
|
],
|
||||||
...defaultServiceComposeConfiguration(network),
|
...defaultComposeConfiguration(network),
|
||||||
},
|
},
|
||||||
[`${id}-worker-mails`]: {
|
[`${id}-worker-mails`]: {
|
||||||
image: `${image}:${version}`,
|
image: `${image}:${version}`,
|
||||||
@@ -2237,7 +2232,7 @@ async function startAppWriteService(request: FastifyRequest<ServiceStartStop>) {
|
|||||||
"_APP_REDIS_PORT=6379",
|
"_APP_REDIS_PORT=6379",
|
||||||
...secrets
|
...secrets
|
||||||
],
|
],
|
||||||
...defaultServiceComposeConfiguration(network),
|
...defaultComposeConfiguration(network),
|
||||||
},
|
},
|
||||||
[`${id}-worker-messaging`]: {
|
[`${id}-worker-messaging`]: {
|
||||||
image: `${image}:${version}`,
|
image: `${image}:${version}`,
|
||||||
@@ -2253,7 +2248,7 @@ async function startAppWriteService(request: FastifyRequest<ServiceStartStop>) {
|
|||||||
"_APP_REDIS_PORT=6379",
|
"_APP_REDIS_PORT=6379",
|
||||||
...secrets
|
...secrets
|
||||||
],
|
],
|
||||||
...defaultServiceComposeConfiguration(network),
|
...defaultComposeConfiguration(network),
|
||||||
},
|
},
|
||||||
[`${id}-maintenance`]: {
|
[`${id}-maintenance`]: {
|
||||||
image: `${image}:${version}`,
|
image: `${image}:${version}`,
|
||||||
@@ -2277,7 +2272,7 @@ async function startAppWriteService(request: FastifyRequest<ServiceStartStop>) {
|
|||||||
`_APP_DB_PASS=${mariadbPassword}`,
|
`_APP_DB_PASS=${mariadbPassword}`,
|
||||||
...secrets
|
...secrets
|
||||||
],
|
],
|
||||||
...defaultServiceComposeConfiguration(network),
|
...defaultComposeConfiguration(network),
|
||||||
},
|
},
|
||||||
[`${id}-schedule`]: {
|
[`${id}-schedule`]: {
|
||||||
image: `${image}:${version}`,
|
image: `${image}:${version}`,
|
||||||
@@ -2293,7 +2288,7 @@ async function startAppWriteService(request: FastifyRequest<ServiceStartStop>) {
|
|||||||
"_APP_REDIS_PORT=6379",
|
"_APP_REDIS_PORT=6379",
|
||||||
...secrets
|
...secrets
|
||||||
],
|
],
|
||||||
...defaultServiceComposeConfiguration(network),
|
...defaultComposeConfiguration(network),
|
||||||
},
|
},
|
||||||
[`${id}-mariadb`]: {
|
[`${id}-mariadb`]: {
|
||||||
"image": "mariadb:10.7",
|
"image": "mariadb:10.7",
|
||||||
@@ -2310,7 +2305,7 @@ async function startAppWriteService(request: FastifyRequest<ServiceStartStop>) {
|
|||||||
`MYSQL_DATABASE=${mariadbDatabase}`
|
`MYSQL_DATABASE=${mariadbDatabase}`
|
||||||
],
|
],
|
||||||
"command": "mysqld --innodb-flush-method=fsync",
|
"command": "mysqld --innodb-flush-method=fsync",
|
||||||
...defaultServiceComposeConfiguration(network),
|
...defaultComposeConfiguration(network),
|
||||||
},
|
},
|
||||||
[`${id}-redis`]: {
|
[`${id}-redis`]: {
|
||||||
"image": "redis:6.2-alpine",
|
"image": "redis:6.2-alpine",
|
||||||
@@ -2319,7 +2314,7 @@ async function startAppWriteService(request: FastifyRequest<ServiceStartStop>) {
|
|||||||
"volumes": [
|
"volumes": [
|
||||||
`${id}-redis:/data:rw`
|
`${id}-redis:/data:rw`
|
||||||
],
|
],
|
||||||
...defaultServiceComposeConfiguration(network),
|
...defaultComposeConfiguration(network),
|
||||||
},
|
},
|
||||||
|
|
||||||
};
|
};
|
||||||
@@ -2348,7 +2343,7 @@ async function startAppWriteService(request: FastifyRequest<ServiceStartStop>) {
|
|||||||
"_APP_REDIS_PORT=6379",
|
"_APP_REDIS_PORT=6379",
|
||||||
...secrets
|
...secrets
|
||||||
],
|
],
|
||||||
...defaultServiceComposeConfiguration(network),
|
...defaultComposeConfiguration(network),
|
||||||
}
|
}
|
||||||
dockerCompose[`${id}-influxdb`] = {
|
dockerCompose[`${id}-influxdb`] = {
|
||||||
"image": "appwrite/influxdb:1.5.0",
|
"image": "appwrite/influxdb:1.5.0",
|
||||||
@@ -2356,7 +2351,7 @@ async function startAppWriteService(request: FastifyRequest<ServiceStartStop>) {
|
|||||||
"volumes": [
|
"volumes": [
|
||||||
`${id}-influxdb:/var/lib/influxdb:rw`
|
`${id}-influxdb:/var/lib/influxdb:rw`
|
||||||
],
|
],
|
||||||
...defaultServiceComposeConfiguration(network),
|
...defaultComposeConfiguration(network),
|
||||||
}
|
}
|
||||||
dockerCompose[`${id}-telegraf`] = {
|
dockerCompose[`${id}-telegraf`] = {
|
||||||
"image": "appwrite/telegraf:1.4.0",
|
"image": "appwrite/telegraf:1.4.0",
|
||||||
@@ -2365,7 +2360,7 @@ async function startAppWriteService(request: FastifyRequest<ServiceStartStop>) {
|
|||||||
`_APP_INFLUXDB_HOST=${id}-influxdb`,
|
`_APP_INFLUXDB_HOST=${id}-influxdb`,
|
||||||
"_APP_INFLUXDB_PORT=8086",
|
"_APP_INFLUXDB_PORT=8086",
|
||||||
],
|
],
|
||||||
...defaultServiceComposeConfiguration(network),
|
...defaultComposeConfiguration(network),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2574,6 +2569,252 @@ async function startMoodleService(request: FastifyRequest<ServiceStartStop>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function startGlitchTipService(request: FastifyRequest<ServiceStartStop>) {
|
||||||
|
try {
|
||||||
|
const { id } = request.params;
|
||||||
|
const teamId = request.user.teamId;
|
||||||
|
const service = await getServiceFromDB({ id, teamId });
|
||||||
|
const {
|
||||||
|
type,
|
||||||
|
version,
|
||||||
|
fqdn,
|
||||||
|
destinationDockerId,
|
||||||
|
destinationDocker,
|
||||||
|
serviceSecret,
|
||||||
|
persistentStorage,
|
||||||
|
exposePort,
|
||||||
|
glitchTip: {
|
||||||
|
postgresqlDatabase,
|
||||||
|
postgresqlPassword,
|
||||||
|
postgresqlUser,
|
||||||
|
secretKeyBase,
|
||||||
|
defaultEmail,
|
||||||
|
defaultUsername,
|
||||||
|
defaultPassword,
|
||||||
|
defaultFromEmail,
|
||||||
|
emailSmtpHost,
|
||||||
|
emailSmtpPort,
|
||||||
|
emailSmtpUser,
|
||||||
|
emailSmtpPassword,
|
||||||
|
emailSmtpUseTls,
|
||||||
|
emailSmtpUseSsl,
|
||||||
|
emailBackend,
|
||||||
|
mailgunApiKey,
|
||||||
|
sendgridApiKey,
|
||||||
|
enableOpenUserRegistration,
|
||||||
|
}
|
||||||
|
} = service;
|
||||||
|
const network = destinationDockerId && destinationDocker.network;
|
||||||
|
const port = getServiceMainPort('glitchTip');
|
||||||
|
|
||||||
|
const { workdir } = await createDirectories({ repository: type, buildId: id });
|
||||||
|
const image = getServiceImage(type);
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
glitchTip: {
|
||||||
|
image: `${image}:${version}`,
|
||||||
|
environmentVariables: {
|
||||||
|
PORT: port,
|
||||||
|
GLITCHTIP_DOMAIN: fqdn,
|
||||||
|
SECRET_KEY: secretKeyBase,
|
||||||
|
DATABASE_URL: `postgresql://${postgresqlUser}:${postgresqlPassword}@${id}-postgresql:5432/${postgresqlDatabase}`,
|
||||||
|
REDIS_URL: `redis://${id}-redis:6379/0`,
|
||||||
|
DEFAULT_FROM_EMAIL: defaultFromEmail,
|
||||||
|
EMAIL_HOST: emailSmtpHost,
|
||||||
|
EMAIL_PORT: emailSmtpPort,
|
||||||
|
EMAIL_HOST_USER: emailSmtpUser,
|
||||||
|
EMAIL_HOST_PASSWORD: emailSmtpPassword,
|
||||||
|
EMAIL_USE_TLS: emailSmtpUseTls,
|
||||||
|
EMAIL_USE_SSL: emailSmtpUseSsl,
|
||||||
|
EMAIL_BACKEND: emailBackend,
|
||||||
|
MAILGUN_API_KEY: mailgunApiKey,
|
||||||
|
SENDGRID_API_KEY: sendgridApiKey,
|
||||||
|
ENABLE_OPEN_USER_REGISTRATION: enableOpenUserRegistration,
|
||||||
|
DJANGO_SUPERUSER_EMAIL: defaultEmail,
|
||||||
|
DJANGO_SUPERUSER_USERNAME: defaultUsername,
|
||||||
|
DJANGO_SUPERUSER_PASSWORD: defaultPassword,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
postgresql: {
|
||||||
|
image: 'postgres:14-alpine',
|
||||||
|
volume: `${id}-postgresql-data:/var/lib/postgresql/data`,
|
||||||
|
environmentVariables: {
|
||||||
|
POSTGRES_USER: postgresqlUser,
|
||||||
|
POSTGRES_PASSWORD: postgresqlPassword,
|
||||||
|
POSTGRES_DB: postgresqlDatabase
|
||||||
|
}
|
||||||
|
},
|
||||||
|
redis: {
|
||||||
|
image: 'redis:7-alpine',
|
||||||
|
volume: `${id}-redis-data:/data`,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (serviceSecret.length > 0) {
|
||||||
|
serviceSecret.forEach((secret) => {
|
||||||
|
config.glitchTip.environmentVariables[secret.name] = secret.value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const { volumes, volumeMounts } = persistentVolumes(id, persistentStorage, config.glitchTip)
|
||||||
|
const composeFile: ComposeFile = {
|
||||||
|
version: '3.8',
|
||||||
|
services: {
|
||||||
|
[id]: {
|
||||||
|
container_name: id,
|
||||||
|
image: config.glitchTip.image,
|
||||||
|
environment: config.glitchTip.environmentVariables,
|
||||||
|
networks: [network],
|
||||||
|
volumes,
|
||||||
|
restart: 'always',
|
||||||
|
labels: makeLabelForServices('glitchTip'),
|
||||||
|
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
||||||
|
deploy: {
|
||||||
|
restart_policy: {
|
||||||
|
condition: 'on-failure',
|
||||||
|
delay: '5s',
|
||||||
|
max_attempts: 3,
|
||||||
|
window: '120s'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
depends_on: [`${id}-postgresql`, `${id}-redis`]
|
||||||
|
},
|
||||||
|
[`${id}-worker`]: {
|
||||||
|
container_name: `${id}-worker`,
|
||||||
|
image: config.glitchTip.image,
|
||||||
|
command: './bin/run-celery-with-beat.sh',
|
||||||
|
environment: config.glitchTip.environmentVariables,
|
||||||
|
networks: [network],
|
||||||
|
restart: 'always',
|
||||||
|
deploy: {
|
||||||
|
restart_policy: {
|
||||||
|
condition: 'on-failure',
|
||||||
|
delay: '5s',
|
||||||
|
max_attempts: 3,
|
||||||
|
window: '120s'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
depends_on: [`${id}-postgresql`, `${id}-redis`]
|
||||||
|
},
|
||||||
|
[`${id}-setup`]: {
|
||||||
|
container_name: `${id}-setup`,
|
||||||
|
image: config.glitchTip.image,
|
||||||
|
command: 'sh -c "(./manage.py migrate || true) && (./manage.py createsuperuser --noinput || true)"',
|
||||||
|
environment: config.glitchTip.environmentVariables,
|
||||||
|
networks: [network],
|
||||||
|
restart: "no",
|
||||||
|
depends_on: [`${id}-postgresql`, `${id}-redis`]
|
||||||
|
},
|
||||||
|
[`${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'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[`${id}-redis`]: {
|
||||||
|
image: config.redis.image,
|
||||||
|
container_name: `${id}-redis`,
|
||||||
|
networks: [network],
|
||||||
|
volumes: [config.redis.volume],
|
||||||
|
restart: 'always',
|
||||||
|
deploy: {
|
||||||
|
restart_policy: {
|
||||||
|
condition: 'on-failure',
|
||||||
|
delay: '5s',
|
||||||
|
max_attempts: 3,
|
||||||
|
window: '120s'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
networks: {
|
||||||
|
[network]: {
|
||||||
|
external: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
volumes: {
|
||||||
|
...volumeMounts,
|
||||||
|
[config.postgresql.volume.split(':')[0]]: {
|
||||||
|
name: config.postgresql.volume.split(':')[0]
|
||||||
|
},
|
||||||
|
[config.redis.volume.split(':')[0]]: {
|
||||||
|
name: config.redis.volume.split(':')[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
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 stopGlitchTipService(request: FastifyRequest<ServiceStartStop>) {
|
||||||
|
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}-worker` });
|
||||||
|
if (found) {
|
||||||
|
await removeContainer({ id: `${id}-worker`, dockerId: destinationDocker.id });
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const found = await checkContainer({ dockerId: destinationDocker.id, container: `${id}-setup` });
|
||||||
|
if (found) {
|
||||||
|
await removeContainer({ id: `${id}-setup`, 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);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const found = await checkContainer({ dockerId: destinationDocker.id, container: `${id}-redis` });
|
||||||
|
if (found) {
|
||||||
|
await removeContainer({ id: `${id}-redis`, dockerId: destinationDocker.id });
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {}
|
||||||
|
} catch ({ status, message }) {
|
||||||
|
return errorHandler({ status, message })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export async function activatePlausibleUsers(request: FastifyRequest<OnlyId>, reply: FastifyReply) {
|
export async function activatePlausibleUsers(request: FastifyRequest<OnlyId>, reply: FastifyReply) {
|
||||||
try {
|
try {
|
||||||
const { id } = request.params
|
const { id } = request.params
|
||||||
|
|||||||
@@ -484,7 +484,6 @@ export async function traefikOtherConfiguration(request: FastifyRequest<TraefikO
|
|||||||
}
|
}
|
||||||
throw { status: 500 }
|
throw { status: 500 }
|
||||||
} catch ({ status, message }) {
|
} catch ({ status, message }) {
|
||||||
console.log(status, message);
|
|
||||||
return errorHandler({ status, message })
|
return errorHandler({ status, message })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -158,7 +158,7 @@ export const supportedServiceTypesAndVersions = [
|
|||||||
ports: {
|
ports: {
|
||||||
main: 80
|
main: 80
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
// {
|
// {
|
||||||
// name: 'moodle',
|
// name: 'moodle',
|
||||||
// fancyName: 'Moodle',
|
// fancyName: 'Moodle',
|
||||||
@@ -170,6 +170,17 @@ export const supportedServiceTypesAndVersions = [
|
|||||||
// main: 8080
|
// main: 8080
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
{
|
||||||
|
name: 'glitchTip',
|
||||||
|
fancyName: 'GlitchTip',
|
||||||
|
baseImage: 'glitchtip/glitchtip',
|
||||||
|
images: ['postgres:14-alpine', 'redis:7-alpine'],
|
||||||
|
versions: ['latest'],
|
||||||
|
recommendedVersion: 'latest',
|
||||||
|
ports: {
|
||||||
|
main: 8000
|
||||||
|
}
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export const asyncSleep = (delay: number) =>
|
export const asyncSleep = (delay: number) =>
|
||||||
|
|||||||
51
apps/ui/src/lib/components/svg/services/GlitchTip.svelte
Normal file
51
apps/ui/src/lib/components/svg/services/GlitchTip.svelte
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
export let isAbsolute = false;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svg
|
||||||
|
class={isAbsolute ? 'w-10 h-10 absolute top-0 left-0 -m-5' : 'w-8 mx-auto'}
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
style="isolation:isolate"
|
||||||
|
viewBox="0 0 400 400"
|
||||||
|
>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="_clipPath_5kOQy2sGcuF9aeG3NHWmCAGgMEPQrnNW">
|
||||||
|
<rect width="400" height="400" />
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
<g clip-path="url(#_clipPath_5kOQy2sGcuF9aeG3NHWmCAGgMEPQrnNW)">
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path
|
||||||
|
d=" M 276.155 367.684 L 337.655 367.684 L 337.655 180.781 L 205.525 180.781 L 205.525 241.801 L 267.987 241.801 L 267.987 258.617 C 267.987 291.29 238.678 308.586 202.162 308.586 C 156.998 308.586 127.689 282.641 127.689 226.906 L 127.689 173.094 C 127.689 117.359 156.998 91.414 202.162 91.414 C 241.08 91.414 261.74 112.554 271.83 138.5 L 331.409 104.386 C 306.424 52.976 261.74 26.55 202.162 26.55 C 111.353 26.55 50.333 88.531 50.333 201.441 C 50.333 313.872 110.873 373.45 187.748 373.45 C 238.197 373.45 268.947 347.985 273.752 314.352 L 276.155 314.352 L 276.155 367.684 Z "
|
||||||
|
fill="rgb(132,24,128)"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
<g opacity="0.5">
|
||||||
|
<path
|
||||||
|
d=" M 139.701 175.78 L 139.701 173.094 C 139.701 117.359 169.01 91.414 214.174 91.414 C 253.092 91.414 273.752 112.554 283.842 138.5 L 343.421 104.386 C 318.436 52.976 273.752 26.55 214.174 26.55 C 128.962 26.55 69.981 81.125 63.033 181.145 L 139.701 175.78 Z "
|
||||||
|
fill-rule="evenodd"
|
||||||
|
fill="rgb(233,64,86)"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
<g opacity="0.5">
|
||||||
|
<path
|
||||||
|
d=" M 349.667 305.194 L 349.667 247.137 L 279.998 252.019 L 279.998 258.617 C 279.998 291.29 250.69 308.586 214.174 308.586 C 179.697 308.586 154.459 293.467 144.446 261.518 L 70.341 266.711 C 76.285 288.796 85.348 307.563 96.86 322.909 L 349.667 305.194 Z "
|
||||||
|
fill-rule="evenodd"
|
||||||
|
fill="rgb(233,64,86)"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
<path
|
||||||
|
d=" M 337.655 247.03 L 337.655 180.781 L 205.525 180.781 L 205.525 241.801 L 267.987 241.801 L 267.987 251.912 L 337.655 247.03 Z M 132.401 261.413 C 129.319 251.534 127.689 240.048 127.689 226.906 L 127.689 175.099 L 51.069 180.468 C 50.581 187.25 50.333 194.242 50.333 201.441 C 50.333 225.632 53.136 247.376 58.301 266.606 L 132.401 261.413 Z "
|
||||||
|
fill-rule="evenodd"
|
||||||
|
fill="rgb(233,64,86)"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d=" M 337.655 305.862 L 337.655 367.684 L 276.155 367.684 L 276.155 314.352 L 273.752 314.352 C 268.947 347.985 238.197 373.45 187.748 373.45 C 146.712 373.45 110.33 356.473 85.327 323.543 L 337.655 305.862 Z "
|
||||||
|
fill-rule="evenodd"
|
||||||
|
fill="rgb(255,63,42)"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
@@ -36,4 +36,6 @@
|
|||||||
<Icons.Appwrite {isAbsolute} />
|
<Icons.Appwrite {isAbsolute} />
|
||||||
{:else if type === 'moodle'}
|
{:else if type === 'moodle'}
|
||||||
<Icons.Moodle {isAbsolute} />
|
<Icons.Moodle {isAbsolute} />
|
||||||
|
{:else if type === 'glitchTip'}
|
||||||
|
<Icons.GlitchTip {isAbsolute} />
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -15,4 +15,4 @@ export { default as Hasura } from './Hasura.svelte';
|
|||||||
export { default as Fider } from './Fider.svelte';
|
export { default as Fider } from './Fider.svelte';
|
||||||
export { default as Appwrite } from './Appwrite.svelte';
|
export { default as Appwrite } from './Appwrite.svelte';
|
||||||
export { default as Moodle } from './Moodle.svelte';
|
export { default as Moodle } from './Moodle.svelte';
|
||||||
|
export { default as GlitchTip } from './GlitchTip.svelte';
|
||||||
|
|||||||
@@ -159,7 +159,7 @@
|
|||||||
"storage_saved": "Storage saved.",
|
"storage_saved": "Storage saved.",
|
||||||
"storage_updated": "Storage updated.",
|
"storage_updated": "Storage updated.",
|
||||||
"storage_deleted": "Storage deleted.",
|
"storage_deleted": "Storage deleted.",
|
||||||
"persistent_storage_explainer": "You can specify any folder that you want to be persistent across deployments. <br>This is useful for storing data such as a database (SQLite) or a cache."
|
"persistent_storage_explainer": "You can specify any folder that you want to be persistent across deployments.<br><span class='text-green-500 font-bold'>/example</span> means it will preserve <span class='text-green-500 font-bold'>/app/example</span> in the container as <span class='text-green-500 font-bold'>/app</span> is <span class='text-green-500 font-bold'>the root directory</span> for your application.<br><br>This is useful for storing data such as a <span class='text-green-500 font-bold'>database (SQLite)</span> or a <span class='text-green-500 font-bold'>cache</span>."
|
||||||
},
|
},
|
||||||
"deployment_queued": "Deployment queued.",
|
"deployment_queued": "Deployment queued.",
|
||||||
"confirm_to_delete": "Are you sure you would like to delete '{{name}}'?",
|
"confirm_to_delete": "Are you sure you would like to delete '{{name}}'?",
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ export const setLocation = (resource: any, settings?: any) => {
|
|||||||
return location.set(resource.fqdn)
|
return location.set(resource.fqdn)
|
||||||
} else {
|
} else {
|
||||||
location.set(null);
|
location.set(null);
|
||||||
disabledButton.set(true);
|
disabledButton.set(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -77,9 +77,9 @@
|
|||||||
|
|
||||||
const { id } = $page.params;
|
const { id } = $page.params;
|
||||||
|
|
||||||
async function handleDeploySubmit() {
|
async function handleDeploySubmit(forceRebuild = false) {
|
||||||
try {
|
try {
|
||||||
const { buildId } = await post(`/applications/${id}/deploy`, { ...application });
|
const { buildId } = await post(`/applications/${id}/deploy`, { ...application, forceRebuild });
|
||||||
addToast({
|
addToast({
|
||||||
message: $t('application.deployment_queued'),
|
message: $t('application.deployment_queued'),
|
||||||
type: 'success'
|
type: 'success'
|
||||||
@@ -141,8 +141,7 @@
|
|||||||
if (
|
if (
|
||||||
application.gitSourceId &&
|
application.gitSourceId &&
|
||||||
application.destinationDockerId &&
|
application.destinationDockerId &&
|
||||||
(application.fqdn ||
|
(application.fqdn || application.settings.isBot)
|
||||||
application.settings.isBot)
|
|
||||||
) {
|
) {
|
||||||
await getStatus();
|
await getStatus();
|
||||||
statusInterval = setInterval(async () => {
|
statusInterval = setInterval(async () => {
|
||||||
@@ -179,9 +178,10 @@
|
|||||||
<polyline points="15 4 20 4 20 9" />
|
<polyline points="15 4 20 4 20 9" />
|
||||||
</svg></a
|
</svg></a
|
||||||
>
|
>
|
||||||
|
<div class="border border-coolgray-500 h-8" />
|
||||||
|
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div class="border border-coolgray-500 h-8" />
|
|
||||||
{#if $status.application.isExited}
|
{#if $status.application.isExited}
|
||||||
<a
|
<a
|
||||||
href={!$disabledButton ? `/applications/${id}/logs` : null}
|
href={!$disabledButton ? `/applications/${id}/logs` : null}
|
||||||
@@ -256,7 +256,7 @@
|
|||||||
<rect x="14" y="5" width="4" height="14" rx="1" />
|
<rect x="14" y="5" width="4" height="14" rx="1" />
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
<form on:submit|preventDefault={handleDeploySubmit}>
|
<form on:submit|preventDefault={() => handleDeploySubmit(true)}>
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={$disabledButton || !isQueueActive}
|
disabled={$disabledButton || !isQueueActive}
|
||||||
@@ -264,7 +264,7 @@
|
|||||||
class="icons bg-transparent tooltip tooltip-primary tooltip-bottom text-sm flex items-center space-x-2"
|
class="icons bg-transparent tooltip tooltip-primary tooltip-bottom text-sm flex items-center space-x-2"
|
||||||
data-tip={$appSession.isAdmin
|
data-tip={$appSession.isAdmin
|
||||||
? isQueueActive
|
? isQueueActive
|
||||||
? 'Rebuild Application'
|
? 'Force Rebuild Application'
|
||||||
: 'Autoupdate inprogress. Cannot rebuild application.'
|
: 'Autoupdate inprogress. Cannot rebuild application.'
|
||||||
: 'You do not have permission to rebuild application.'}
|
: 'You do not have permission to rebuild application.'}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
delete tempBuildPack.color;
|
delete tempBuildPack.color;
|
||||||
delete tempBuildPack.hoverColor;
|
delete tempBuildPack.hoverColor;
|
||||||
|
|
||||||
if (foundConfig.buildPack !== name) {
|
if (foundConfig?.buildPack !== name) {
|
||||||
await post(`/applications/${id}`, { ...tempBuildPack, buildPack: name });
|
await post(`/applications/${id}`, { ...tempBuildPack, buildPack: name });
|
||||||
}
|
}
|
||||||
await post(`/applications/${id}/configuration/buildpack`, { buildPack: name });
|
await post(`/applications/${id}/configuration/buildpack`, { buildPack: name });
|
||||||
|
|||||||
@@ -0,0 +1,199 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { get, post } from '$lib/api';
|
||||||
|
import { t } from '$lib/translations';
|
||||||
|
import { page } from '$app/stores';
|
||||||
|
|
||||||
|
import Select from 'svelte-select';
|
||||||
|
import Explainer from '$lib/components/Explainer.svelte';
|
||||||
|
import { goto } from '$app/navigation';
|
||||||
|
import { errorNotification } from '$lib/common';
|
||||||
|
|
||||||
|
const { id } = $page.params;
|
||||||
|
|
||||||
|
let publicRepositoryLink: string;
|
||||||
|
let projectId: number;
|
||||||
|
let repositoryName: string;
|
||||||
|
let branchName: string;
|
||||||
|
let ownerName: string;
|
||||||
|
let type: string;
|
||||||
|
let branchSelectOptions: any = [];
|
||||||
|
let loading = {
|
||||||
|
branches: false
|
||||||
|
};
|
||||||
|
async function loadBranches() {
|
||||||
|
try {
|
||||||
|
loading.branches = true;
|
||||||
|
|
||||||
|
const protocol = publicRepositoryLink.split(':')[0];
|
||||||
|
const gitUrl = publicRepositoryLink.replace('http://', '').replace('https://', '');
|
||||||
|
|
||||||
|
let [host, ...path] = gitUrl.split('/');
|
||||||
|
const [owner, repository, ...branch] = path;
|
||||||
|
|
||||||
|
ownerName = owner;
|
||||||
|
repositoryName = repository;
|
||||||
|
|
||||||
|
if (host === 'github.com') {
|
||||||
|
host = 'api.github.com';
|
||||||
|
type = 'github';
|
||||||
|
if (branch[0] === 'tree' && branch[1]) {
|
||||||
|
branchName = branch[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (host === 'gitlab.com') {
|
||||||
|
host = 'gitlab.com/api/v4';
|
||||||
|
type = 'gitlab';
|
||||||
|
if (branch[1] === 'tree' && branch[2]) {
|
||||||
|
branchName = branch[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const apiUrl = `${protocol}://${host}`;
|
||||||
|
if (type === 'github') {
|
||||||
|
const repositoryDetails = await get(`${apiUrl}/repos/${ownerName}/${repositoryName}`);
|
||||||
|
projectId = repositoryDetails.id.toString();
|
||||||
|
}
|
||||||
|
if (type === 'gitlab') {
|
||||||
|
const repositoryDetails = await get(`${apiUrl}/projects/${ownerName}%2F${repositoryName}`);
|
||||||
|
projectId = repositoryDetails.id.toString();
|
||||||
|
}
|
||||||
|
if (type === 'github' && branchName) {
|
||||||
|
try {
|
||||||
|
await get(`${apiUrl}/repos/${ownerName}/${repositoryName}/branches/${branchName}`);
|
||||||
|
await saveRepository();
|
||||||
|
loading.branches = false;
|
||||||
|
return;
|
||||||
|
} catch (error) {
|
||||||
|
errorNotification(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (type === 'gitlab' && branchName) {
|
||||||
|
try {
|
||||||
|
await get(
|
||||||
|
`${apiUrl}/projects/${ownerName}%2F${repositoryName}/repository/branches/${branchName}`
|
||||||
|
);
|
||||||
|
await saveRepository();
|
||||||
|
loading.branches = false;
|
||||||
|
return;
|
||||||
|
} catch (error) {
|
||||||
|
errorNotification(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let branches: any[] = [];
|
||||||
|
let page = 1;
|
||||||
|
let branchCount = 0;
|
||||||
|
const loadedBranches = await loadBranchesByPage(
|
||||||
|
apiUrl,
|
||||||
|
ownerName,
|
||||||
|
repositoryName,
|
||||||
|
page,
|
||||||
|
type
|
||||||
|
);
|
||||||
|
branches = branches.concat(loadedBranches);
|
||||||
|
branchCount = branches.length;
|
||||||
|
if (branchCount === 100) {
|
||||||
|
while (branchCount === 100) {
|
||||||
|
page = page + 1;
|
||||||
|
const nextBranches = await loadBranchesByPage(
|
||||||
|
apiUrl,
|
||||||
|
ownerName,
|
||||||
|
repositoryName,
|
||||||
|
page,
|
||||||
|
type
|
||||||
|
);
|
||||||
|
branches = branches.concat(nextBranches);
|
||||||
|
branchCount = nextBranches.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loading.branches = false;
|
||||||
|
branchSelectOptions = branches.map((branch: any) => ({
|
||||||
|
value: branch.name,
|
||||||
|
label: branch.name
|
||||||
|
}));
|
||||||
|
} catch (error) {
|
||||||
|
return errorNotification(error);
|
||||||
|
} finally {
|
||||||
|
loading.branches = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async function loadBranchesByPage(
|
||||||
|
apiUrl: string,
|
||||||
|
owner: string,
|
||||||
|
repository: string,
|
||||||
|
page = 1,
|
||||||
|
type: string
|
||||||
|
) {
|
||||||
|
if (type === 'github') {
|
||||||
|
return await get(`${apiUrl}/repos/${owner}/${repository}/branches?per_page=100&page=${page}`);
|
||||||
|
}
|
||||||
|
if (type === 'gitlab') {
|
||||||
|
return await get(
|
||||||
|
`${apiUrl}/projects/${ownerName}%2F${repositoryName}/repository/branches?page=${page}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async function saveRepository(event?: any) {
|
||||||
|
try {
|
||||||
|
if (event?.detail?.value) {
|
||||||
|
branchName = event.detail.value;
|
||||||
|
}
|
||||||
|
await post(`/applications/${id}/configuration/source`, {
|
||||||
|
gitSourceId: null,
|
||||||
|
forPublic: true,
|
||||||
|
type
|
||||||
|
});
|
||||||
|
await post(`/applications/${id}/configuration/repository`, {
|
||||||
|
repository: `${ownerName}/${repositoryName}`,
|
||||||
|
branch: branchName,
|
||||||
|
projectId,
|
||||||
|
autodeploy: false,
|
||||||
|
webhookToken: null,
|
||||||
|
isPublicRepository: true
|
||||||
|
});
|
||||||
|
|
||||||
|
return await goto(`/applications/${id}/configuration/destination`);
|
||||||
|
} catch (error) {
|
||||||
|
return errorNotification(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="mx-auto max-w-5xl">
|
||||||
|
<div class="grid grid-flow-row gap-2 px-10">
|
||||||
|
<div class="flex">
|
||||||
|
<form class="flex" on:submit|preventDefault={loadBranches}>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<input
|
||||||
|
placeholder="eg: https://github.com/coollabsio/nodejs-example/tree/main"
|
||||||
|
class="text-xs"
|
||||||
|
bind:value={publicRepositoryLink}
|
||||||
|
/>
|
||||||
|
{#if branchSelectOptions.length > 0}
|
||||||
|
<div class="custom-select-wrapper">
|
||||||
|
<Select
|
||||||
|
placeholder={loading.branches
|
||||||
|
? $t('application.configuration.loading_branches')
|
||||||
|
: !publicRepositoryLink
|
||||||
|
? $t('application.configuration.select_a_repository_first')
|
||||||
|
: $t('application.configuration.select_a_branch')}
|
||||||
|
isWaiting={loading.branches}
|
||||||
|
showIndicator={!!publicRepositoryLink && !loading.branches}
|
||||||
|
id="branches"
|
||||||
|
on:select={saveRepository}
|
||||||
|
items={branchSelectOptions}
|
||||||
|
isDisabled={loading.branches || !!!publicRepositoryLink}
|
||||||
|
isClearable={false}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button class="btn mx-4 bg-orange-600" class:loading={loading.branches} type="submit"
|
||||||
|
>Load Repository</button
|
||||||
|
>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Explainer
|
||||||
|
text="Examples:<br><br>https://github.com/coollabsio/nodejs-example<br>https://github.com/coollabsio/nodejs-example/tree/main<br>https://gitlab.com/aleveha/fastify-example<br>https://gitlab.com/aleveha/fastify-example/-/tree/master<br><br>Only works with Github.com and Gitlab.com."
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
@@ -47,6 +47,7 @@
|
|||||||
export let branch: any;
|
export let branch: any;
|
||||||
export let type: any;
|
export let type: any;
|
||||||
export let application: any;
|
export let application: any;
|
||||||
|
export let isPublicRepository: boolean;
|
||||||
|
|
||||||
function checkPackageJSONContents({ key, json }: { key: any; json: any }) {
|
function checkPackageJSONContents({ key, json }: { key: any; json: any }) {
|
||||||
return json?.dependencies?.hasOwnProperty(key) || json?.devDependencies?.hasOwnProperty(key);
|
return json?.dependencies?.hasOwnProperty(key) || json?.devDependencies?.hasOwnProperty(key);
|
||||||
@@ -236,7 +237,7 @@
|
|||||||
if (error.message === 'Bad credentials') {
|
if (error.message === 'Bad credentials') {
|
||||||
const { token } = await get(`/applications/${id}/configuration/githubToken`);
|
const { token } = await get(`/applications/${id}/configuration/githubToken`);
|
||||||
$appSession.tokens.github = token;
|
$appSession.tokens.github = token;
|
||||||
return await scanRepository()
|
return await scanRepository();
|
||||||
}
|
}
|
||||||
return errorNotification(error);
|
return errorNotification(error);
|
||||||
} finally {
|
} finally {
|
||||||
@@ -245,7 +246,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
await scanRepository();
|
if (!isPublicRepository) {
|
||||||
|
await scanRepository();
|
||||||
|
} else {
|
||||||
|
scanning = false;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -262,27 +267,25 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
|
<div class="max-w-5xl mx-auto ">
|
||||||
|
<div class="title pb-2">Coolify</div>
|
||||||
<div class="max-w-7xl mx-auto ">
|
|
||||||
<div class="title pb-2">Coolify Buildpacks</div>
|
|
||||||
<div class="flex flex-wrap justify-center">
|
<div class="flex flex-wrap justify-center">
|
||||||
{#each buildPacks.filter(bp => bp.isCoolifyBuildPack === true) as buildPack}
|
{#each buildPacks.filter((bp) => bp.isCoolifyBuildPack === true) as buildPack}
|
||||||
<div class="p-2">
|
<div class="p-2">
|
||||||
<BuildPack {packageManager} {buildPack} {scanning} bind:foundConfig />
|
<BuildPack {packageManager} {buildPack} {scanning} bind:foundConfig />
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="max-w-7xl mx-auto ">
|
<div class="max-w-5xl mx-auto ">
|
||||||
<div class="title pb-2">Heroku</div>
|
<div class="title pb-2">Other</div>
|
||||||
<div class="flex flex-wrap justify-center">
|
<div class="flex flex-wrap justify-center">
|
||||||
{#each buildPacks.filter(bp => bp.isHerokuBuildPack === true) as buildPack}
|
{#each buildPacks.filter((bp) => bp.isHerokuBuildPack === true) as buildPack}
|
||||||
<div class="p-2">
|
<div class="p-2">
|
||||||
<BuildPack {packageManager} {buildPack} {scanning} bind:foundConfig />
|
<BuildPack {packageManager} {buildPack} {scanning} bind:foundConfig />
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -48,3 +48,4 @@
|
|||||||
<GitlabRepositories {application} {appId} {settings} />
|
<GitlabRepositories {application} {appId} {settings} />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,8 @@
|
|||||||
import { t } from '$lib/translations';
|
import { t } from '$lib/translations';
|
||||||
import { errorNotification } from '$lib/common';
|
import { errorNotification } from '$lib/common';
|
||||||
import { appSession } from '$lib/store';
|
import { appSession } from '$lib/store';
|
||||||
|
import PublicRepository from './_PublicRepository.svelte';
|
||||||
|
import Explainer from '$lib/components/Explainer.svelte';
|
||||||
|
|
||||||
const { id } = $page.params;
|
const { id } = $page.params;
|
||||||
const from = $page.url.searchParams.get('from');
|
const from = $page.url.searchParams.get('from');
|
||||||
@@ -71,120 +73,126 @@
|
|||||||
{$t('application.configuration.select_a_git_source')}
|
{$t('application.configuration.select_a_git_source')}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col justify-center">
|
<div class="max-w-5xl mx-auto ">
|
||||||
{#if !filteredSources || ownSources.length === 0}
|
<div class="title pb-8">Git App</div>
|
||||||
<div class="flex-col">
|
<div class="flex flex-wrap justify-center">
|
||||||
<div class="pb-2 text-center font-bold">
|
{#if !filteredSources || ownSources.length === 0}
|
||||||
{$t('application.configuration.no_configurable_git')}
|
<div class="flex-col">
|
||||||
</div>
|
<div class="pb-2 text-center font-bold">
|
||||||
<div class="flex justify-center">
|
{$t('application.configuration.no_configurable_git')}
|
||||||
<a
|
</div>
|
||||||
href="/sources/new?from={$page.url.pathname}"
|
<div class="flex justify-center">
|
||||||
class="add-icon bg-orange-600 hover:bg-orange-500"
|
<a
|
||||||
>
|
href="/sources/new?from={$page.url.pathname}"
|
||||||
<svg
|
class="add-icon bg-orange-600 hover:bg-orange-500"
|
||||||
class="w-6"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
fill="none"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
stroke="currentColor"
|
|
||||||
><path
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
stroke-width="2"
|
|
||||||
d="M12 6v6m0 0v6m0-6h6m-6 0H6"
|
|
||||||
/></svg
|
|
||||||
>
|
>
|
||||||
</a>
|
<svg
|
||||||
|
class="w-6"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke="currentColor"
|
||||||
|
><path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M12 6v6m0 0v6m0-6h6m-6 0H6"
|
||||||
|
/></svg
|
||||||
|
>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{:else}
|
||||||
{:else}
|
<div class="flex flex-col flex-wrap justify-center px-2 md:flex-row ">
|
||||||
<div class="flex flex-col flex-wrap justify-center px-2 md:flex-row ">
|
{#each ownSources as source}
|
||||||
{#each ownSources as source}
|
<div class="p-2 relative">
|
||||||
<div class="p-2 relative">
|
<div class="absolute -m-4">
|
||||||
<div class="absolute -m-4">
|
{#if source?.type === 'gitlab'}
|
||||||
{#if source?.type === 'gitlab'}
|
<svg viewBox="0 0 128 128" class="w-8">
|
||||||
<svg viewBox="0 0 128 128" class="w-8">
|
<path
|
||||||
<path
|
fill="#FC6D26"
|
||||||
fill="#FC6D26"
|
d="M126.615 72.31l-7.034-21.647L105.64 7.76c-.716-2.206-3.84-2.206-4.556 0l-13.94 42.903H40.856L26.916 7.76c-.717-2.206-3.84-2.206-4.557 0L8.42 50.664 1.385 72.31a4.792 4.792 0 001.74 5.358L64 121.894l60.874-44.227a4.793 4.793 0 001.74-5.357"
|
||||||
d="M126.615 72.31l-7.034-21.647L105.64 7.76c-.716-2.206-3.84-2.206-4.556 0l-13.94 42.903H40.856L26.916 7.76c-.717-2.206-3.84-2.206-4.557 0L8.42 50.664 1.385 72.31a4.792 4.792 0 001.74 5.358L64 121.894l60.874-44.227a4.793 4.793 0 001.74-5.357"
|
/><path fill="#E24329" d="M64 121.894l23.144-71.23H40.856L64 121.893z" /><path
|
||||||
/><path fill="#E24329" d="M64 121.894l23.144-71.23H40.856L64 121.893z" /><path
|
fill="#FC6D26"
|
||||||
fill="#FC6D26"
|
d="M64 121.894l-23.144-71.23H8.42L64 121.893z"
|
||||||
d="M64 121.894l-23.144-71.23H8.42L64 121.893z"
|
|
||||||
/><path
|
|
||||||
fill="#FCA326"
|
|
||||||
d="M8.42 50.663L1.384 72.31a4.79 4.79 0 001.74 5.357L64 121.894 8.42 50.664z"
|
|
||||||
/><path
|
|
||||||
fill="#E24329"
|
|
||||||
d="M8.42 50.663h32.436L26.916 7.76c-.717-2.206-3.84-2.206-4.557 0L8.42 50.664z"
|
|
||||||
/><path fill="#FC6D26" d="M64 121.894l23.144-71.23h32.437L64 121.893z" /><path
|
|
||||||
fill="#FCA326"
|
|
||||||
d="M119.58 50.663l7.035 21.647a4.79 4.79 0 01-1.74 5.357L64 121.894l55.58-71.23z"
|
|
||||||
/><path
|
|
||||||
fill="#E24329"
|
|
||||||
d="M119.58 50.663H87.145l13.94-42.902c.717-2.206 3.84-2.206 4.557 0l13.94 42.903z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
{:else if source?.type === 'github'}
|
|
||||||
<svg viewBox="0 0 128 128" class="w-8">
|
|
||||||
<g fill="#ffffff"
|
|
||||||
><path
|
|
||||||
fill-rule="evenodd"
|
|
||||||
clip-rule="evenodd"
|
|
||||||
d="M64 5.103c-33.347 0-60.388 27.035-60.388 60.388 0 26.682 17.303 49.317 41.297 57.303 3.017.56 4.125-1.31 4.125-2.905 0-1.44-.056-6.197-.082-11.243-16.8 3.653-20.345-7.125-20.345-7.125-2.747-6.98-6.705-8.836-6.705-8.836-5.48-3.748.413-3.67.413-3.67 6.063.425 9.257 6.223 9.257 6.223 5.386 9.23 14.127 6.562 17.573 5.02.542-3.903 2.107-6.568 3.834-8.076-13.413-1.525-27.514-6.704-27.514-29.843 0-6.593 2.36-11.98 6.223-16.21-.628-1.52-2.695-7.662.584-15.98 0 0 5.07-1.623 16.61 6.19C53.7 35 58.867 34.327 64 34.304c5.13.023 10.3.694 15.127 2.033 11.526-7.813 16.59-6.19 16.59-6.19 3.287 8.317 1.22 14.46.593 15.98 3.872 4.23 6.215 9.617 6.215 16.21 0 23.194-14.127 28.3-27.574 29.796 2.167 1.874 4.097 5.55 4.097 11.183 0 8.08-.07 14.583-.07 16.572 0 1.607 1.088 3.49 4.148 2.897 23.98-7.994 41.263-30.622 41.263-57.294C124.388 32.14 97.35 5.104 64 5.104z"
|
|
||||||
/><path
|
/><path
|
||||||
d="M26.484 91.806c-.133.3-.605.39-1.035.185-.44-.196-.685-.605-.543-.906.13-.31.603-.395 1.04-.188.44.197.69.61.537.91zm2.446 2.729c-.287.267-.85.143-1.232-.28-.396-.42-.47-.983-.177-1.254.298-.266.844-.14 1.24.28.394.426.472.984.17 1.255zM31.312 98.012c-.37.258-.976.017-1.35-.52-.37-.538-.37-1.183.01-1.44.373-.258.97-.025 1.35.507.368.545.368 1.19-.01 1.452zm3.261 3.361c-.33.365-1.036.267-1.552-.23-.527-.487-.674-1.18-.343-1.544.336-.366 1.045-.264 1.564.23.527.486.686 1.18.333 1.543zm4.5 1.951c-.147.473-.825.688-1.51.486-.683-.207-1.13-.76-.99-1.238.14-.477.823-.7 1.512-.485.683.206 1.13.756.988 1.237zm4.943.361c.017.498-.563.91-1.28.92-.723.017-1.308-.387-1.315-.877 0-.503.568-.91 1.29-.924.717-.013 1.306.387 1.306.88zm4.598-.782c.086.485-.413.984-1.126 1.117-.7.13-1.35-.172-1.44-.653-.086-.498.422-.997 1.122-1.126.714-.123 1.354.17 1.444.663zm0 0"
|
fill="#FCA326"
|
||||||
/></g
|
d="M8.42 50.663L1.384 72.31a4.79 4.79 0 001.74 5.357L64 121.894 8.42 50.664z"
|
||||||
>
|
/><path
|
||||||
</svg>
|
fill="#E24329"
|
||||||
{/if}
|
d="M8.42 50.663h32.436L26.916 7.76c-.717-2.206-3.84-2.206-4.557 0L8.42 50.664z"
|
||||||
|
/><path fill="#FC6D26" d="M64 121.894l23.144-71.23h32.437L64 121.893z" /><path
|
||||||
|
fill="#FCA326"
|
||||||
|
d="M119.58 50.663l7.035 21.647a4.79 4.79 0 01-1.74 5.357L64 121.894l55.58-71.23z"
|
||||||
|
/><path
|
||||||
|
fill="#E24329"
|
||||||
|
d="M119.58 50.663H87.145l13.94-42.902c.717-2.206 3.84-2.206 4.557 0l13.94 42.903z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
{:else if source?.type === 'github'}
|
||||||
|
<svg viewBox="0 0 128 128" class="w-8">
|
||||||
|
<g fill="#ffffff"
|
||||||
|
><path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
d="M64 5.103c-33.347 0-60.388 27.035-60.388 60.388 0 26.682 17.303 49.317 41.297 57.303 3.017.56 4.125-1.31 4.125-2.905 0-1.44-.056-6.197-.082-11.243-16.8 3.653-20.345-7.125-20.345-7.125-2.747-6.98-6.705-8.836-6.705-8.836-5.48-3.748.413-3.67.413-3.67 6.063.425 9.257 6.223 9.257 6.223 5.386 9.23 14.127 6.562 17.573 5.02.542-3.903 2.107-6.568 3.834-8.076-13.413-1.525-27.514-6.704-27.514-29.843 0-6.593 2.36-11.98 6.223-16.21-.628-1.52-2.695-7.662.584-15.98 0 0 5.07-1.623 16.61 6.19C53.7 35 58.867 34.327 64 34.304c5.13.023 10.3.694 15.127 2.033 11.526-7.813 16.59-6.19 16.59-6.19 3.287 8.317 1.22 14.46.593 15.98 3.872 4.23 6.215 9.617 6.215 16.21 0 23.194-14.127 28.3-27.574 29.796 2.167 1.874 4.097 5.55 4.097 11.183 0 8.08-.07 14.583-.07 16.572 0 1.607 1.088 3.49 4.148 2.897 23.98-7.994 41.263-30.622 41.263-57.294C124.388 32.14 97.35 5.104 64 5.104z"
|
||||||
|
/><path
|
||||||
|
d="M26.484 91.806c-.133.3-.605.39-1.035.185-.44-.196-.685-.605-.543-.906.13-.31.603-.395 1.04-.188.44.197.69.61.537.91zm2.446 2.729c-.287.267-.85.143-1.232-.28-.396-.42-.47-.983-.177-1.254.298-.266.844-.14 1.24.28.394.426.472.984.17 1.255zM31.312 98.012c-.37.258-.976.017-1.35-.52-.37-.538-.37-1.183.01-1.44.373-.258.97-.025 1.35.507.368.545.368 1.19-.01 1.452zm3.261 3.361c-.33.365-1.036.267-1.552-.23-.527-.487-.674-1.18-.343-1.544.336-.366 1.045-.264 1.564.23.527.486.686 1.18.333 1.543zm4.5 1.951c-.147.473-.825.688-1.51.486-.683-.207-1.13-.76-.99-1.238.14-.477.823-.7 1.512-.485.683.206 1.13.756.988 1.237zm4.943.361c.017.498-.563.91-1.28.92-.723.017-1.308-.387-1.315-.877 0-.503.568-.91 1.29-.924.717-.013 1.306.387 1.306.88zm4.598-.782c.086.485-.413.984-1.126 1.117-.7.13-1.35-.172-1.44-.653-.086-.498.422-.997 1.122-1.126.714-.123 1.354.17 1.444.663zm0 0"
|
||||||
|
/></g
|
||||||
|
>
|
||||||
|
</svg>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
<form on:submit|preventDefault={() => handleSubmit(source.id)}>
|
||||||
|
<button
|
||||||
|
disabled={source.gitlabApp && !source.gitlabAppId}
|
||||||
|
type="submit"
|
||||||
|
class="disabled:opacity-95 bg-coolgray-200 disabled:text-white box-selection hover:bg-orange-700 group"
|
||||||
|
class:border-red-500={source.gitlabApp && !source.gitlabAppId}
|
||||||
|
class:border-0={source.gitlabApp && !source.gitlabAppId}
|
||||||
|
class:border-l-4={source.gitlabApp && !source.gitlabAppId}
|
||||||
|
>
|
||||||
|
<div class="font-bold text-xl text-center truncate">{source.name}</div>
|
||||||
|
{#if source.gitlabApp && !source.gitlabAppId}
|
||||||
|
<div class="font-bold text-center truncate text-red-500 group-hover:text-white">
|
||||||
|
Configuration missing
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<form on:submit|preventDefault={() => handleSubmit(source.id)}>
|
{/each}
|
||||||
<button
|
</div>
|
||||||
disabled={source.gitlabApp && !source.gitlabAppId}
|
|
||||||
type="submit"
|
|
||||||
class="disabled:opacity-95 bg-coolgray-200 disabled:text-white box-selection hover:bg-orange-700 group"
|
|
||||||
class:border-red-500={source.gitlabApp && !source.gitlabAppId}
|
|
||||||
class:border-0={source.gitlabApp && !source.gitlabAppId}
|
|
||||||
class:border-l-4={source.gitlabApp && !source.gitlabAppId}
|
|
||||||
>
|
|
||||||
<div class="font-bold text-xl text-center truncate">{source.name}</div>
|
|
||||||
{#if source.gitlabApp && !source.gitlabAppId}
|
|
||||||
<div class="font-bold text-center truncate text-red-500 group-hover:text-white">
|
|
||||||
Configuration missing
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{#if otherSources.length > 0 && $appSession.teamId === '0'}
|
{#if otherSources.length > 0 && $appSession.teamId === '0'}
|
||||||
<div class="px-6 pb-5 pt-10 text-xl font-bold">Other Sources</div>
|
<div class="px-6 pb-5 pt-10 text-xl font-bold">Other Sources</div>
|
||||||
|
{/if}
|
||||||
|
<div class="flex flex-col flex-wrap justify-center px-2 md:flex-row">
|
||||||
|
{#each otherSources as source}
|
||||||
|
<div class="p-2">
|
||||||
|
<form on:submit|preventDefault={() => handleSubmit(source.id)}>
|
||||||
|
<button
|
||||||
|
disabled={source.gitlabApp && !source.gitlabAppId}
|
||||||
|
type="submit"
|
||||||
|
class="disabled:opacity-95 bg-coolgray-200 disabled:text-white box-selection hover:bg-orange-700 group"
|
||||||
|
class:border-red-500={source.gitlabApp && !source.gitlabAppId}
|
||||||
|
class:border-0={source.gitlabApp && !source.gitlabAppId}
|
||||||
|
class:border-l-4={source.gitlabApp && !source.gitlabAppId}
|
||||||
|
>
|
||||||
|
<div class="font-bold text-xl text-center truncate">{source.name}</div>
|
||||||
|
{#if source.gitlabApp && !source.gitlabAppId}
|
||||||
|
<div class="font-bold text-center truncate text-red-500 group-hover:text-white">
|
||||||
|
{$t('application.configuration.configuration_missing')}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
<div class="flex flex-col flex-wrap justify-center px-2 md:flex-row">
|
</div>
|
||||||
{#each otherSources as source}
|
<div class="title py-4">Public Repository</div>
|
||||||
<div class="p-2">
|
|
||||||
<form on:submit|preventDefault={() => handleSubmit(source.id)}>
|
<PublicRepository />
|
||||||
<button
|
|
||||||
disabled={source.gitlabApp && !source.gitlabAppId}
|
|
||||||
type="submit"
|
|
||||||
class="disabled:opacity-95 bg-coolgray-200 disabled:text-white box-selection hover:bg-orange-700 group"
|
|
||||||
class:border-red-500={source.gitlabApp && !source.gitlabAppId}
|
|
||||||
class:border-0={source.gitlabApp && !source.gitlabAppId}
|
|
||||||
class:border-l-4={source.gitlabApp && !source.gitlabAppId}
|
|
||||||
>
|
|
||||||
<div class="font-bold text-xl text-center truncate">{source.name}</div>
|
|
||||||
{#if source.gitlabApp && !source.gitlabAppId}
|
|
||||||
<div class="font-bold text-center truncate text-red-500 group-hover:text-white">
|
|
||||||
{$t('application.configuration.configuration_missing')}
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -133,6 +133,7 @@
|
|||||||
autodeploy = !autodeploy;
|
autodeploy = !autodeploy;
|
||||||
}
|
}
|
||||||
if (name === 'isBot') {
|
if (name === 'isBot') {
|
||||||
|
if ($status.application.isRunning) return;
|
||||||
isBot = !isBot;
|
isBot = !isBot;
|
||||||
application.settings.isBot = isBot;
|
application.settings.isBot = isBot;
|
||||||
setLocation(application, settings);
|
setLocation(application, settings);
|
||||||
@@ -345,8 +346,11 @@
|
|||||||
<label for="gitSource" class="text-base font-bold text-stone-100"
|
<label for="gitSource" class="text-base font-bold text-stone-100"
|
||||||
>{$t('application.git_source')}</label
|
>{$t('application.git_source')}</label
|
||||||
>
|
>
|
||||||
{#if isDisabled}
|
{#if isDisabled || application.settings.isPublicRepository}
|
||||||
<input disabled={isDisabled} value={application.gitSource.name} />
|
<input
|
||||||
|
disabled={isDisabled || application.settings.isPublicRepository}
|
||||||
|
value={application.gitSource.name}
|
||||||
|
/>
|
||||||
{:else}
|
{:else}
|
||||||
<a
|
<a
|
||||||
href={`/applications/${id}/configuration/source?from=/applications/${id}`}
|
href={`/applications/${id}/configuration/source?from=/applications/${id}`}
|
||||||
@@ -363,8 +367,11 @@
|
|||||||
<label for="repository" class="text-base font-bold text-stone-100"
|
<label for="repository" class="text-base font-bold text-stone-100"
|
||||||
>{$t('application.git_repository')}</label
|
>{$t('application.git_repository')}</label
|
||||||
>
|
>
|
||||||
{#if isDisabled}
|
{#if isDisabled || application.settings.isPublicRepository}
|
||||||
<input disabled={isDisabled} value="{application.repository}/{application.branch}" />
|
<input
|
||||||
|
disabled={isDisabled || application.settings.isPublicRepository}
|
||||||
|
value="{application.repository}/{application.branch}"
|
||||||
|
/>
|
||||||
{:else}
|
{:else}
|
||||||
<a
|
<a
|
||||||
href={`/applications/${id}/configuration/repository?from=/applications/${id}&to=/applications/${id}/configuration/buildpack`}
|
href={`/applications/${id}/configuration/repository?from=/applications/${id}&to=/applications/${id}/configuration/buildpack`}
|
||||||
@@ -487,7 +494,8 @@
|
|||||||
bind:setting={isBot}
|
bind:setting={isBot}
|
||||||
on:click={() => changeSettings('isBot')}
|
on:click={() => changeSettings('isBot')}
|
||||||
title="Is your application a bot?"
|
title="Is your application a bot?"
|
||||||
description="You can deploy applications without domains. <br>They will listen on <span class='text-green-500 font-bold'>IP:EXPOSEDPORT</span> instead.<br></Setting><br>Useful to host <span class='text-green-500 font-bold'>Twitch bots.</span>"
|
description="You can deploy applications without domains. <br>You can also make them to listen on <span class='text-green-500 font-bold'>IP:EXPOSEDPORT</span> as well.<br></Setting><br>Useful to host <span class='text-green-500 font-bold'>Twitch bots, regular jobs, or anything that does not require an incoming connection.</span>"
|
||||||
|
disabled={$status.application.isRunning}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{#if !isBot}
|
{#if !isBot}
|
||||||
@@ -612,7 +620,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
{#if !staticDeployments.includes(application.buildPack) && !isBot}
|
{#if !staticDeployments.includes(application.buildPack)}
|
||||||
<div class="grid grid-cols-2 items-center">
|
<div class="grid grid-cols-2 items-center">
|
||||||
<label for="port" class="text-base font-bold text-stone-100">{$t('forms.port')}</label>
|
<label for="port" class="text-base font-bold text-stone-100">{$t('forms.port')}</label>
|
||||||
<input
|
<input
|
||||||
@@ -623,6 +631,9 @@
|
|||||||
bind:value={application.port}
|
bind:value={application.port}
|
||||||
placeholder="{$t('forms.default')}: 'python' ? '8000' : '3000'"
|
placeholder="{$t('forms.default')}: 'python' ? '8000' : '3000'"
|
||||||
/>
|
/>
|
||||||
|
<Explainer
|
||||||
|
text={'The port your application listens on.'}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
<div class="grid grid-cols-2 items-center">
|
<div class="grid grid-cols-2 items-center">
|
||||||
@@ -633,7 +644,6 @@
|
|||||||
name="exposePort"
|
name="exposePort"
|
||||||
id="exposePort"
|
id="exposePort"
|
||||||
bind:value={application.exposePort}
|
bind:value={application.exposePort}
|
||||||
required={isBot}
|
|
||||||
placeholder="12345"
|
placeholder="12345"
|
||||||
/>
|
/>
|
||||||
<Explainer
|
<Explainer
|
||||||
@@ -770,15 +780,17 @@
|
|||||||
<div class="title">{$t('application.features')}</div>
|
<div class="title">{$t('application.features')}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="px-10 pb-10">
|
<div class="px-10 pb-10">
|
||||||
<div class="grid grid-cols-2 items-center">
|
{#if !application.settings.isPublicRepository}
|
||||||
<Setting
|
<div class="grid grid-cols-2 items-center">
|
||||||
isCenter={false}
|
<Setting
|
||||||
bind:setting={autodeploy}
|
isCenter={false}
|
||||||
on:click={() => changeSettings('autodeploy')}
|
bind:setting={autodeploy}
|
||||||
title={$t('application.enable_automatic_deployment')}
|
on:click={() => changeSettings('autodeploy')}
|
||||||
description={$t('application.enable_auto_deploy_webhooks')}
|
title={$t('application.enable_automatic_deployment')}
|
||||||
/>
|
description={$t('application.enable_auto_deploy_webhooks')}
|
||||||
</div>
|
/>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
{#if !application.settings.isBot}
|
{#if !application.settings.isBot}
|
||||||
<div class="grid grid-cols-2 items-center">
|
<div class="grid grid-cols-2 items-center">
|
||||||
<Setting
|
<Setting
|
||||||
|
|||||||
@@ -109,7 +109,7 @@
|
|||||||
<div class="flex justify-end sticky top-0 p-2 mx-1">
|
<div class="flex justify-end sticky top-0 p-2 mx-1">
|
||||||
<button
|
<button
|
||||||
on:click={followBuild}
|
on:click={followBuild}
|
||||||
class="bg-transparent btn btn-sm tooltip tooltip-primary tooltip-bottom hover:text-green-500 hover:bg-coolgray-500"
|
class="bg-transparent btn btn-sm btn-link tooltip tooltip-primary tooltip-bottom hover:text-green-500 hover:bg-coolgray-500"
|
||||||
data-tip="Follow logs"
|
data-tip="Follow logs"
|
||||||
class:text-green-500={followingBuild}
|
class:text-green-500={followingBuild}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -147,7 +147,7 @@
|
|||||||
<div class="flex justify-end sticky top-0 p-1 mx-1">
|
<div class="flex justify-end sticky top-0 p-1 mx-1">
|
||||||
<button
|
<button
|
||||||
on:click={followBuild}
|
on:click={followBuild}
|
||||||
class="bg-transparent btn btn-sm tooltip tooltip-primary tooltip-bottom"
|
class="bg-transparent btn btn-sm btn-link tooltip tooltip-primary tooltip-bottom"
|
||||||
data-tip="Follow logs"
|
data-tip="Follow logs"
|
||||||
class:text-green-500={followingLogs}
|
class:text-green-500={followingLogs}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -87,9 +87,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mx-auto max-w-6xl rounded-xl px-6 pt-4">
|
<div class="mx-auto max-w-6xl rounded-xl px-6 pt-4">
|
||||||
<div class="flex justify-center py-4 text-center">
|
|
||||||
<Explainer customClass="w-full" text={$t('application.storage.persistent_storage_explainer')} />
|
|
||||||
</div>
|
|
||||||
<table class="mx-auto border-separate text-left">
|
<table class="mx-auto border-separate text-left">
|
||||||
<thead>
|
<thead>
|
||||||
<tr class="h-12">
|
<tr class="h-12">
|
||||||
@@ -109,4 +107,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
<div class="flex justify-center py-4 text-center">
|
||||||
|
<Explainer customClass="w-full" text={$t('application.storage.persistent_storage_explainer')} />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -63,4 +63,8 @@
|
|||||||
<a href="https://moodle.org" target="_blank">
|
<a href="https://moodle.org" target="_blank">
|
||||||
<Icons.Moodle />
|
<Icons.Moodle />
|
||||||
</a>
|
</a>
|
||||||
|
{:else if service.type === 'glitchTip'}
|
||||||
|
<a href="https://glitchtip.com" target="_blank">
|
||||||
|
<Icons.GlitchTip />
|
||||||
|
</a>
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import CopyPasswordField from '$lib/components/CopyPasswordField.svelte';
|
import CopyPasswordField from '$lib/components/CopyPasswordField.svelte';
|
||||||
|
import Explainer from '$lib/components/Explainer.svelte';
|
||||||
import { t } from '$lib/translations';
|
import { t } from '$lib/translations';
|
||||||
export let readOnly: any;
|
export let readOnly: any;
|
||||||
export let service: any;
|
export let service: any;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex space-x-1 py-5 font-bold">
|
<div class="flex space-x-1 py-5">
|
||||||
<div class="title">Ghost</div>
|
<div class="title">Ghost</div>
|
||||||
|
<Explainer text={'You can change these values in the Ghost admin panel.'} />
|
||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-2 items-center px-10">
|
<div class="grid grid-cols-2 items-center px-10">
|
||||||
<label for="email">{$t('forms.default_email_address')}</label>
|
<label for="email">{$t('forms.default_email_address')}</label>
|
||||||
|
|||||||
208
apps/ui/src/routes/services/[id]/_Services/_GlitchTip.svelte
Normal file
208
apps/ui/src/routes/services/[id]/_Services/_GlitchTip.svelte
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import CopyPasswordField from '$lib/components/CopyPasswordField.svelte';
|
||||||
|
import Explainer from '$lib/components/Explainer.svelte';
|
||||||
|
import Setting from '$lib/components/Setting.svelte';
|
||||||
|
import { t } from '$lib/translations';
|
||||||
|
export let service: any;
|
||||||
|
function toggleEmailSmtpUseTls() {
|
||||||
|
service.glitchTip.emailSmtpUseTls = !service.glitchTip.emailSmtpUseTls;
|
||||||
|
}
|
||||||
|
function toggleEmailSmtpUseSsl() {
|
||||||
|
service.glitchTip.emailSmtpUseSsl = !service.glitchTip.emailSmtpUseSsl;
|
||||||
|
}
|
||||||
|
function toggleEnableOpenUserRegistration() {
|
||||||
|
service.glitchTip.enableOpenUserRegistration = !service.glitchTip.enableOpenUserRegistration;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="flex space-x-1 py-5 font-bold">
|
||||||
|
<div class="title">GlitchTip</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex space-x-1 py-2 font-bold">
|
||||||
|
<div class="subtitle">Settings</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-2 items-center px-10">
|
||||||
|
<Setting
|
||||||
|
bind:setting={service.glitchTip.enableOpenUserRegistration}
|
||||||
|
on:click={toggleEnableOpenUserRegistration}
|
||||||
|
title={'Enable Open User Registration'}
|
||||||
|
description={''}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex space-x-1 py-2 font-bold">
|
||||||
|
<div class="subtitle">Email settings</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-2 items-center px-10">
|
||||||
|
<label for="defaultEmailFrom" class="text-base font-bold text-stone-100">Default Email From</label
|
||||||
|
>
|
||||||
|
<CopyPasswordField
|
||||||
|
required
|
||||||
|
name="defaultEmailFrom"
|
||||||
|
id="defaultEmailFrom"
|
||||||
|
value={service.glitchTip.defaultEmailFrom}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-2 items-center px-10">
|
||||||
|
<label for="emailSmtpHost" class="text-base font-bold text-stone-100">SMTP Host</label>
|
||||||
|
<CopyPasswordField
|
||||||
|
name="emailSmtpHost"
|
||||||
|
id="emailSmtpHost"
|
||||||
|
value={service.glitchTip.emailSmtpHost}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-2 items-center px-10">
|
||||||
|
<label for="emailSmtpPort" class="text-base font-bold text-stone-100">SMTP Port</label>
|
||||||
|
<CopyPasswordField
|
||||||
|
name="emailSmtpPort"
|
||||||
|
id="emailSmtpPort"
|
||||||
|
value={service.glitchTip.emailSmtpPort}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-2 items-center px-10">
|
||||||
|
<label for="emailSmtpUser" class="text-base font-bold text-stone-100">SMTP User</label>
|
||||||
|
<CopyPasswordField
|
||||||
|
name="emailSmtpUser"
|
||||||
|
id="emailSmtpUser"
|
||||||
|
value={service.glitchTip.emailSmtpUser}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-2 items-center px-10">
|
||||||
|
<label for="emailSmtpPassword" class="text-base font-bold text-stone-100">SMTP Password</label>
|
||||||
|
<CopyPasswordField
|
||||||
|
name="emailSmtpPassword"
|
||||||
|
id="emailSmtpPassword"
|
||||||
|
value={service.glitchTip.emailSmtpPassword}
|
||||||
|
isPasswordField
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-2 items-center px-10">
|
||||||
|
<Setting
|
||||||
|
bind:setting={service.glitchTip.emailSmtpUseTls}
|
||||||
|
on:click={toggleEmailSmtpUseTls}
|
||||||
|
title={'SMTP Use TLS'}
|
||||||
|
description={''}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-2 items-center px-10">
|
||||||
|
<Setting
|
||||||
|
bind:setting={service.glitchTip.emailSmtpUseSsl}
|
||||||
|
on:click={toggleEmailSmtpUseSsl}
|
||||||
|
title={'SMTP Use SSL'}
|
||||||
|
description={''}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-2 items-center px-10">
|
||||||
|
<label for="emailBackend" class="text-base font-bold text-stone-100">Email Backend</label>
|
||||||
|
<CopyPasswordField name="emailBackend" id="emailBackend" value={service.glitchTip.emailBackend} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-2 items-center px-10">
|
||||||
|
<label for="mailgunApiKey" class="text-base font-bold text-stone-100">Mailgun API Key</label>
|
||||||
|
<CopyPasswordField
|
||||||
|
name="mailgunApiKey"
|
||||||
|
id="mailgunApiKey"
|
||||||
|
value={service.glitchTip.mailgunApiKey}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-2 items-center px-10">
|
||||||
|
<label for="sendgridApiKey" class="text-base font-bold text-stone-100">SendGrid API Key</label>
|
||||||
|
<CopyPasswordField
|
||||||
|
name="sendgridApiKey"
|
||||||
|
id="sendgridApiKey"
|
||||||
|
value={service.glitchTip.sendgridApiKey}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex space-x-1 py-2 font-bold">
|
||||||
|
<div class="subtitle">Default User & Superuser</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-2 items-center px-10">
|
||||||
|
<label for="defaultEmail" class="text-base font-bold text-stone-100">{$t('forms.email')}</label>
|
||||||
|
<CopyPasswordField
|
||||||
|
name="defaultEmail"
|
||||||
|
id="defaultEmail"
|
||||||
|
value={service.glitchTip.defaultEmail}
|
||||||
|
readonly
|
||||||
|
disabled
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 items-center px-10">
|
||||||
|
<label for="defaultUsername" class="text-base font-bold text-stone-100"
|
||||||
|
>{$t('forms.username')}</label
|
||||||
|
>
|
||||||
|
<CopyPasswordField
|
||||||
|
name="defaultUsername"
|
||||||
|
id="defaultUsername"
|
||||||
|
value={service.glitchTip.defaultUsername}
|
||||||
|
readonly
|
||||||
|
disabled
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 items-center px-10">
|
||||||
|
<label for="defaultPassword" class="text-base font-bold text-stone-100"
|
||||||
|
>{$t('forms.password')}</label
|
||||||
|
>
|
||||||
|
<CopyPasswordField
|
||||||
|
name="defaultPassword"
|
||||||
|
id="defaultPassword"
|
||||||
|
value={service.glitchTip.defaultPassword}
|
||||||
|
readonly
|
||||||
|
disabled
|
||||||
|
isPasswordField
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex space-x-1 py-5 font-bold">
|
||||||
|
<div class="title">PostgreSQL</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-2 items-center px-10">
|
||||||
|
<label for="postgresqlUser" class="text-base font-bold text-stone-100"
|
||||||
|
>{$t('forms.username')}</label
|
||||||
|
>
|
||||||
|
<CopyPasswordField
|
||||||
|
name="postgresqlUser"
|
||||||
|
id="postgresqlUser"
|
||||||
|
value={service.glitchTip.postgresqlUser}
|
||||||
|
readonly
|
||||||
|
disabled
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 items-center px-10">
|
||||||
|
<label for="postgresqlPassword" class="text-base font-bold text-stone-100"
|
||||||
|
>{$t('forms.password')}</label
|
||||||
|
>
|
||||||
|
<CopyPasswordField
|
||||||
|
id="postgresqlPassword"
|
||||||
|
isPasswordField
|
||||||
|
readonly
|
||||||
|
disabled
|
||||||
|
name="postgresqlPassword"
|
||||||
|
value={service.glitchTip.postgresqlPassword}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 items-center px-10">
|
||||||
|
<label for="postgresqlDatabase" class="text-base font-bold text-stone-100"
|
||||||
|
>{$t('index.database')}</label
|
||||||
|
>
|
||||||
|
<CopyPasswordField
|
||||||
|
name="postgresqlDatabase"
|
||||||
|
id="postgresqlDatabase"
|
||||||
|
value={service.glitchTip.postgresqlDatabase}
|
||||||
|
readonly
|
||||||
|
disabled
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
import Fider from './_Fider.svelte';
|
import Fider from './_Fider.svelte';
|
||||||
import Ghost from './_Ghost.svelte';
|
import Ghost from './_Ghost.svelte';
|
||||||
|
import GlitchTip from './_GlitchTip.svelte';
|
||||||
import Hasura from './_Hasura.svelte';
|
import Hasura from './_Hasura.svelte';
|
||||||
import MeiliSearch from './_MeiliSearch.svelte';
|
import MeiliSearch from './_MeiliSearch.svelte';
|
||||||
import MinIo from './_MinIO.svelte';
|
import MinIo from './_MinIO.svelte';
|
||||||
@@ -399,6 +400,8 @@
|
|||||||
<Appwrite bind:service {readOnly} />
|
<Appwrite bind:service {readOnly} />
|
||||||
{:else if service.type === 'moodle'}
|
{:else if service.type === 'moodle'}
|
||||||
<Moodle bind:service {readOnly} />
|
<Moodle bind:service {readOnly} />
|
||||||
|
{:else if service.type === 'glitchTip'}
|
||||||
|
<GlitchTip bind:service />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "coolify",
|
"name": "coolify",
|
||||||
"description": "An open-source & self-hostable Heroku / Netlify alternative.",
|
"description": "An open-source & self-hostable Heroku / Netlify alternative.",
|
||||||
"version": "3.5.1",
|
"version": "3.7.0",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"repository": "github:coollabsio/coolify",
|
"repository": "github:coollabsio/coolify",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
Reference in New Issue
Block a user