feat: docker registries working
This commit is contained in:
@@ -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, defaultComposeConfiguration, executeDockerCmd, getDomain, prisma, decryptApplication } from '../lib/common';
|
import { createDirectories, decrypt, defaultComposeConfiguration, executeDockerCmd, getDomain, prisma, decryptApplication, isDev } 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';
|
||||||
|
|
||||||
@@ -426,8 +426,10 @@ import * as buildpacks from '../lib/buildPacks';
|
|||||||
await saveBuildLog({ line: error, buildId, applicationId: application.id });
|
await saveBuildLog({ line: error, buildId, applicationId: application.id });
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
|
if (!isDev) {
|
||||||
await fs.rm(workdir, { recursive: true, force: true });
|
await fs.rm(workdir, { recursive: true, force: true });
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
await pAll.default(actions, { concurrency })
|
await pAll.default(actions, { concurrency })
|
||||||
|
@@ -590,13 +590,14 @@ export async function saveDockerRegistryCredentials({ url, username, password, w
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
}
|
}
|
||||||
await fs.writeFile(`${location}/config.json`, JSON.stringify({
|
const payload = JSON.stringify({
|
||||||
"auths": {
|
"auths": {
|
||||||
[url]: {
|
[url]: {
|
||||||
"auth": Buffer.from(`${username}:${decryptedPassword}`).toString('base64')
|
"auth": Buffer.from(`${username}:${decryptedPassword}`).toString('base64')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}))
|
})
|
||||||
|
await fs.writeFile(`${location}/config.json`, payload)
|
||||||
return location
|
return location
|
||||||
}
|
}
|
||||||
export async function buildImage({
|
export async function buildImage({
|
||||||
@@ -626,6 +627,8 @@ export async function buildImage({
|
|||||||
const cache = `${applicationId}:${tag}${isCache ? '-cache' : ''}`
|
const cache = `${applicationId}:${tag}${isCache ? '-cache' : ''}`
|
||||||
const { dockerRegistry: { url, username, password } } = await prisma.application.findUnique({ where: { id: applicationId }, select: { dockerRegistry: true } })
|
const { dockerRegistry: { url, username, password } } = await prisma.application.findUnique({ where: { id: applicationId }, select: { dockerRegistry: true } })
|
||||||
const location = await saveDockerRegistryCredentials({ url, username, password, workdir })
|
const location = await saveDockerRegistryCredentials({ url, username, password, workdir })
|
||||||
|
console.log(`docker ${location ? `--config ${location}` : ''} build --progress plain -f ${workdir}/${dockerFile} -t ${cache} --build-arg SOURCE_COMMIT=${commit} ${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}` })
|
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}` })
|
||||||
|
|
||||||
const { status } = await prisma.build.findUnique({ where: { id: buildId } })
|
const { status } = await prisma.build.findUnique({ where: { id: buildId } })
|
||||||
|
@@ -877,6 +877,16 @@ export async function getBuildPack(request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function saveRegistry(request, reply) {
|
||||||
|
try {
|
||||||
|
const { id } = request.params
|
||||||
|
const { registryId } = request.body
|
||||||
|
await prisma.application.update({ where: { id }, data: { dockerRegistry: { connect: { id: registryId } } } });
|
||||||
|
return reply.code(201).send()
|
||||||
|
} catch ({ status, message }) {
|
||||||
|
return errorHandler({ status, message })
|
||||||
|
}
|
||||||
|
}
|
||||||
export async function saveBuildPack(request, reply) {
|
export async function saveBuildPack(request, reply) {
|
||||||
try {
|
try {
|
||||||
const { id } = request.params
|
const { id } = request.params
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
import { FastifyPluginAsync } from 'fastify';
|
import { FastifyPluginAsync } from 'fastify';
|
||||||
import { OnlyId } from '../../../../types';
|
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, 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, 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, RestartPreviewApplication, SaveApplication, SaveApplicationSettings, SaveApplicationSource, SaveDeployKey, SaveDestination, SaveSecret, SaveStorage, StopPreviewApplication } from './types';
|
||||||
|
|
||||||
@@ -64,6 +64,8 @@ const root: FastifyPluginAsync = async (fastify): Promise<void> => {
|
|||||||
fastify.get('/:id/configuration/buildpack', async (request) => await getBuildPack(request));
|
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/buildpack', async (request, reply) => await saveBuildPack(request, reply));
|
||||||
|
|
||||||
|
fastify.post('/:id/configuration/registry', async (request, reply) => await saveRegistry(request, reply));
|
||||||
|
|
||||||
fastify.post('/:id/configuration/database', async (request, reply) => await saveConnectedDatabase(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.get<OnlyId>('/:id/configuration/sshkey', async (request) => await getGitLabSSHKey(request));
|
||||||
|
@@ -2,7 +2,13 @@ import { FastifyPluginAsync } from 'fastify';
|
|||||||
import { errorHandler, listSettings, version } from '../../../../lib/common';
|
import { errorHandler, listSettings, version } from '../../../../lib/common';
|
||||||
|
|
||||||
const root: FastifyPluginAsync = async (fastify): Promise<void> => {
|
const root: FastifyPluginAsync = async (fastify): Promise<void> => {
|
||||||
fastify.addHook('onRequest', async (request) => await request.jwtVerify());
|
fastify.addHook('onRequest', async (request) => {
|
||||||
|
try {
|
||||||
|
await request.jwtVerify()
|
||||||
|
} catch(error) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
});
|
||||||
fastify.get('/', async (request) => {
|
fastify.get('/', async (request) => {
|
||||||
const teamId = request.user?.teamId;
|
const teamId = request.user?.teamId;
|
||||||
const settings = await listSettings()
|
const settings = await listSettings()
|
||||||
|
@@ -3,7 +3,7 @@ import { X509Certificate } from 'node:crypto';
|
|||||||
|
|
||||||
import type { FastifyReply, FastifyRequest } from 'fastify';
|
import type { FastifyReply, FastifyRequest } from 'fastify';
|
||||||
import { asyncExecShell, checkDomainsIsValidInDNS, decrypt, encrypt, errorHandler, isDev, isDNSValid, isDomainConfigured, listSettings, prisma } from '../../../../lib/common';
|
import { asyncExecShell, checkDomainsIsValidInDNS, decrypt, encrypt, errorHandler, isDev, isDNSValid, isDomainConfigured, listSettings, prisma } from '../../../../lib/common';
|
||||||
import { CheckDNS, CheckDomain, DeleteDomain, OnlyIdInBody, SaveSettings, SaveSSHKey, SetDefaultRegistry } from './types';
|
import { AddDefaultRegistry, CheckDNS, CheckDomain, DeleteDomain, OnlyIdInBody, SaveSettings, SaveSSHKey, SetDefaultRegistry } from './types';
|
||||||
|
|
||||||
|
|
||||||
export async function listAllSettings(request: FastifyRequest) {
|
export async function listAllSettings(request: FastifyRequest) {
|
||||||
@@ -12,7 +12,7 @@ export async function listAllSettings(request: FastifyRequest) {
|
|||||||
const settings = await listSettings();
|
const settings = await listSettings();
|
||||||
const sshKeys = await prisma.sshKey.findMany({ where: { team: { id: teamId } } })
|
const sshKeys = await prisma.sshKey.findMany({ where: { team: { id: teamId } } })
|
||||||
let publicRegistries = await prisma.dockerRegistry.findMany({ where: { isSystemWide: true } })
|
let publicRegistries = await prisma.dockerRegistry.findMany({ where: { isSystemWide: true } })
|
||||||
let privateRegistries = await prisma.dockerRegistry.findMany({ where: { team: { id: teamId } } })
|
let privateRegistries = await prisma.dockerRegistry.findMany({ where: { team: { id: teamId }, isSystemWide: false } })
|
||||||
publicRegistries = publicRegistries.map((registry) => {
|
publicRegistries = publicRegistries.map((registry) => {
|
||||||
if (registry.password) {
|
if (registry.password) {
|
||||||
registry.password = decrypt(registry.password)
|
registry.password = decrypt(registry.password)
|
||||||
@@ -149,8 +149,9 @@ export async function saveSSHKey(request: FastifyRequest<SaveSSHKey>, reply: Fas
|
|||||||
}
|
}
|
||||||
export async function deleteSSHKey(request: FastifyRequest<OnlyIdInBody>, reply: FastifyReply) {
|
export async function deleteSSHKey(request: FastifyRequest<OnlyIdInBody>, reply: FastifyReply) {
|
||||||
try {
|
try {
|
||||||
|
const teamId = request.user.teamId;
|
||||||
const { id } = request.body;
|
const { id } = request.body;
|
||||||
await prisma.sshKey.delete({ where: { id } })
|
await prisma.sshKey.deleteMany({ where: { id, teamId } })
|
||||||
return reply.code(201).send()
|
return reply.code(201).send()
|
||||||
} catch ({ status, message }) {
|
} catch ({ status, message }) {
|
||||||
return errorHandler({ status, message })
|
return errorHandler({ status, message })
|
||||||
@@ -159,9 +160,10 @@ export async function deleteSSHKey(request: FastifyRequest<OnlyIdInBody>, reply:
|
|||||||
|
|
||||||
export async function deleteCertificates(request: FastifyRequest<OnlyIdInBody>, reply: FastifyReply) {
|
export async function deleteCertificates(request: FastifyRequest<OnlyIdInBody>, reply: FastifyReply) {
|
||||||
try {
|
try {
|
||||||
|
const teamId = request.user.teamId;
|
||||||
const { id } = request.body;
|
const { id } = request.body;
|
||||||
await asyncExecShell(`docker exec coolify-proxy sh -c 'rm -f /etc/traefik/acme/custom/${id}-key.pem /etc/traefik/acme/custom/${id}-cert.pem'`)
|
await asyncExecShell(`docker exec coolify-proxy sh -c 'rm -f /etc/traefik/acme/custom/${id}-key.pem /etc/traefik/acme/custom/${id}-cert.pem'`)
|
||||||
await prisma.certificate.delete({ where: { id } })
|
await prisma.certificate.deleteMany({ where: { id, teamId } })
|
||||||
return reply.code(201).send()
|
return reply.code(201).send()
|
||||||
} catch ({ status, message }) {
|
} catch ({ status, message }) {
|
||||||
return errorHandler({ status, message })
|
return errorHandler({ status, message })
|
||||||
@@ -186,3 +188,28 @@ export async function setDockerRegistry(request: FastifyRequest<SetDefaultRegist
|
|||||||
return errorHandler({ status, message })
|
return errorHandler({ status, message })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
export async function addDockerRegistry(request: FastifyRequest<AddDefaultRegistry>, reply: FastifyReply) {
|
||||||
|
try {
|
||||||
|
const teamId = request.user.teamId;
|
||||||
|
const { name, url, username, password, isSystemWide } = request.body;
|
||||||
|
|
||||||
|
let encryptedPassword = ''
|
||||||
|
if (password) encryptedPassword = encrypt(password)
|
||||||
|
await prisma.dockerRegistry.create({ data: { name, url, username, password: encryptedPassword, isSystemWide, team: { connect: { id: teamId } } } })
|
||||||
|
|
||||||
|
return reply.code(201).send()
|
||||||
|
} catch ({ status, message }) {
|
||||||
|
return errorHandler({ status, message })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export async function deleteDockerRegistry(request: FastifyRequest<OnlyIdInBody>, reply: FastifyReply) {
|
||||||
|
try {
|
||||||
|
const teamId = request.user.teamId;
|
||||||
|
const { id } = request.body;
|
||||||
|
await prisma.application.updateMany({ where: { dockerRegistryId: id }, data: { dockerRegistryId: '0' } })
|
||||||
|
await prisma.dockerRegistry.deleteMany({ where: { id, teamId } })
|
||||||
|
return reply.code(201).send()
|
||||||
|
} catch ({ status, message }) {
|
||||||
|
return errorHandler({ status, message })
|
||||||
|
}
|
||||||
|
}
|
@@ -2,8 +2,8 @@ import { FastifyPluginAsync } from 'fastify';
|
|||||||
import { X509Certificate } from 'node:crypto';
|
import { X509Certificate } from 'node:crypto';
|
||||||
|
|
||||||
import { encrypt, errorHandler, prisma } from '../../../../lib/common';
|
import { encrypt, errorHandler, prisma } from '../../../../lib/common';
|
||||||
import { checkDNS, checkDomain, deleteCertificates, deleteDomain, deleteSSHKey, listAllSettings, saveSettings, saveSSHKey, setDockerRegistry } from './handlers';
|
import { addDockerRegistry, checkDNS, checkDomain, deleteCertificates, deleteDockerRegistry, deleteDomain, deleteSSHKey, listAllSettings, saveSettings, saveSSHKey, setDockerRegistry } from './handlers';
|
||||||
import { CheckDNS, CheckDomain, DeleteDomain, OnlyIdInBody, SaveSettings, SaveSSHKey, SetDefaultRegistry } from './types';
|
import { AddDefaultRegistry, CheckDNS, CheckDomain, DeleteDomain, OnlyIdInBody, SaveSettings, SaveSSHKey, SetDefaultRegistry } from './types';
|
||||||
|
|
||||||
|
|
||||||
const root: FastifyPluginAsync = async (fastify): Promise<void> => {
|
const root: FastifyPluginAsync = async (fastify): Promise<void> => {
|
||||||
@@ -21,6 +21,8 @@ const root: FastifyPluginAsync = async (fastify): Promise<void> => {
|
|||||||
fastify.delete<OnlyIdInBody>('/sshKey', async (request, reply) => await deleteSSHKey(request, reply));
|
fastify.delete<OnlyIdInBody>('/sshKey', async (request, reply) => await deleteSSHKey(request, reply));
|
||||||
|
|
||||||
fastify.post<SetDefaultRegistry>('/registry', async (request, reply) => await setDockerRegistry(request, reply));
|
fastify.post<SetDefaultRegistry>('/registry', async (request, reply) => await setDockerRegistry(request, reply));
|
||||||
|
fastify.post<AddDefaultRegistry>('/registry/new', async (request, reply) => await addDockerRegistry(request, reply));
|
||||||
|
fastify.delete<OnlyIdInBody>('/registry', async (request, reply) => await deleteDockerRegistry(request, reply));
|
||||||
// fastify.delete<>('/registry', async (request, reply) => await deleteSSHKey(request, reply));
|
// fastify.delete<>('/registry', async (request, reply) => await deleteSSHKey(request, reply));
|
||||||
|
|
||||||
fastify.post('/upload', async (request) => {
|
fastify.post('/upload', async (request) => {
|
||||||
|
@@ -56,3 +56,12 @@ export interface SetDefaultRegistry {
|
|||||||
password: string
|
password: string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
export interface AddDefaultRegistry {
|
||||||
|
Body: {
|
||||||
|
url: string
|
||||||
|
name: string
|
||||||
|
username: string
|
||||||
|
password: string
|
||||||
|
isSystemWide: boolean
|
||||||
|
}
|
||||||
|
}
|
@@ -244,14 +244,14 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{#if $page.url.pathname.startsWith(`/applications/${id}/configuration/`)}
|
{#if $page.url.pathname.startsWith(`/applications/${id}/configuration/`)}
|
||||||
<div class="px-2">
|
<div class="px-4">
|
||||||
{#if forceDelete}
|
{#if forceDelete}
|
||||||
<button
|
<button
|
||||||
on:click={() => deleteApplication(application.name, true)}
|
on:click={() => deleteApplication(application.name, true)}
|
||||||
disabled={!$appSession.isAdmin}
|
disabled={!$appSession.isAdmin}
|
||||||
class:bg-red-600={$appSession.isAdmin}
|
class:bg-red-600={$appSession.isAdmin}
|
||||||
class:hover:bg-red-500={$appSession.isAdmin}
|
class:hover:bg-red-500={$appSession.isAdmin}
|
||||||
class="btn btn-sm btn-error text-sm"
|
class="btn btn-sm btn-error hover:bg-red-700 text-sm w-64"
|
||||||
>
|
>
|
||||||
Force Delete Application
|
Force Delete Application
|
||||||
</button>
|
</button>
|
||||||
@@ -261,7 +261,7 @@
|
|||||||
disabled={!$appSession.isAdmin}
|
disabled={!$appSession.isAdmin}
|
||||||
class:bg-red-600={$appSession.isAdmin}
|
class:bg-red-600={$appSession.isAdmin}
|
||||||
class:hover:bg-red-500={$appSession.isAdmin}
|
class:hover:bg-red-500={$appSession.isAdmin}
|
||||||
class="btn btn-sm btn-error text-sm"
|
class="btn btn-sm btn-error hover:bg-red-700 text-sm w-64"
|
||||||
>
|
>
|
||||||
Delete Application
|
Delete Application
|
||||||
</button>
|
</button>
|
||||||
|
@@ -0,0 +1,118 @@
|
|||||||
|
<script context="module" lang="ts">
|
||||||
|
import type { Load } from '@sveltejs/kit';
|
||||||
|
export const load: Load = async ({ fetch, params, url, stuff }) => {
|
||||||
|
try {
|
||||||
|
const { application } = stuff;
|
||||||
|
if (application?.destinationDockerId && !url.searchParams.get('from')) {
|
||||||
|
return {
|
||||||
|
status: 302,
|
||||||
|
redirect: `/applications/${params.id}`
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const response = await get(`/settings`);
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
...response
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
status: 500,
|
||||||
|
error: new Error(`Could not load ${url}`)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
export let registries: any;
|
||||||
|
import { page } from '$app/stores';
|
||||||
|
import { goto } from '$app/navigation';
|
||||||
|
import { get, post } from '$lib/api';
|
||||||
|
import { errorNotification } from '$lib/common';
|
||||||
|
|
||||||
|
const { id } = $page.params;
|
||||||
|
const from = $page.url.searchParams.get('from');
|
||||||
|
|
||||||
|
async function handleSubmit(registryId: any) {
|
||||||
|
try {
|
||||||
|
await post(`/applications/${id}/configuration/registry`, { registryId });
|
||||||
|
return await goto(from || `/applications/${id}`);
|
||||||
|
} catch (error) {
|
||||||
|
return errorNotification(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="flex flex-col justify-center w-full">
|
||||||
|
<div class="flex flex-col flex-wrap justify-center px-2 md:flex-row mx-auto gap-4">
|
||||||
|
{#each registries.public as registry}
|
||||||
|
<button
|
||||||
|
on:click={() => handleSubmit(registry.id)}
|
||||||
|
class="box-selection hover:bg-primary relative"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
class="absolute top-0 left-0 -m-4 h-12 w-12 text-sky-500"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke-width="1.5"
|
||||||
|
stroke="currentColor"
|
||||||
|
fill="none"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
>
|
||||||
|
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||||
|
<path
|
||||||
|
d="M22 12.54c-1.804 -.345 -2.701 -1.08 -3.523 -2.94c-.487 .696 -1.102 1.568 -.92 2.4c.028 .238 -.32 1.002 -.557 1h-14c0 5.208 3.164 7 6.196 7c4.124 .022 7.828 -1.376 9.854 -5c1.146 -.101 2.296 -1.505 2.95 -2.46z"
|
||||||
|
/>
|
||||||
|
<path d="M5 10h3v3h-3z" />
|
||||||
|
<path d="M8 10h3v3h-3z" />
|
||||||
|
<path d="M11 10h3v3h-3z" />
|
||||||
|
<path d="M8 7h3v3h-3z" />
|
||||||
|
<path d="M11 7h3v3h-3z" />
|
||||||
|
<path d="M11 4h3v3h-3z" />
|
||||||
|
<path d="M4.571 18c1.5 0 2.047 -.074 2.958 -.78" />
|
||||||
|
<line x1="10" y1="16" x2="10" y2="16.01" />
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<div class="font-bold text-xl text-center truncate">{registry.name}</div>
|
||||||
|
<div class="text-center truncate">{registry.url}</div>
|
||||||
|
<div>public</div>
|
||||||
|
</button>
|
||||||
|
{/each}
|
||||||
|
{#each registries.private as registry}
|
||||||
|
<button
|
||||||
|
on:click={() => handleSubmit(registry.id)}
|
||||||
|
class="box-selection hover:bg-primary relative"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
class="absolute top-0 left-0 -m-4 h-12 w-12 text-sky-500"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke-width="1.5"
|
||||||
|
stroke="currentColor"
|
||||||
|
fill="none"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
>
|
||||||
|
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||||
|
<path
|
||||||
|
d="M22 12.54c-1.804 -.345 -2.701 -1.08 -3.523 -2.94c-.487 .696 -1.102 1.568 -.92 2.4c.028 .238 -.32 1.002 -.557 1h-14c0 5.208 3.164 7 6.196 7c4.124 .022 7.828 -1.376 9.854 -5c1.146 -.101 2.296 -1.505 2.95 -2.46z"
|
||||||
|
/>
|
||||||
|
<path d="M5 10h3v3h-3z" />
|
||||||
|
<path d="M8 10h3v3h-3z" />
|
||||||
|
<path d="M11 10h3v3h-3z" />
|
||||||
|
<path d="M8 7h3v3h-3z" />
|
||||||
|
<path d="M11 7h3v3h-3z" />
|
||||||
|
<path d="M11 4h3v3h-3z" />
|
||||||
|
<path d="M4.571 18c1.5 0 2.047 -.074 2.958 -.78" />
|
||||||
|
<line x1="10" y1="16" x2="10" y2="16.01" />
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<div class="font-bold text-xl text-center truncate">{registry.name}</div>
|
||||||
|
<div class="text-center truncate">{registry.url}</div>
|
||||||
|
<div>private</div>
|
||||||
|
</button>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</div>
|
@@ -61,7 +61,7 @@
|
|||||||
disabled={!$appSession.isAdmin}
|
disabled={!$appSession.isAdmin}
|
||||||
class:bg-red-600={$appSession.isAdmin}
|
class:bg-red-600={$appSession.isAdmin}
|
||||||
class:hover:bg-red-500={$appSession.isAdmin}
|
class:hover:bg-red-500={$appSession.isAdmin}
|
||||||
class="btn btn-lg btn-error text-sm"
|
class="btn btn-lg btn-error hover:bg-red-700 text-sm w-64"
|
||||||
>
|
>
|
||||||
Force Delete Application
|
Force Delete Application
|
||||||
</button>
|
</button>
|
||||||
@@ -71,7 +71,7 @@
|
|||||||
on:click={() => deleteApplication(application.name, false)}
|
on:click={() => deleteApplication(application.name, false)}
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={!$appSession.isAdmin}
|
disabled={!$appSession.isAdmin}
|
||||||
class="btn btn-lg btn-error hover:bg-red-700 text-sm"
|
class="btn btn-lg btn-error hover:bg-red-700 text-sm w-64"
|
||||||
>
|
>
|
||||||
Delete Application
|
Delete Application
|
||||||
</button>
|
</button>
|
||||||
|
@@ -522,6 +522,27 @@
|
|||||||
>
|
>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
<div class="grid grid-cols-2 items-center">
|
||||||
|
<label for="registry">Docker Registry</label>
|
||||||
|
{#if isDisabled}
|
||||||
|
<input
|
||||||
|
class="capitalize w-full"
|
||||||
|
disabled={isDisabled}
|
||||||
|
value={application.dockerRegistry.name}
|
||||||
|
/>
|
||||||
|
{:else}
|
||||||
|
<a
|
||||||
|
href={`/applications/${id}/configuration/registry?from=/applications/${id}`}
|
||||||
|
class="no-underline"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
value={application.dockerRegistry.name}
|
||||||
|
id="registry"
|
||||||
|
class="cursor-pointer hover:bg-coolgray-500 capitalize w-full"
|
||||||
|
/></a
|
||||||
|
>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
<div class="grid grid-cols-2 items-center">
|
<div class="grid grid-cols-2 items-center">
|
||||||
<label for="buildPack">{$t('application.build_pack')} </label>
|
<label for="buildPack">{$t('application.build_pack')} </label>
|
||||||
{#if isDisabled}
|
{#if isDisabled}
|
||||||
|
@@ -21,6 +21,7 @@
|
|||||||
import { del, post } from '$lib/api';
|
import { del, post } from '$lib/api';
|
||||||
import { errorNotification } from '$lib/common';
|
import { errorNotification } from '$lib/common';
|
||||||
import CopyPasswordField from '$lib/components/CopyPasswordField.svelte';
|
import CopyPasswordField from '$lib/components/CopyPasswordField.svelte';
|
||||||
|
import { addToast } from '$lib/store';
|
||||||
const publicRegistries = registries.public;
|
const publicRegistries = registries.public;
|
||||||
const privateRegistries = registries.private;
|
const privateRegistries = registries.private;
|
||||||
|
|
||||||
@@ -36,9 +37,8 @@
|
|||||||
|
|
||||||
async function handleSubmit() {
|
async function handleSubmit() {
|
||||||
try {
|
try {
|
||||||
console.log(newRegistry);
|
await post(`/settings/registry/new`, newRegistry);
|
||||||
// await post(`/settings/sshKey`, { ...newSSHKey });
|
return window.location.reload();
|
||||||
// return window.location.reload();
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
errorNotification(error);
|
errorNotification(error);
|
||||||
return false;
|
return false;
|
||||||
@@ -47,14 +47,23 @@
|
|||||||
async function setRegistry(registry: any) {
|
async function setRegistry(registry: any) {
|
||||||
try {
|
try {
|
||||||
await post(`/settings/registry`, registry);
|
await post(`/settings/registry`, registry);
|
||||||
} catch (error) {}
|
return addToast({
|
||||||
|
message: 'Registry updated successfully.',
|
||||||
|
type: 'success'
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
errorNotification(error);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
async function deleteSSHKey(id: string) {
|
}
|
||||||
const sure = confirm('Are you sure you would like to delete this SSH key?');
|
async function deleteDockerRegistry(id: string) {
|
||||||
|
const sure = confirm(
|
||||||
|
'Are you sure you would like to delete this Docker Registry? All dependent resources will be affected and fails to redeploy.'
|
||||||
|
);
|
||||||
if (sure) {
|
if (sure) {
|
||||||
try {
|
try {
|
||||||
if (!id) return;
|
if (!id) return;
|
||||||
// await del(`/settings/sshKey`, { id });
|
await del(`/settings/registry`, { id });
|
||||||
return window.location.reload();
|
return window.location.reload();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
errorNotification(error);
|
errorNotification(error);
|
||||||
@@ -78,7 +87,7 @@
|
|||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Name</th>
|
<th>Name</th>
|
||||||
<th>Public</th>
|
<th>SystemWide</th>
|
||||||
<th>Username</th>
|
<th>Username</th>
|
||||||
<th>Password</th>
|
<th>Password</th>
|
||||||
<th>Actions</th>
|
<th>Actions</th>
|
||||||
@@ -87,7 +96,7 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
{#each publicRegistries as registry}
|
{#each publicRegistries as registry}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{registry.name}</td>
|
<td>{registry.name}<div class="text-xs">{registry.url}</div></td>
|
||||||
<td>{(registry.isSystemWide && 'Yes') || 'No'}</td>
|
<td>{(registry.isSystemWide && 'Yes') || 'No'}</td>
|
||||||
<td>
|
<td>
|
||||||
<CopyPasswordField
|
<CopyPasswordField
|
||||||
@@ -110,9 +119,10 @@
|
|||||||
<button on:click={() => setRegistry(registry)} class="btn btn-sm btn-primary"
|
<button on:click={() => setRegistry(registry)} class="btn btn-sm btn-primary"
|
||||||
>Set</button
|
>Set</button
|
||||||
>
|
>
|
||||||
{#if !registry.isSystemWide}
|
{#if registry.id !== '0'}
|
||||||
<button on:click={() => deleteSSHKey(registry.id)} class="btn btn-sm btn-error"
|
<button
|
||||||
>Delete</button
|
on:click={() => deleteDockerRegistry(registry.id)}
|
||||||
|
class="btn btn-sm btn-error">Delete</button
|
||||||
>
|
>
|
||||||
{/if}
|
{/if}
|
||||||
</td>
|
</td>
|
||||||
@@ -120,15 +130,34 @@
|
|||||||
{/each}
|
{/each}
|
||||||
{#each privateRegistries as registry}
|
{#each privateRegistries as registry}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{registry.name}</td>
|
<td>{registry.name} <div class="text-xs">{registry.url}</div></td>
|
||||||
<td>{(registry.isSystemWide && 'Yes') || 'No'}</td>
|
<td>{(registry.isSystemWide && 'Yes') || 'No'}</td>
|
||||||
<td>{registry.username ?? 'N/A'}</td>
|
<td>
|
||||||
<td>{registry.password ?? 'N/A'}</td>
|
<CopyPasswordField
|
||||||
|
name="username"
|
||||||
|
id="Username"
|
||||||
|
bind:value={registry.username}
|
||||||
|
placeholder="Username"
|
||||||
|
/></td
|
||||||
|
>
|
||||||
|
<td
|
||||||
|
><CopyPasswordField
|
||||||
|
isPasswordField={true}
|
||||||
|
name="Password"
|
||||||
|
id="Password"
|
||||||
|
bind:value={registry.password}
|
||||||
|
placeholder="Password"
|
||||||
|
/></td
|
||||||
|
>
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
{#if !registry.isSystemWide}
|
<button on:click={() => setRegistry(registry)} class="btn btn-sm btn-primary"
|
||||||
<button on:click={() => deleteSSHKey(registry.id)} class="btn btn-sm btn-error"
|
>Set</button
|
||||||
>Delete</button
|
>
|
||||||
|
{#if registry.id !== '0'}
|
||||||
|
<button
|
||||||
|
on:click={() => deleteDockerRegistry(registry.id)}
|
||||||
|
class="btn btn-sm btn-error">Delete</button
|
||||||
>
|
>
|
||||||
{/if}
|
{/if}
|
||||||
</td>
|
</td>
|
||||||
|
Reference in New Issue
Block a user