diff --git a/apps/api/prisma/migrations/20221130142058_reconfigure_docker_registries/migration.sql b/apps/api/prisma/migrations/20221130142058_reconfigure_docker_registries/migration.sql new file mode 100644 index 000000000..c77afb687 --- /dev/null +++ b/apps/api/prisma/migrations/20221130142058_reconfigure_docker_registries/migration.sql @@ -0,0 +1,66 @@ +/* + Warnings: + + - You are about to drop the column `isSystemWide` on the `DockerRegistry` table. All the data in the column will be lost. + +*/ +-- RedefineTables +PRAGMA foreign_keys=OFF; +CREATE TABLE "new_DockerRegistry" ( + "id" TEXT NOT NULL PRIMARY KEY, + "name" TEXT NOT NULL, + "url" TEXT NOT NULL, + "username" TEXT, + "password" TEXT, + "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" DATETIME NOT NULL, + "teamId" TEXT, + CONSTRAINT "DockerRegistry_teamId_fkey" FOREIGN KEY ("teamId") REFERENCES "Team" ("id") ON DELETE SET NULL ON UPDATE CASCADE +); +INSERT INTO "new_DockerRegistry" ("createdAt", "id", "name", "password", "teamId", "updatedAt", "url", "username") SELECT "createdAt", "id", "name", "password", "teamId", "updatedAt", "url", "username" FROM "DockerRegistry"; +DROP TABLE "DockerRegistry"; +ALTER TABLE "new_DockerRegistry" RENAME TO "DockerRegistry"; +CREATE TABLE "new_Application" ( + "id" TEXT NOT NULL PRIMARY KEY, + "name" TEXT NOT NULL, + "fqdn" TEXT, + "repository" TEXT, + "configHash" TEXT, + "branch" TEXT, + "buildPack" TEXT, + "projectId" INTEGER, + "port" INTEGER, + "exposePort" INTEGER, + "installCommand" TEXT, + "buildCommand" TEXT, + "startCommand" TEXT, + "baseDirectory" TEXT, + "publishDirectory" TEXT, + "deploymentType" TEXT, + "phpModules" TEXT, + "pythonWSGI" TEXT, + "pythonModule" TEXT, + "pythonVariable" TEXT, + "dockerFileLocation" TEXT, + "denoMainFile" TEXT, + "denoOptions" TEXT, + "dockerComposeFile" TEXT, + "dockerComposeFileLocation" TEXT, + "dockerComposeConfiguration" TEXT, + "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" DATETIME NOT NULL, + "destinationDockerId" TEXT, + "gitSourceId" TEXT, + "gitCommitHash" TEXT, + "baseImage" TEXT, + "baseBuildImage" TEXT, + "dockerRegistryId" TEXT, + CONSTRAINT "Application_gitSourceId_fkey" FOREIGN KEY ("gitSourceId") REFERENCES "GitSource" ("id") ON DELETE SET NULL ON UPDATE CASCADE, + CONSTRAINT "Application_destinationDockerId_fkey" FOREIGN KEY ("destinationDockerId") REFERENCES "DestinationDocker" ("id") ON DELETE SET NULL ON UPDATE CASCADE, + CONSTRAINT "Application_dockerRegistryId_fkey" FOREIGN KEY ("dockerRegistryId") REFERENCES "DockerRegistry" ("id") ON DELETE SET NULL ON UPDATE CASCADE +); +INSERT INTO "new_Application" ("baseBuildImage", "baseDirectory", "baseImage", "branch", "buildCommand", "buildPack", "configHash", "createdAt", "denoMainFile", "denoOptions", "deploymentType", "destinationDockerId", "dockerComposeConfiguration", "dockerComposeFile", "dockerComposeFileLocation", "dockerFileLocation", "dockerRegistryId", "exposePort", "fqdn", "gitCommitHash", "gitSourceId", "id", "installCommand", "name", "phpModules", "port", "projectId", "publishDirectory", "pythonModule", "pythonVariable", "pythonWSGI", "repository", "startCommand", "updatedAt") SELECT "baseBuildImage", "baseDirectory", "baseImage", "branch", "buildCommand", "buildPack", "configHash", "createdAt", "denoMainFile", "denoOptions", "deploymentType", "destinationDockerId", "dockerComposeConfiguration", "dockerComposeFile", "dockerComposeFileLocation", "dockerFileLocation", "dockerRegistryId", "exposePort", "fqdn", "gitCommitHash", "gitSourceId", "id", "installCommand", "name", "phpModules", "port", "projectId", "publishDirectory", "pythonModule", "pythonVariable", "pythonWSGI", "repository", "startCommand", "updatedAt" FROM "Application"; +DROP TABLE "Application"; +ALTER TABLE "new_Application" RENAME TO "Application"; +PRAGMA foreign_key_check; +PRAGMA foreign_keys=ON; diff --git a/apps/api/prisma/schema.prisma b/apps/api/prisma/schema.prisma index 75c516a9b..f3adfe4aa 100644 --- a/apps/api/prisma/schema.prisma +++ b/apps/api/prisma/schema.prisma @@ -139,8 +139,8 @@ model Application { teams Team[] connectedDatabase ApplicationConnectedDatabase? previewApplication PreviewApplication[] - dockerRegistryId String @default("0") - dockerRegistry DockerRegistry @relation(fields: [dockerRegistryId], references: [id]) + dockerRegistryId String? + dockerRegistry DockerRegistry? @relation(fields: [dockerRegistryId], references: [id]) } model PreviewApplication { @@ -302,17 +302,16 @@ model SshKey { } model DockerRegistry { - id String @id @default(cuid()) - name String - url String - username String? - password String? - isSystemWide Boolean @default(false) - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - teamId String? - team Team? @relation(fields: [teamId], references: [id]) - application Application[] + id String @id @default(cuid()) + name String + url String + username String? + password String? + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + teamId String? + team Team? @relation(fields: [teamId], references: [id]) + application Application[] } model GitSource { diff --git a/apps/api/prisma/seed.js b/apps/api/prisma/seed.js index 93fcb477b..6dcba147d 100644 --- a/apps/api/prisma/seed.js +++ b/apps/api/prisma/seed.js @@ -91,10 +91,10 @@ async function main() { } } // Add default docker registry (dockerhub) - const registries = await prisma.dockerRegistry.findMany() - if (registries.length === 0) { - await prisma.dockerRegistry.create({ data: { id: "0", name: 'Docker Hub', url: 'https://index.docker.io/v1/', isSystemWide: true } }) - } + // const registries = await prisma.dockerRegistry.findMany() + // if (registries.length === 0) { + // await prisma.dockerRegistry.create({ data: { id: "0", name: 'Docker Hub', url: 'https://index.docker.io/v1/', isSystemWide: true, team: { connect: { id: '0' } } } }) + // } } main() .catch((e) => { diff --git a/apps/api/src/lib/buildPacks/common.ts b/apps/api/src/lib/buildPacks/common.ts index 9fed7baba..9d6fe585f 100644 --- a/apps/api/src/lib/buildPacks/common.ts +++ b/apps/api/src/lib/buildPacks/common.ts @@ -654,8 +654,14 @@ export async function buildImage({ } const dockerFile = isCache ? `${dockerFileLocation}-cache` : `${dockerFileLocation}` const cache = `${applicationId}:${tag}${isCache ? '-cache' : ''}` - const { dockerRegistry: { url, username, password } } = await prisma.application.findUnique({ where: { id: applicationId }, select: { dockerRegistry: true } }) - const location = await saveDockerRegistryCredentials({ url, username, password, workdir }) + + let location = null + + const { dockerRegistry } = await prisma.application.findUnique({ where: { id: applicationId }, select: { dockerRegistry: true } }) + if (dockerRegistry) { + const { url, username, password } = dockerRegistry + location = await saveDockerRegistryCredentials({ url, username, password, workdir }) + } await executeDockerCmd({ debug, buildId, applicationId, dockerId, command: `docker ${location ? `--config ${location}` : ''} build --progress plain -f ${workdir}/${dockerFile} -t ${cache} --build-arg SOURCE_COMMIT=${commit} ${workdir}` }) diff --git a/apps/api/src/lib/importers/github.ts b/apps/api/src/lib/importers/github.ts index c57d804fe..af41c8e48 100644 --- a/apps/api/src/lib/importers/github.ts +++ b/apps/api/src/lib/importers/github.ts @@ -37,6 +37,13 @@ export default async function ({ buildId, applicationId }); + if (gitCommitHash) { + await saveBuildLog({ + line: `Checking out ${gitCommitHash} commit.`, + buildId, + applicationId + }); + } await asyncExecShell( `git clone -q -b ${branch} https://${url}/${repository}.git ${workdir}/ && cd ${workdir} && git checkout ${gitCommitHash || ""} && git submodule update --init --recursive && git lfs pull && cd .. ` ); @@ -68,6 +75,13 @@ export default async function ({ buildId, applicationId }); + if (gitCommitHash) { + await saveBuildLog({ + line: `Checking out ${gitCommitHash} commit.`, + 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 checkout ${gitCommitHash || ""} && git submodule update --init --recursive && git lfs pull && cd .. ` ); diff --git a/apps/api/src/lib/importers/gitlab.ts b/apps/api/src/lib/importers/gitlab.ts index 63808589a..fd6c7e830 100644 --- a/apps/api/src/lib/importers/gitlab.ts +++ b/apps/api/src/lib/importers/gitlab.ts @@ -39,7 +39,13 @@ export default async function ({ buildId, applicationId }); - + if (gitCommitHash) { + await saveBuildLog({ + line: `Checking out ${gitCommitHash} commit.`, + buildId, + applicationId + }); + } if (forPublic) { await asyncExecShell( `git clone -q -b ${branch} https://${url}/${repository}.git ${workdir}/ && cd ${workdir}/ && git checkout ${gitCommitHash || ""} && git submodule update --init --recursive && git lfs pull && cd .. ` @@ -49,7 +55,7 @@ export default async function ({ `git clone -q -b ${branch} git@${url}:${repository}.git --config core.sshCommand="ssh -p ${customPort} -q -i ${repodir}id.rsa -o StrictHostKeyChecking=no" ${workdir}/ && cd ${workdir}/ && git checkout ${gitCommitHash || ""} && git submodule update --init --recursive && git lfs pull && cd .. ` ); } - + const { stdout: commit } = await asyncExecShell(`cd ${workdir}/ && git rev-parse HEAD`); return commit.replace('\n', ''); } diff --git a/apps/api/src/routes/api/v1/applications/handlers.ts b/apps/api/src/routes/api/v1/applications/handlers.ts index a0e383398..f81a41850 100644 --- a/apps/api/src/routes/api/v1/applications/handlers.ts +++ b/apps/api/src/routes/api/v1/applications/handlers.ts @@ -12,7 +12,7 @@ import { checkDomainsIsValidInDNS, checkExposedPort, createDirectories, decrypt, import { checkContainer, formatLabelsOnDocker, removeContainer } from '../../../../lib/docker'; import type { FastifyRequest } from 'fastify'; -import type { GetImages, CancelDeployment, CheckDNS, CheckRepository, DeleteApplication, DeleteSecret, DeleteStorage, GetApplicationLogs, GetBuildIdLogs, SaveApplication, SaveApplicationSettings, SaveApplicationSource, SaveDeployKey, SaveDestination, SaveSecret, SaveStorage, DeployApplication, CheckDomain, StopPreviewApplication, RestartPreviewApplication, GetBuilds } from './types'; +import type { GetImages, CancelDeployment, CheckDNS, CheckRepository, DeleteApplication, DeleteSecret, DeleteStorage, GetApplicationLogs, GetBuildIdLogs, SaveApplication, SaveApplicationSettings, SaveApplicationSource, SaveDeployKey, SaveDestination, SaveSecret, SaveStorage, DeployApplication, CheckDomain, StopPreviewApplication, RestartPreviewApplication, GetBuilds, RestartApplication } from './types'; import { OnlyId } from '../../../../types'; function filterObject(obj, callback) { @@ -443,9 +443,10 @@ export async function stopPreviewApplication(request: FastifyRequest, reply: FastifyReply) { +export async function restartApplication(request: FastifyRequest, reply: FastifyReply) { try { const { id } = request.params + const { imageId = null } = request.body const { teamId } = request.user let application: any = await getApplicationFromDB(id, teamId); if (application?.destinationDockerId) { @@ -475,17 +476,22 @@ export async function restartApplication(request: FastifyRequest, reply: const { workdir } = await createDirectories({ repository, buildId }); const labels = [] let image = null - const { stdout: container } = await executeDockerCmd({ dockerId, command: `docker container ls --filter 'label=com.docker.compose.service=${id}' --format '{{json .}}'` }) - const containersArray = container.trim().split('\n'); - for (const container of containersArray) { - const containerObj = formatLabelsOnDocker(container); - image = containerObj[0].Image - Object.keys(containerObj[0].Labels).forEach(function (key) { - if (key.startsWith('coolify')) { - labels.push(`${key}=${containerObj[0].Labels[key]}`) - } - }) + if (imageId) { + image = imageId + } else { + const { stdout: container } = await executeDockerCmd({ dockerId, command: `docker container ls --filter 'label=com.docker.compose.service=${id}' --format '{{json .}}'` }) + const containersArray = container.trim().split('\n'); + for (const container of containersArray) { + const containerObj = formatLabelsOnDocker(container); + image = containerObj[0].Image + Object.keys(containerObj[0].Labels).forEach(function (key) { + if (key.startsWith('coolify')) { + labels.push(`${key}=${containerObj[0].Labels[key]}`) + } + }) + } } + let imageFound = false; try { await executeDockerCmd({ @@ -681,6 +687,38 @@ export async function getUsage(request) { return errorHandler({ status, message }) } } +export async function getDockerImages(request) { + try { + const { id } = request.params + const teamId = request.user?.teamId; + const application: any = await getApplicationFromDB(id, teamId); + const { stdout } = await executeDockerCmd({ dockerId: application.destinationDocker.id, command: `docker images --format '{{.Repository}}#{{.Tag}}#{{.CreatedAt}}' | grep -i ${id} | grep -v cache` }); + const { stdout: runningImage } = await executeDockerCmd({ dockerId: application.destinationDocker.id, command: `docker ps -a --filter 'label=com.docker.compose.service=${id}' --format {{.Image}}` }); + const images = stdout.trim().split('\n'); + let imagesAvailables = []; + for (const image of images) { + const [repository, tag, createdAt] = image.split('#'); + if (tag.includes('-')) { + continue; + } + const [year, time] = createdAt.split(' '); + imagesAvailables.push({ + repository, + tag, + createdAt: day(year + time).unix() + }) + } + + imagesAvailables = imagesAvailables.sort((a, b) => b.tag - a.tag); + + return { + imagesAvailables, + runningImage + } + } catch ({ status, message }) { + return errorHandler({ status, message }) + } +} export async function getUsageByContainer(request) { try { diff --git a/apps/api/src/routes/api/v1/applications/index.ts b/apps/api/src/routes/api/v1/applications/index.ts index 750f7b765..546c5596e 100644 --- a/apps/api/src/routes/api/v1/applications/index.ts +++ b/apps/api/src/routes/api/v1/applications/index.ts @@ -1,8 +1,8 @@ import { FastifyPluginAsync } from 'fastify'; import { OnlyId } from '../../../../types'; -import { cancelDeployment, checkDNS, checkDomain, checkRepository, cleanupUnconfiguredApplications, deleteApplication, deleteSecret, deleteStorage, deployApplication, getApplication, getApplicationLogs, getApplicationStatus, getBuildIdLogs, getBuildPack, getBuilds, getGitHubToken, getGitLabSSHKey, getImages, getPreviews, getPreviewStatus, getSecrets, getStorages, getUsage, getUsageByContainer, listApplications, loadPreviews, newApplication, restartApplication, restartPreview, saveApplication, saveApplicationSettings, saveApplicationSource, saveBuildPack, saveConnectedDatabase, saveDeployKey, saveDestination, saveGitLabSSHKey, saveRegistry, saveRepository, saveSecret, saveStorage, stopApplication, stopPreviewApplication, updatePreviewSecret, updateSecret } from './handlers'; +import { cancelDeployment, checkDNS, checkDomain, checkRepository, cleanupUnconfiguredApplications, deleteApplication, deleteSecret, deleteStorage, deployApplication, getApplication, getApplicationLogs, getApplicationStatus, getBuildIdLogs, getBuildPack, getBuilds, getDockerImages, getGitHubToken, getGitLabSSHKey, getImages, getPreviews, getPreviewStatus, getSecrets, getStorages, getUsage, getUsageByContainer, listApplications, loadPreviews, newApplication, restartApplication, restartPreview, saveApplication, saveApplicationSettings, saveApplicationSource, saveBuildPack, saveConnectedDatabase, saveDeployKey, saveDestination, saveGitLabSSHKey, saveRegistry, saveRepository, saveSecret, saveStorage, stopApplication, stopPreviewApplication, updatePreviewSecret, updateSecret } from './handlers'; -import type { CancelDeployment, CheckDNS, CheckDomain, CheckRepository, DeleteApplication, DeleteSecret, DeleteStorage, DeployApplication, GetApplicationLogs, GetBuildIdLogs, GetBuilds, GetImages, RestartPreviewApplication, SaveApplication, SaveApplicationSettings, SaveApplicationSource, SaveDeployKey, SaveDestination, SaveSecret, SaveStorage, StopPreviewApplication } from './types'; +import type { CancelDeployment, CheckDNS, CheckDomain, CheckRepository, DeleteApplication, DeleteSecret, DeleteStorage, DeployApplication, GetApplicationLogs, GetBuildIdLogs, GetBuilds, GetImages, RestartApplication, RestartPreviewApplication, SaveApplication, SaveApplicationSettings, SaveApplicationSource, SaveDeployKey, SaveDestination, SaveSecret, SaveStorage, StopPreviewApplication } from './types'; const root: FastifyPluginAsync = async (fastify): Promise => { fastify.addHook('onRequest', async (request) => { @@ -21,7 +21,7 @@ const root: FastifyPluginAsync = async (fastify): Promise => { fastify.get('/:id/status', async (request) => await getApplicationStatus(request)); - fastify.post('/:id/restart', async (request, reply) => await restartApplication(request, reply)); + fastify.post('/:id/restart', async (request, reply) => await restartApplication(request, reply)); fastify.post('/:id/stop', async (request, reply) => await stopApplication(request, reply)); fastify.post('/:id/stop/preview', async (request, reply) => await stopPreviewApplication(request, reply)); @@ -53,6 +53,8 @@ const root: FastifyPluginAsync = async (fastify): Promise => { fastify.get('/:id/usage', async (request) => await getUsage(request)) fastify.get('/:id/usage/:containerId', async (request) => await getUsageByContainer(request)) + fastify.get('/:id/images', async (request) => await getDockerImages(request)) + fastify.post('/:id/deploy', async (request) => await deployApplication(request)) fastify.post('/:id/cancel', async (request, reply) => await cancelDeployment(request, reply)); diff --git a/apps/api/src/routes/api/v1/applications/types.ts b/apps/api/src/routes/api/v1/applications/types.ts index a11e6356d..28ec6725e 100644 --- a/apps/api/src/routes/api/v1/applications/types.ts +++ b/apps/api/src/routes/api/v1/applications/types.ts @@ -141,4 +141,12 @@ export interface RestartPreviewApplication { id: string, pullmergeRequestId: string | null, } +} +export interface RestartApplication { + Params: { + id: string, + }, + Body: { + imageId: string | null, + } } \ No newline at end of file diff --git a/apps/api/src/routes/api/v1/settings/handlers.ts b/apps/api/src/routes/api/v1/settings/handlers.ts index 4b2af55eb..5269c259a 100644 --- a/apps/api/src/routes/api/v1/settings/handlers.ts +++ b/apps/api/src/routes/api/v1/settings/handlers.ts @@ -11,15 +11,8 @@ export async function listAllSettings(request: FastifyRequest) { const teamId = request.user.teamId; const settings = await listSettings(); const sshKeys = await prisma.sshKey.findMany({ where: { team: { id: teamId } } }) - let publicRegistries = await prisma.dockerRegistry.findMany({ where: { isSystemWide: true } }) - let privateRegistries = await prisma.dockerRegistry.findMany({ where: { team: { id: teamId }, isSystemWide: false } }) - publicRegistries = publicRegistries.map((registry) => { - if (registry.password) { - registry.password = decrypt(registry.password) - } - return registry - }) - privateRegistries = privateRegistries.map((registry) => { + let registries = await prisma.dockerRegistry.findMany({ where: { team: { id: teamId } } }) + registries = registries.map((registry) => { if (registry.password) { registry.password = decrypt(registry.password) } @@ -42,10 +35,7 @@ export async function listAllSettings(request: FastifyRequest) { settings, certificates: cns, sshKeys: unencryptedKeys, - registries: { - public: publicRegistries, - private: privateRegistries - } + registries } } catch ({ status, message }) { return errorHandler({ status, message }) @@ -221,11 +211,11 @@ export async function setDockerRegistry(request: FastifyRequest, reply: FastifyReply) { try { const teamId = request.user.teamId; - const { name, url, username, password, isSystemWide } = request.body; + const { name, url, username, password } = request.body; let encryptedPassword = '' if (password) encryptedPassword = encrypt(password) - await prisma.dockerRegistry.create({ data: { name, url, username, password: encryptedPassword, isSystemWide, team: { connect: { id: teamId } } } }) + await prisma.dockerRegistry.create({ data: { name, url, username, password: encryptedPassword, team: { connect: { id: teamId } } } }) return reply.code(201).send() } catch ({ status, message }) { @@ -236,7 +226,7 @@ export async function deleteDockerRegistry(request: FastifyRequest try { const teamId = request.user.teamId; const { id } = request.body; - await prisma.application.updateMany({ where: { dockerRegistryId: id }, data: { dockerRegistryId: '0' } }) + await prisma.application.updateMany({ where: { dockerRegistryId: id }, data: { dockerRegistryId: null } }) await prisma.dockerRegistry.deleteMany({ where: { id, teamId } }) return reply.code(201).send() } catch ({ status, message }) { diff --git a/apps/api/src/routes/api/v1/settings/index.ts b/apps/api/src/routes/api/v1/settings/index.ts index d727c123c..2ba8b178a 100644 --- a/apps/api/src/routes/api/v1/settings/index.ts +++ b/apps/api/src/routes/api/v1/settings/index.ts @@ -23,7 +23,6 @@ const root: FastifyPluginAsync = async (fastify): Promise => { fastify.post('/registry', async (request, reply) => await setDockerRegistry(request, reply)); fastify.post('/registry/new', async (request, reply) => await addDockerRegistry(request, reply)); fastify.delete('/registry', async (request, reply) => await deleteDockerRegistry(request, reply)); - // fastify.delete<>('/registry', async (request, reply) => await deleteSSHKey(request, reply)); fastify.post('/upload', async (request) => { try { diff --git a/apps/api/src/routes/api/v1/settings/types.ts b/apps/api/src/routes/api/v1/settings/types.ts index 6f858f0a5..418f2661f 100644 --- a/apps/api/src/routes/api/v1/settings/types.ts +++ b/apps/api/src/routes/api/v1/settings/types.ts @@ -65,6 +65,5 @@ export interface AddDefaultRegistry { name: string username: string password: string - isSystemWide: boolean } } \ No newline at end of file diff --git a/apps/ui/src/routes/__layout.svelte b/apps/ui/src/routes/__layout.svelte index 4813a7799..2efaa8a4e 100644 --- a/apps/ui/src/routes/__layout.svelte +++ b/apps/ui/src/routes/__layout.svelte @@ -268,7 +268,7 @@ {#if application.gitSource?.type === 'gitlab'} @@ -165,7 +165,9 @@ class:bg-coollabs={$page.url.pathname === `/applications/${$page.params.id}/logs`} > Advanced +
  • + + + + + + + Revert +
  • - { await getStatus(); diff --git a/apps/ui/src/routes/applications/[id]/configuration/registry.svelte b/apps/ui/src/routes/applications/[id]/configuration/registry.svelte index f1e2a9951..c122f8d68 100644 --- a/apps/ui/src/routes/applications/[id]/configuration/registry.svelte +++ b/apps/ui/src/routes/applications/[id]/configuration/registry.svelte @@ -46,73 +46,48 @@ diff --git a/apps/ui/src/routes/applications/[id]/index.svelte b/apps/ui/src/routes/applications/[id]/index.svelte index fb4cc1f74..abae70aaf 100644 --- a/apps/ui/src/routes/applications/[id]/index.svelte +++ b/apps/ui/src/routes/applications/[id]/index.svelte @@ -515,40 +515,37 @@ > {/if} - {#if application.settings.isPublicRepository} -
    - -
    - - Commits - - + + + +
    - {/if} +
    {#if isDisabled || application.settings.isPublicRepository} @@ -575,7 +572,7 @@ {:else} + import type { Load } from '@sveltejs/kit'; + export const load: Load = async ({ fetch, params, stuff, url }) => { + try { + const response = await get(`/applications/${params.id}/images`); + return { + props: { + application: stuff.application, + ...response + } + }; + } catch (error) { + return { + status: 500, + error: new Error(`Could not load ${url}`) + }; + } + }; + + + + +
    +
    +
    +
    Revert Application
    +
    +
    + You can revert application to a previously built image. Currently only locally stored images + supported. +
    +
    +
    + If you do not want the next commit to overwrite the reverted application, temporary disable Automatic Deployment + feature here. +
    +
    + {#each imagesAvailables as image} +
    +
    +
    + {image.tag} +
    +
    + + + {#if image.repository + ':' + image.tag !== runningImage} + + {:else} + + {/if} +
    +
    +
    + {/each} +
    +
    +
    diff --git a/apps/ui/src/routes/settings/_Menu.svelte b/apps/ui/src/routes/settings/_Menu.svelte index 167aa257f..7adb01a6a 100644 --- a/apps/ui/src/routes/settings/_Menu.svelte +++ b/apps/ui/src/routes/settings/_Menu.svelte @@ -4,10 +4,10 @@
    {#if isModalActive}