fix: update prisma
feat(beta): database branching
This commit is contained in:
parent
c9aecd51f3
commit
5a15e64471
@ -15,7 +15,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@breejs/ts-worker": "2.0.0",
|
||||
"@fastify/autoload": "5.2.0",
|
||||
"@fastify/autoload": "5.3.1",
|
||||
"@fastify/cookie": "8.1.0",
|
||||
"@fastify/cors": "8.1.0",
|
||||
"@fastify/env": "4.1.0",
|
||||
@ -23,7 +23,7 @@
|
||||
"@fastify/static": "6.5.0",
|
||||
"@iarna/toml": "2.2.5",
|
||||
"@ladjs/graceful": "3.0.2",
|
||||
"@prisma/client": "3.15.2",
|
||||
"@prisma/client": "4.3.1",
|
||||
"axios": "0.27.2",
|
||||
"bcryptjs": "2.4.3",
|
||||
"bree": "9.1.2",
|
||||
@ -37,7 +37,7 @@
|
||||
"fastify": "4.5.3",
|
||||
"fastify-plugin": "4.2.1",
|
||||
"generate-password": "1.7.0",
|
||||
"got": "12.3.1",
|
||||
"got": "12.4.1",
|
||||
"is-ip": "5.0.0",
|
||||
"is-port-reachable": "4.0.0",
|
||||
"js-yaml": "4.1.0",
|
||||
@ -52,20 +52,20 @@
|
||||
"unique-names-generator": "4.7.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "18.7.13",
|
||||
"@types/node": "18.7.15",
|
||||
"@types/node-os-utils": "1.3.0",
|
||||
"@typescript-eslint/eslint-plugin": "5.35.1",
|
||||
"@typescript-eslint/parser": "5.35.1",
|
||||
"esbuild": "0.15.5",
|
||||
"@typescript-eslint/eslint-plugin": "5.36.1",
|
||||
"@typescript-eslint/parser": "5.36.1",
|
||||
"esbuild": "0.15.7",
|
||||
"eslint": "8.23.0",
|
||||
"eslint-config-prettier": "8.5.0",
|
||||
"eslint-plugin-prettier": "4.2.1",
|
||||
"nodemon": "2.0.19",
|
||||
"prettier": "2.7.1",
|
||||
"prisma": "3.15.2",
|
||||
"prisma": "4.3.1",
|
||||
"rimraf": "3.0.2",
|
||||
"tsconfig-paths": "4.1.0",
|
||||
"typescript": "4.7.4"
|
||||
"typescript": "4.8.2"
|
||||
},
|
||||
"prisma": {
|
||||
"seed": "node prisma/seed.js"
|
||||
|
@ -0,0 +1,20 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to alter the column `time` on the `BuildLog` table. The data in that column could be lost. The data in that column will be cast from `Int` to `BigInt`.
|
||||
|
||||
*/
|
||||
-- RedefineTables
|
||||
PRAGMA foreign_keys=OFF;
|
||||
CREATE TABLE "new_BuildLog" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"applicationId" TEXT,
|
||||
"buildId" TEXT NOT NULL,
|
||||
"line" TEXT NOT NULL,
|
||||
"time" BIGINT NOT NULL
|
||||
);
|
||||
INSERT INTO "new_BuildLog" ("applicationId", "buildId", "id", "line", "time") SELECT "applicationId", "buildId", "id", "line", "time" FROM "BuildLog";
|
||||
DROP TABLE "BuildLog";
|
||||
ALTER TABLE "new_BuildLog" RENAME TO "BuildLog";
|
||||
PRAGMA foreign_key_check;
|
||||
PRAGMA foreign_keys=ON;
|
@ -0,0 +1,20 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "ApplicationConnectedDatabase" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"applicationId" TEXT NOT NULL,
|
||||
"databaseId" TEXT,
|
||||
"hostedDatabaseType" TEXT,
|
||||
"hostedDatabaseHost" TEXT,
|
||||
"hostedDatabasePort" INTEGER,
|
||||
"hostedDatabaseName" TEXT,
|
||||
"hostedDatabaseUser" TEXT,
|
||||
"hostedDatabasePassword" TEXT,
|
||||
"hostedDatabaseDBName" TEXT,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" DATETIME NOT NULL,
|
||||
CONSTRAINT "ApplicationConnectedDatabase_databaseId_fkey" FOREIGN KEY ("databaseId") REFERENCES "Database" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
|
||||
CONSTRAINT "ApplicationConnectedDatabase_applicationId_fkey" FOREIGN KEY ("applicationId") REFERENCES "Application" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "ApplicationConnectedDatabase_applicationId_key" ON "ApplicationConnectedDatabase"("applicationId");
|
@ -117,6 +117,24 @@ model Application {
|
||||
settings ApplicationSettings?
|
||||
secrets Secret[]
|
||||
teams Team[]
|
||||
connectedDatabase ApplicationConnectedDatabase?
|
||||
}
|
||||
|
||||
model ApplicationConnectedDatabase {
|
||||
id String @id @default(cuid())
|
||||
applicationId String @unique
|
||||
databaseId String?
|
||||
hostedDatabaseType String?
|
||||
hostedDatabaseHost String?
|
||||
hostedDatabasePort Int?
|
||||
hostedDatabaseName String?
|
||||
hostedDatabaseUser String?
|
||||
hostedDatabasePassword String?
|
||||
hostedDatabaseDBName String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
database Database? @relation(fields: [databaseId], references: [id])
|
||||
application Application @relation(fields: [applicationId], references: [id])
|
||||
}
|
||||
|
||||
model ApplicationSettings {
|
||||
@ -187,7 +205,7 @@ model BuildLog {
|
||||
applicationId String?
|
||||
buildId String
|
||||
line String
|
||||
time Int
|
||||
time BigInt
|
||||
}
|
||||
|
||||
model Build {
|
||||
@ -292,22 +310,23 @@ model GitlabApp {
|
||||
}
|
||||
|
||||
model Database {
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
publicPort Int?
|
||||
defaultDatabase String?
|
||||
type String?
|
||||
version String?
|
||||
dbUser String?
|
||||
dbUserPassword String?
|
||||
rootUser String?
|
||||
rootUserPassword String?
|
||||
destinationDockerId String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
destinationDocker DestinationDocker? @relation(fields: [destinationDockerId], references: [id])
|
||||
settings DatabaseSettings?
|
||||
teams Team[]
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
publicPort Int?
|
||||
defaultDatabase String?
|
||||
type String?
|
||||
version String?
|
||||
dbUser String?
|
||||
dbUserPassword String?
|
||||
rootUser String?
|
||||
rootUserPassword String?
|
||||
destinationDockerId String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
destinationDocker DestinationDocker? @relation(fields: [destinationDockerId], references: [id])
|
||||
settings DatabaseSettings?
|
||||
teams Team[]
|
||||
applicationConnectedDatabase ApplicationConnectedDatabase[]
|
||||
}
|
||||
|
||||
model DatabaseSettings {
|
||||
|
@ -156,7 +156,8 @@ export async function getApplicationFromDB(id: string, teamId: string) {
|
||||
settings: true,
|
||||
gitSource: { include: { githubApp: true, gitlabApp: true } },
|
||||
secrets: true,
|
||||
persistentStorage: true
|
||||
persistentStorage: true,
|
||||
connectedDatabase: true
|
||||
}
|
||||
});
|
||||
if (!application) {
|
||||
@ -190,7 +191,8 @@ export async function getApplicationFromDBWebhook(projectId: number, branch: str
|
||||
settings: true,
|
||||
gitSource: { include: { githubApp: true, gitlabApp: true } },
|
||||
secrets: true,
|
||||
persistentStorage: true
|
||||
persistentStorage: true,
|
||||
connectedDatabase: true
|
||||
}
|
||||
});
|
||||
if (applications.length === 0) {
|
||||
@ -242,7 +244,8 @@ export async function saveApplication(request: FastifyRequest<SaveApplication>,
|
||||
denoOptions,
|
||||
baseImage,
|
||||
baseBuildImage,
|
||||
deploymentType
|
||||
deploymentType,
|
||||
baseDatabaseBranch
|
||||
} = request.body
|
||||
if (port) port = Number(port);
|
||||
if (exposePort) {
|
||||
@ -263,22 +266,43 @@ export async function saveApplication(request: FastifyRequest<SaveApplication>,
|
||||
dockerFileLocation,
|
||||
denoMainFile
|
||||
});
|
||||
await prisma.application.update({
|
||||
where: { id },
|
||||
data: {
|
||||
name,
|
||||
fqdn,
|
||||
exposePort,
|
||||
pythonWSGI,
|
||||
pythonModule,
|
||||
pythonVariable,
|
||||
denoOptions,
|
||||
baseImage,
|
||||
baseBuildImage,
|
||||
deploymentType,
|
||||
...defaultConfiguration
|
||||
}
|
||||
});
|
||||
if (baseDatabaseBranch) {
|
||||
await prisma.application.update({
|
||||
where: { id },
|
||||
data: {
|
||||
name,
|
||||
fqdn,
|
||||
exposePort,
|
||||
pythonWSGI,
|
||||
pythonModule,
|
||||
pythonVariable,
|
||||
denoOptions,
|
||||
baseImage,
|
||||
baseBuildImage,
|
||||
deploymentType,
|
||||
...defaultConfiguration,
|
||||
connectedDatabase: { update: { hostedDatabaseDBName: baseDatabaseBranch } }
|
||||
}
|
||||
});
|
||||
} else {
|
||||
await prisma.application.update({
|
||||
where: { id },
|
||||
data: {
|
||||
name,
|
||||
fqdn,
|
||||
exposePort,
|
||||
pythonWSGI,
|
||||
pythonModule,
|
||||
pythonVariable,
|
||||
denoOptions,
|
||||
baseImage,
|
||||
baseBuildImage,
|
||||
deploymentType,
|
||||
...defaultConfiguration
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return reply.code(201).send();
|
||||
} catch ({ status, message }) {
|
||||
return errorHandler({ status, message })
|
||||
@ -289,7 +313,7 @@ export async function saveApplication(request: FastifyRequest<SaveApplication>,
|
||||
export async function saveApplicationSettings(request: FastifyRequest<SaveApplicationSettings>, reply: FastifyReply) {
|
||||
try {
|
||||
const { id } = request.params
|
||||
const { debug, previews, dualCerts, autodeploy, branch, projectId, isBot } = request.body
|
||||
const { debug, previews, dualCerts, autodeploy, branch, projectId, isBot, isDBBranching } = request.body
|
||||
// const isDouble = await checkDoubleBranch(branch, projectId);
|
||||
// if (isDouble && autodeploy) {
|
||||
// await prisma.applicationSettings.updateMany({ where: { application: { branch, projectId } }, data: { autodeploy: false } })
|
||||
@ -297,7 +321,7 @@ export async function saveApplicationSettings(request: FastifyRequest<SaveApplic
|
||||
// }
|
||||
await prisma.application.update({
|
||||
where: { id },
|
||||
data: { fqdn: isBot ? null : undefined, settings: { update: { debug, previews, dualCerts, autodeploy, isBot } } },
|
||||
data: { fqdn: isBot ? null : undefined, settings: { update: { debug, previews, dualCerts, autodeploy, isBot, isDBBranching } } },
|
||||
include: { destinationDocker: true }
|
||||
});
|
||||
return reply.code(201).send();
|
||||
@ -478,6 +502,7 @@ export async function deleteApplication(request: FastifyRequest<DeleteApplicatio
|
||||
await prisma.build.deleteMany({ where: { applicationId: id } });
|
||||
await prisma.secret.deleteMany({ where: { applicationId: id } });
|
||||
await prisma.applicationPersistentStorage.deleteMany({ where: { applicationId: id } });
|
||||
await prisma.applicationConnectedDatabase.deleteMany({ where: { applicationId: id } });
|
||||
if (teamId === '0') {
|
||||
await prisma.application.deleteMany({ where: { id } });
|
||||
} else {
|
||||
@ -738,6 +763,17 @@ export async function saveBuildPack(request, reply) {
|
||||
return errorHandler({ status, message })
|
||||
}
|
||||
}
|
||||
export async function saveConnectedDatabase(request, reply) {
|
||||
try {
|
||||
const { id } = request.params
|
||||
const { databaseId, type } = request.body
|
||||
console.log({ databaseId, type })
|
||||
await prisma.application.update({ where: { id }, data: { connectedDatabase: { upsert: { create: { database: { connect: { id: databaseId } }, hostedDatabaseType: type }, update: { database: { connect: { id: databaseId } }, hostedDatabaseType: type } } } } })
|
||||
return reply.code(201).send()
|
||||
} catch ({ status, message }) {
|
||||
return errorHandler({ status, message })
|
||||
}
|
||||
}
|
||||
|
||||
export async function getSecrets(request: FastifyRequest<OnlyId>) {
|
||||
try {
|
||||
@ -986,11 +1022,13 @@ export async function getBuildIdLogs(request: FastifyRequest<GetBuildIdLogs>) {
|
||||
where: { buildId, time: { gt: sequence } },
|
||||
orderBy: { time: 'asc' }
|
||||
});
|
||||
|
||||
const data = await prisma.build.findFirst({ where: { id: buildId } });
|
||||
const createdAt = day(data.createdAt).utc();
|
||||
return {
|
||||
logs,
|
||||
logs: logs.map(log => {
|
||||
log.time = Number(log.time)
|
||||
return log
|
||||
}),
|
||||
took: day().diff(createdAt) / 1000,
|
||||
status: data?.status || 'queued'
|
||||
}
|
||||
@ -1067,3 +1105,58 @@ export async function cancelDeployment(request: FastifyRequest<CancelDeployment>
|
||||
return errorHandler({ status, message })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export async function createdBranchDatabase(database: any, baseDatabaseBranch: string, pullmergeRequestId: string) {
|
||||
try {
|
||||
if (!baseDatabaseBranch) return
|
||||
const { id, type, destinationDockerId, rootUser, rootUserPassword, dbUser } = database;
|
||||
if (destinationDockerId) {
|
||||
if (type === 'postgresql') {
|
||||
const decryptedRootUserPassword = decrypt(rootUserPassword);
|
||||
await executeDockerCmd({
|
||||
dockerId: destinationDockerId,
|
||||
command: `docker exec ${id} pg_dump -d "postgresql://postgres:${decryptedRootUserPassword}@${id}:5432/${baseDatabaseBranch}" --encoding=UTF8 --schema-only -f /tmp/${baseDatabaseBranch}.dump`
|
||||
})
|
||||
await executeDockerCmd({
|
||||
dockerId: destinationDockerId,
|
||||
command: `docker exec ${id} psql postgresql://postgres:${decryptedRootUserPassword}@${id}:5432 -c "CREATE DATABASE branch_${pullmergeRequestId}"`
|
||||
})
|
||||
await executeDockerCmd({
|
||||
dockerId: destinationDockerId,
|
||||
command: `docker exec ${id} psql -d "postgresql://postgres:${decryptedRootUserPassword}@${id}:5432/branch_${pullmergeRequestId}" -f /tmp/${baseDatabaseBranch}.dump`
|
||||
})
|
||||
await executeDockerCmd({
|
||||
dockerId: destinationDockerId,
|
||||
command: `docker exec ${id} psql postgresql://postgres:${decryptedRootUserPassword}@${id}:5432 -c "ALTER DATABASE branch_${pullmergeRequestId} OWNER TO ${dbUser}"`
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} catch ({ status, message }) {
|
||||
return errorHandler({ status, message })
|
||||
}
|
||||
}
|
||||
export async function removeBranchDatabase(database: any, pullmergeRequestId: string) {
|
||||
try {
|
||||
const { id, type, destinationDockerId, rootUser, rootUserPassword } = database;
|
||||
if (destinationDockerId) {
|
||||
if (type === 'postgresql') {
|
||||
const decryptedRootUserPassword = decrypt(rootUserPassword);
|
||||
// Terminate all connections to the database
|
||||
await executeDockerCmd({
|
||||
dockerId: destinationDockerId,
|
||||
command: `docker exec ${id} psql postgresql://postgres:${decryptedRootUserPassword}@${id}:5432 -c "SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity WHERE pg_stat_activity.datname = 'branch_${pullmergeRequestId}' AND pid <> pg_backend_pid();"`
|
||||
})
|
||||
|
||||
await executeDockerCmd({
|
||||
dockerId: destinationDockerId,
|
||||
command: `docker exec ${id} psql postgresql://postgres:${decryptedRootUserPassword}@${id}:5432 -c "DROP DATABASE branch_${pullmergeRequestId}"`
|
||||
})
|
||||
}
|
||||
}
|
||||
} catch ({ status, message }) {
|
||||
return errorHandler({ status, message })
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
import { FastifyPluginAsync } from 'fastify';
|
||||
import { OnlyId } from '../../../../types';
|
||||
import { cancelDeployment, checkDNS, checkDomain, checkRepository, deleteApplication, deleteSecret, deleteStorage, deployApplication, getApplication, getApplicationLogs, getApplicationStatus, getBuildIdLogs, getBuildLogs, getBuildPack, getGitHubToken, getGitLabSSHKey, getImages, getPreviews, getSecrets, getStorages, getUsage, listApplications, newApplication, restartApplication, saveApplication, saveApplicationSettings, saveApplicationSource, saveBuildPack, saveDeployKey, saveDestination, saveGitLabSSHKey, saveRepository, saveSecret, saveStorage, stopApplication, stopPreviewApplication } from './handlers';
|
||||
import { cancelDeployment, checkDNS, checkDomain, checkRepository, deleteApplication, deleteSecret, deleteStorage, deployApplication, getApplication, getApplicationLogs, getApplicationStatus, getBuildIdLogs, getBuildLogs, getBuildPack, getGitHubToken, getGitLabSSHKey, getImages, getPreviews, getSecrets, getStorages, getUsage, listApplications, newApplication, restartApplication, saveApplication, saveApplicationSettings, saveApplicationSource, saveBuildPack, saveConnectedDatabase, saveDeployKey, saveDestination, saveGitLabSSHKey, saveRepository, saveSecret, saveStorage, stopApplication, stopPreviewApplication } from './handlers';
|
||||
|
||||
import type { CancelDeployment, CheckDNS, CheckDomain, CheckRepository, DeleteApplication, DeleteSecret, DeleteStorage, DeployApplication, GetApplicationLogs, GetBuildIdLogs, GetBuildLogs, GetImages, SaveApplication, SaveApplicationSettings, SaveApplicationSource, SaveDeployKey, SaveDestination, SaveSecret, SaveStorage, StopPreviewApplication } from './types';
|
||||
|
||||
@ -55,6 +55,8 @@ const root: FastifyPluginAsync = async (fastify): Promise<void> => {
|
||||
fastify.get('/:id/configuration/buildpack', async (request) => await getBuildPack(request));
|
||||
fastify.post('/:id/configuration/buildpack', async (request, reply) => await saveBuildPack(request, reply));
|
||||
|
||||
fastify.post('/:id/configuration/database', async (request, reply) => await saveConnectedDatabase(request, reply));
|
||||
|
||||
fastify.get<OnlyId>('/:id/configuration/sshkey', async (request) => await getGitLabSSHKey(request));
|
||||
fastify.post<OnlyId>('/:id/configuration/sshkey', async (request, reply) => await saveGitLabSSHKey(request, reply));
|
||||
|
||||
|
@ -20,12 +20,13 @@ export interface SaveApplication extends OnlyId {
|
||||
denoOptions: string,
|
||||
baseImage: string,
|
||||
baseBuildImage: string,
|
||||
deploymentType: string
|
||||
deploymentType: string,
|
||||
baseDatabaseBranch: string
|
||||
}
|
||||
}
|
||||
export interface SaveApplicationSettings extends OnlyId {
|
||||
Querystring: { domain: string; };
|
||||
Body: { debug: boolean; previews: boolean; dualCerts: boolean; autodeploy: boolean; branch: string; projectId: number; isBot: boolean; };
|
||||
Body: { debug: boolean; previews: boolean; dualCerts: boolean; autodeploy: boolean; branch: string; projectId: number; isBot: boolean; isDBBranching: boolean };
|
||||
}
|
||||
export interface DeleteApplication extends OnlyId {
|
||||
Querystring: { domain: string; };
|
||||
|
@ -3,8 +3,7 @@ import cuid from "cuid";
|
||||
import crypto from "crypto";
|
||||
import { encrypt, errorHandler, getUIUrl, isDev, prisma } from "../../../lib/common";
|
||||
import { checkContainer, removeContainer } from "../../../lib/docker";
|
||||
import { scheduler } from "../../../lib/scheduler";
|
||||
import { getApplicationFromDBWebhook } from "../../api/v1/applications/handlers";
|
||||
import { createdBranchDatabase, getApplicationFromDBWebhook, removeBranchDatabase } from "../../api/v1/applications/handlers";
|
||||
|
||||
import type { FastifyReply, FastifyRequest } from "fastify";
|
||||
import type { GitHubEvents, InstallGithub } from "./types";
|
||||
@ -67,7 +66,6 @@ export async function configureGitHubApp(request, reply) {
|
||||
}
|
||||
export async function gitHubEvents(request: FastifyRequest<GitHubEvents>): Promise<any> {
|
||||
try {
|
||||
|
||||
const allowedGithubEvents = ['push', 'pull_request'];
|
||||
const allowedActions = ['opened', 'reopened', 'synchronize', 'closed'];
|
||||
const githubEvent = request.headers['x-github-event']?.toString().toLowerCase();
|
||||
@ -133,8 +131,6 @@ export async function gitHubEvents(request: FastifyRequest<GitHubEvents>): Promi
|
||||
where: { id: application.id },
|
||||
data: { updatedAt: new Date() }
|
||||
});
|
||||
console.log(application.id)
|
||||
|
||||
await prisma.build.create({
|
||||
data: {
|
||||
id: buildId,
|
||||
@ -178,6 +174,16 @@ export async function gitHubEvents(request: FastifyRequest<GitHubEvents>): Promi
|
||||
where: { id: application.id },
|
||||
data: { updatedAt: new Date() }
|
||||
});
|
||||
if (application.connectedDatabase && pullmergeRequestAction === 'opened' || pullmergeRequestAction === 'reopened') {
|
||||
// Coolify hosted database
|
||||
if (application.connectedDatabase.databaseId) {
|
||||
const databaseId = application.connectedDatabase.databaseId;
|
||||
const database = await prisma.database.findUnique({ where: { id: databaseId } });
|
||||
if (database) {
|
||||
await createdBranchDatabase(database, application.connectedDatabase.hostedDatabaseDBName, pullmergeRequestId);
|
||||
}
|
||||
}
|
||||
}
|
||||
await prisma.build.create({
|
||||
data: {
|
||||
id: buildId,
|
||||
@ -197,9 +203,17 @@ export async function gitHubEvents(request: FastifyRequest<GitHubEvents>): Promi
|
||||
} else if (pullmergeRequestAction === 'closed') {
|
||||
if (application.destinationDockerId) {
|
||||
const id = `${application.id}-${pullmergeRequestId}`;
|
||||
await removeContainer({ id, dockerId: application.destinationDocker.id });
|
||||
try {
|
||||
await removeContainer({ id, dockerId: application.destinationDocker.id });
|
||||
} catch (error) { }
|
||||
}
|
||||
if (application.connectedDatabase.databaseId) {
|
||||
const databaseId = application.connectedDatabase.databaseId;
|
||||
const database = await prisma.database.findUnique({ where: { id: databaseId } });
|
||||
if (database) {
|
||||
await removeBranchDatabase(database, pullmergeRequestId);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,11 +19,11 @@
|
||||
"@popperjs/core": "2.11.6",
|
||||
"@sveltejs/kit": "1.0.0-next.405",
|
||||
"@types/js-cookie": "3.0.2",
|
||||
"@typescript-eslint/eslint-plugin": "5.35.1",
|
||||
"@typescript-eslint/parser": "5.35.1",
|
||||
"@typescript-eslint/eslint-plugin": "5.36.1",
|
||||
"@typescript-eslint/parser": "5.36.1",
|
||||
"autoprefixer": "10.4.8",
|
||||
"classnames": "2.3.1",
|
||||
"eslint": "8.22.0",
|
||||
"eslint": "8.23.0",
|
||||
"eslint-config-prettier": "8.5.0",
|
||||
"eslint-plugin-svelte3": "4.0.0",
|
||||
"flowbite": "1.5.2",
|
||||
@ -31,21 +31,21 @@
|
||||
"postcss": "8.4.16",
|
||||
"prettier": "2.7.1",
|
||||
"prettier-plugin-svelte": "2.7.0",
|
||||
"svelte": "3.49.0",
|
||||
"svelte-check": "2.8.1",
|
||||
"svelte": "3.50.0",
|
||||
"svelte-check": "2.9.0",
|
||||
"svelte-preprocess": "4.10.7",
|
||||
"tailwindcss": "3.1.8",
|
||||
"tailwindcss-scrollbar": "0.1.0",
|
||||
"tslib": "2.4.0",
|
||||
"typescript": "4.7.4",
|
||||
"vite": "3.0.5"
|
||||
"typescript": "4.8.2",
|
||||
"vite": "3.1.0"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@sveltejs/adapter-static": "1.0.0-next.39",
|
||||
"@tailwindcss/typography": "^0.5.4",
|
||||
"@tailwindcss/typography": "^0.5.7",
|
||||
"cuid": "2.1.8",
|
||||
"daisyui": "2.24.0",
|
||||
"daisyui": "2.24.2",
|
||||
"js-cookie": "3.0.1",
|
||||
"p-limit": "4.0.0",
|
||||
"svelte-select": "4.4.7",
|
||||
|
@ -0,0 +1,162 @@
|
||||
<script context="module" lang="ts">
|
||||
import type { Load } from '@sveltejs/kit';
|
||||
export const load: Load = async () => {
|
||||
try {
|
||||
const response = await get(`/databases`);
|
||||
return {
|
||||
props: {
|
||||
...response
|
||||
}
|
||||
};
|
||||
} catch (error: any) {
|
||||
return {
|
||||
status: 500,
|
||||
error: new Error(error)
|
||||
};
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
export let databases: any = [];
|
||||
import { get, post } from '$lib/api';
|
||||
import { t } from '$lib/translations';
|
||||
import { appSession } from '$lib/store';
|
||||
import DatabaseIcons from '$lib/components/svg/databases/DatabaseIcons.svelte';
|
||||
import { errorNotification } from '$lib/common';
|
||||
import { page } from '$app/stores';
|
||||
import { goto } from '$app/navigation';
|
||||
|
||||
const from = $page.url.searchParams.get('from');
|
||||
|
||||
let remoteDatabase = {
|
||||
name: null,
|
||||
type: null,
|
||||
host: null,
|
||||
port: null,
|
||||
user: null,
|
||||
password: null,
|
||||
database: null
|
||||
};
|
||||
|
||||
const ownDatabases = databases.filter((database: any) => {
|
||||
if (database.teams[0].id === $appSession.teamId) {
|
||||
return database;
|
||||
}
|
||||
});
|
||||
const otherDatabases = databases.filter((database: any) => {
|
||||
if (database.teams[0].id !== $appSession.teamId) {
|
||||
return database;
|
||||
}
|
||||
});
|
||||
|
||||
async function addCoolifyDatabase(database: any) {
|
||||
try {
|
||||
await post(`/applications/${$page.params.id}/configuration/database`, {
|
||||
databaseId: database.id,
|
||||
type: database.type
|
||||
});
|
||||
return window.location.assign(from || `/applications/${$page.params.id}/`);
|
||||
} catch (error) {
|
||||
return errorNotification(error);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="flex space-x-1 p-6 font-bold">
|
||||
<div class="mr-4 text-2xl tracking-tight">Select a Database</div>
|
||||
</div>
|
||||
|
||||
<div class="flex-col justify-center mt-10 pb-12 sm:pb-16">
|
||||
{#if !databases || ownDatabases.length === 0}
|
||||
<div class="flex-col">
|
||||
<div class="text-center text-xl font-bold">{$t('database.no_databases_found')}</div>
|
||||
</div>
|
||||
{/if}
|
||||
{#if ownDatabases.length > 0 || otherDatabases.length > 0}
|
||||
<div class="flex flex-col">
|
||||
<div class="flex flex-col flex-wrap justify-center px-2 md:flex-row">
|
||||
{#each ownDatabases as database}
|
||||
<button on:click={() => addCoolifyDatabase(database)} class="p-2 no-underline">
|
||||
<div class="box-selection group relative hover:bg-purple-600">
|
||||
<DatabaseIcons type={database.type} isAbsolute={true} />
|
||||
<div class="truncate text-center text-xl font-bold">
|
||||
{database.name}
|
||||
</div>
|
||||
{#if $appSession.teamId === '0' && otherDatabases.length > 0}
|
||||
<div class="truncate text-center">{database.teams[0].name}</div>
|
||||
{/if}
|
||||
{#if database.destinationDocker?.name}
|
||||
<div class="truncate text-center">{database.destinationDocker.name}</div>
|
||||
{/if}
|
||||
{#if !database.type}
|
||||
<div class="truncate text-center font-bold text-red-500 group-hover:text-white">
|
||||
{$t('application.configuration.configuration_missing')}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
{#if otherDatabases.length > 0 && $appSession.teamId === '0'}
|
||||
<div class="px-6 pb-5 pt-10 text-2xl font-bold text-center">Other Databases</div>
|
||||
<div class="flex flex-col flex-wrap justify-center px-2 md:flex-row">
|
||||
{#each otherDatabases as database}
|
||||
<a href="/databases/{database.id}" class="p-2 no-underline">
|
||||
<div class="box-selection group relative hover:bg-purple-600">
|
||||
<DatabaseIcons type={database.type} isAbsolute={true} />
|
||||
<div class="truncate text-center text-xl font-bold">
|
||||
{database.name}
|
||||
</div>
|
||||
{#if $appSession.teamId === '0'}
|
||||
<div class="truncate text-center">{database.teams[0].name}</div>
|
||||
{/if}
|
||||
{#if !database.type}
|
||||
<div class="truncate text-center font-bold text-red-500 group-hover:text-white">
|
||||
Configuration missing
|
||||
</div>
|
||||
{:else}
|
||||
<div class="text-center truncate">{database.type}</div>
|
||||
{/if}
|
||||
</div>
|
||||
</a>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="mx-auto max-w-4xl p-6">
|
||||
<div class="grid grid-flow-row gap-2 px-10">
|
||||
<div class="font-bold text-xl tracking-tight">Connect a Hosted / Remote Database</div>
|
||||
<div class="mt-2 grid grid-cols-2 items-center px-4">
|
||||
<label for="name" class="text-base font-bold text-stone-100">Name</label>
|
||||
<input name="name" id="name" required bind:value={remoteDatabase.name} />
|
||||
</div>
|
||||
<div class="mt-2 grid grid-cols-2 items-center px-4">
|
||||
<label for="type" class="text-base font-bold text-stone-100">Type</label>
|
||||
<input name="type" id="type" required bind:value={remoteDatabase.type} />
|
||||
</div>
|
||||
<div class="mt-2 grid grid-cols-2 items-center px-4">
|
||||
<label for="host" class="text-base font-bold text-stone-100">Host</label>
|
||||
<input name="host" id="host" required bind:value={remoteDatabase.host} />
|
||||
</div>
|
||||
<div class="mt-2 grid grid-cols-2 items-center px-4">
|
||||
<label for="port" class="text-base font-bold text-stone-100">Port</label>
|
||||
<input name="port" id="port" required bind:value={remoteDatabase.port} />
|
||||
</div>
|
||||
<div class="mt-2 grid grid-cols-2 items-center px-4">
|
||||
<label for="user" class="text-base font-bold text-stone-100">User</label>
|
||||
<input name="user" id="user" required bind:value={remoteDatabase.user} />
|
||||
</div>
|
||||
<div class="mt-2 grid grid-cols-2 items-center px-4">
|
||||
<label for="password" class="text-base font-bold text-stone-100">Password</label>
|
||||
<input name="password" id="password" required bind:value={remoteDatabase.password} />
|
||||
</div>
|
||||
<div class="mt-2 grid grid-cols-2 items-center px-4">
|
||||
<label for="database" class="text-base font-bold text-stone-100">Database Name</label>
|
||||
<input name="database" id="database" required bind:value={remoteDatabase.database} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -31,7 +31,6 @@
|
||||
import { page } from '$app/stores';
|
||||
import { onDestroy, onMount } from 'svelte';
|
||||
import Select from 'svelte-select';
|
||||
|
||||
import { get, post } from '$lib/api';
|
||||
import cuid from 'cuid';
|
||||
import {
|
||||
@ -40,13 +39,15 @@
|
||||
checkIfDeploymentEnabledApplications,
|
||||
setLocation,
|
||||
status,
|
||||
isDeploymentEnabled
|
||||
isDeploymentEnabled,
|
||||
features
|
||||
} from '$lib/store';
|
||||
import { t } from '$lib/translations';
|
||||
import { errorNotification, getDomain, notNodeDeployments, staticDeployments } from '$lib/common';
|
||||
import Setting from '$lib/components/Setting.svelte';
|
||||
import Tooltip from '$lib/components/Tooltip.svelte';
|
||||
import Explainer from '$lib/components/Explainer.svelte';
|
||||
import { goto } from '$app/navigation';
|
||||
|
||||
const { id } = $page.params;
|
||||
|
||||
@ -73,6 +74,7 @@
|
||||
let isBot = application.settings.isBot;
|
||||
let isDBBranching = application.settings.isDBBranching;
|
||||
|
||||
let baseDatabaseBranch: any = application?.connectedDatabase?.hostedDatabaseDBName || null;
|
||||
let nonWWWDomain = application.fqdn && getDomain(application.fqdn).replace(/^www\./, '');
|
||||
let isNonWWWDomainOK = false;
|
||||
let isWWWDomainOK = false;
|
||||
@ -172,7 +174,6 @@
|
||||
}
|
||||
if (name === 'isDBBranching') {
|
||||
isDBBranching = !isDBBranching;
|
||||
application.settings.isDBBranching = isDBBranching;
|
||||
}
|
||||
try {
|
||||
await post(`/applications/${id}/settings`, {
|
||||
@ -181,6 +182,7 @@
|
||||
dualCerts,
|
||||
isBot,
|
||||
autodeploy,
|
||||
isDBBranching,
|
||||
branch: application.branch,
|
||||
projectId: application.projectId
|
||||
});
|
||||
@ -204,6 +206,9 @@
|
||||
if (name === 'isBot') {
|
||||
isBot = !isBot;
|
||||
}
|
||||
if (name === 'isDBBranching') {
|
||||
isDBBranching = !isDBBranching;
|
||||
}
|
||||
return errorNotification(error);
|
||||
} finally {
|
||||
$isDeploymentEnabled = checkIfDeploymentEnabledApplications($appSession.isAdmin, application);
|
||||
@ -223,7 +228,7 @@
|
||||
dualCerts,
|
||||
exposePort: application.exposePort
|
||||
}));
|
||||
await post(`/applications/${id}`, { ...application });
|
||||
await post(`/applications/${id}`, { ...application, baseDatabaseBranch });
|
||||
setLocation(application, settings);
|
||||
$isDeploymentEnabled = checkIfDeploymentEnabledApplications($appSession.isAdmin, application);
|
||||
|
||||
@ -525,6 +530,46 @@
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
{#if $features.beta}
|
||||
{#if !application.settings.isBot && !application.settings.isPublicRepository}
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<Setting
|
||||
id="isDBBranching"
|
||||
isCenter={false}
|
||||
bind:setting={isDBBranching}
|
||||
on:click={() => changeSettings('isDBBranching')}
|
||||
title="Enable DB Branching"
|
||||
description="Enable DB Branching"
|
||||
/>
|
||||
</div>
|
||||
{#if isDBBranching}
|
||||
<button
|
||||
on:click|stopPropagation|preventDefault={() =>
|
||||
goto(`/applications/${id}/configuration/database`)}
|
||||
class="btn btn-sm">Configure Connected Database</button
|
||||
>
|
||||
{#if application.connectedDatabase}
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="baseImage" class="text-base font-bold text-stone-100"
|
||||
>Base Database
|
||||
<Explainer
|
||||
explanation={'The name of the database that will be used as base when branching.'}
|
||||
/></label
|
||||
>
|
||||
<input
|
||||
name="baseDatabaseBranch"
|
||||
required
|
||||
id="baseDatabaseBranch"
|
||||
bind:value={baseDatabaseBranch}
|
||||
/>
|
||||
</div>
|
||||
<div class="text-center bg-green-600 rounded">
|
||||
Connected to {application.connectedDatabase.databaseId}
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
<div class="flex space-x-1 py-5 font-bold">
|
||||
<div class="title">{$t('application.application')}</div>
|
||||
@ -846,16 +891,6 @@
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<Setting
|
||||
id="isDBBranching"
|
||||
isCenter={false}
|
||||
bind:setting={isDBBranching}
|
||||
on:click={() => changeSettings('isDBBranching')}
|
||||
title="Enable DB Branching"
|
||||
description="Enable DB Branching"
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<Setting
|
||||
id="debug"
|
||||
|
864
pnpm-lock.yaml
generated
864
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user