package updates + tags selector
This commit is contained in:
parent
52ba9dc02a
commit
4416646954
1
.gitignore
vendored
1
.gitignore
vendored
@ -16,3 +16,4 @@ apps/api/core*
|
|||||||
logs
|
logs
|
||||||
others/certificates
|
others/certificates
|
||||||
apps/api/template.json
|
apps/api/template.json
|
||||||
|
apps/api/tags.json
|
||||||
|
@ -16,18 +16,18 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@breejs/ts-worker": "2.0.0",
|
"@breejs/ts-worker": "2.0.0",
|
||||||
"@fastify/autoload": "5.4.0",
|
"@fastify/autoload": "5.4.1",
|
||||||
"@fastify/cookie": "8.3.0",
|
"@fastify/cookie": "8.3.0",
|
||||||
"@fastify/cors": "8.1.0",
|
"@fastify/cors": "8.1.1",
|
||||||
"@fastify/env": "4.1.0",
|
"@fastify/env": "4.1.0",
|
||||||
"@fastify/jwt": "6.3.2",
|
"@fastify/jwt": "6.3.2",
|
||||||
"@fastify/multipart": "7.2.0",
|
"@fastify/multipart": "7.3.0",
|
||||||
"@fastify/static": "6.5.0",
|
"@fastify/static": "6.5.0",
|
||||||
"@iarna/toml": "2.2.5",
|
"@iarna/toml": "2.2.5",
|
||||||
"@ladjs/graceful": "3.0.2",
|
"@ladjs/graceful": "3.0.2",
|
||||||
"@prisma/client": "4.4.0",
|
"@prisma/client": "4.5.0",
|
||||||
"prisma": "4.4.0",
|
"prisma": "4.5.0",
|
||||||
"axios": "0.27.2",
|
"axios": "1.1.3",
|
||||||
"bcryptjs": "2.4.3",
|
"bcryptjs": "2.4.3",
|
||||||
"bree": "9.1.2",
|
"bree": "9.1.2",
|
||||||
"cabin": "9.1.2",
|
"cabin": "9.1.2",
|
||||||
@ -35,12 +35,12 @@
|
|||||||
"csv-parse": "5.3.1",
|
"csv-parse": "5.3.1",
|
||||||
"csvtojson": "2.0.10",
|
"csvtojson": "2.0.10",
|
||||||
"cuid": "2.1.8",
|
"cuid": "2.1.8",
|
||||||
"dayjs": "1.11.5",
|
"dayjs": "1.11.6",
|
||||||
"dockerode": "3.3.4",
|
"dockerode": "3.3.4",
|
||||||
"dotenv-extended": "2.9.0",
|
"dotenv-extended": "2.9.0",
|
||||||
"execa": "6.1.0",
|
"execa": "6.1.0",
|
||||||
"fastify": "4.8.1",
|
"fastify": "4.9.2",
|
||||||
"fastify-plugin": "4.2.1",
|
"fastify-plugin": "4.3.0",
|
||||||
"generate-password": "1.7.0",
|
"generate-password": "1.7.0",
|
||||||
"got": "12.5.2",
|
"got": "12.5.2",
|
||||||
"is-ip": "5.0.0",
|
"is-ip": "5.0.0",
|
||||||
@ -58,17 +58,17 @@
|
|||||||
"unique-names-generator": "4.7.1"
|
"unique-names-generator": "4.7.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "18.8.5",
|
"semver-sort": "1.0.0",
|
||||||
|
"@types/node": "18.11.6",
|
||||||
"@types/node-os-utils": "1.3.0",
|
"@types/node-os-utils": "1.3.0",
|
||||||
"@typescript-eslint/eslint-plugin": "5.38.1",
|
"@typescript-eslint/eslint-plugin": "5.41.0",
|
||||||
"@typescript-eslint/parser": "5.38.1",
|
"@typescript-eslint/parser": "5.41.0",
|
||||||
"esbuild": "0.15.10",
|
"esbuild": "0.15.12",
|
||||||
"eslint": "8.25.0",
|
"eslint": "8.26.0",
|
||||||
"eslint-config-prettier": "8.5.0",
|
"eslint-config-prettier": "8.5.0",
|
||||||
"eslint-plugin-prettier": "4.2.1",
|
"eslint-plugin-prettier": "4.2.1",
|
||||||
"nodemon": "2.0.20",
|
"nodemon": "2.0.20",
|
||||||
"prettier": "2.7.1",
|
"prettier": "2.7.1",
|
||||||
|
|
||||||
"rimraf": "3.0.2",
|
"rimraf": "3.0.2",
|
||||||
"tsconfig-paths": "4.1.0",
|
"tsconfig-paths": "4.1.0",
|
||||||
"typescript": "4.8.4"
|
"typescript": "4.8.4"
|
||||||
|
67
apps/api/scripts/generateTags.mjs
Normal file
67
apps/api/scripts/generateTags.mjs
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
import fs from 'fs/promises';
|
||||||
|
import yaml from 'js-yaml';
|
||||||
|
import got from 'got';
|
||||||
|
import semverSort from 'semver-sort';
|
||||||
|
|
||||||
|
const repositories = [];
|
||||||
|
const templates = await fs.readFile('../devTemplates.yaml', 'utf8');
|
||||||
|
const devTemplates = yaml.load(templates);
|
||||||
|
for (const template of devTemplates) {
|
||||||
|
let image = template.services['$$id'].image.replaceAll(':$$core_version', '');
|
||||||
|
const name = template.name
|
||||||
|
if (!image.includes('/')) {
|
||||||
|
image = `library/${image}`;
|
||||||
|
}
|
||||||
|
repositories.push({ image, name: name.toLowerCase().replaceAll(' ', '') });
|
||||||
|
}
|
||||||
|
const services = []
|
||||||
|
|
||||||
|
const numberOfTags = 30;
|
||||||
|
// const semverRegex = new RegExp(/^v?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/g)
|
||||||
|
const semverRegex = new RegExp(/^v?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/g)
|
||||||
|
for (const repository of repositories) {
|
||||||
|
console.log('Querying', repository.name, 'at', repository.image);
|
||||||
|
if (repository.image.includes('ghcr.io')) {
|
||||||
|
const { execaCommand } = await import('execa');
|
||||||
|
const { stdout } = await execaCommand(`docker run --rm quay.io/skopeo/stable list-tags docker://${repository.image}`);
|
||||||
|
if (stdout) {
|
||||||
|
const json = JSON.parse(stdout);
|
||||||
|
const semverTags = json.Tags.filter((tag) => semverRegex.test(tag))
|
||||||
|
let tags = semverTags.length > 10 ? semverTags.sort().reverse().slice(0, numberOfTags) : json.Tags.sort().reverse().slice(0, numberOfTags)
|
||||||
|
if (!tags.includes('latest')) {
|
||||||
|
tags.push('latest')
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
tags = semverSort.desc(tags)
|
||||||
|
} catch (error) { }
|
||||||
|
services.push({ name: repository.name, image: repository.image, tags })
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const { token } = await got.get(`https://auth.docker.io/token?service=registry.docker.io&scope=repository:${repository.image}:pull`).json()
|
||||||
|
let data = await got.get(`https://registry-1.docker.io/v2/${repository.image}/tags/list`, {
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${token}`
|
||||||
|
}
|
||||||
|
}).json()
|
||||||
|
const semverTags = data.tags.filter((tag) => semverRegex.test(tag))
|
||||||
|
let tags = semverTags.length > 10 ? semverTags.sort().reverse().slice(0, numberOfTags) : data.tags.sort().reverse().slice(0, numberOfTags)
|
||||||
|
if (!tags.includes('latest')) {
|
||||||
|
tags.push('latest')
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
tags = semverSort.desc(tags)
|
||||||
|
} catch (error) { }
|
||||||
|
|
||||||
|
console.log({
|
||||||
|
name: repository.name,
|
||||||
|
image: repository.image,
|
||||||
|
tags
|
||||||
|
})
|
||||||
|
services.push({
|
||||||
|
name: repository.name,
|
||||||
|
image: repository.image,
|
||||||
|
tags
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await fs.writeFile('./tags.json', JSON.stringify(services));
|
@ -17,7 +17,7 @@ import { verifyRemoteDockerEngineFn } from './routes/api/v1/destinations/handler
|
|||||||
import { checkContainer } from './lib/docker';
|
import { checkContainer } from './lib/docker';
|
||||||
import { migrateServicesToNewTemplate } from './lib';
|
import { migrateServicesToNewTemplate } from './lib';
|
||||||
import { getTemplates } from './lib/services';
|
import { getTemplates } from './lib/services';
|
||||||
import { refreshTemplates } from './routes/api/v1/handlers';
|
import { refreshTags, refreshTemplates } from './routes/api/v1/handlers';
|
||||||
declare module 'fastify' {
|
declare module 'fastify' {
|
||||||
interface FastifyInstance {
|
interface FastifyInstance {
|
||||||
config: {
|
config: {
|
||||||
@ -131,12 +131,17 @@ const host = '0.0.0.0';
|
|||||||
try {
|
try {
|
||||||
const { default: got } = await import('got')
|
const { default: got } = await import('got')
|
||||||
try {
|
try {
|
||||||
|
const tags = await got.get('https://get.coollabs.io/coolify/service-tags.json').text()
|
||||||
|
|
||||||
if (isDev) {
|
if (isDev) {
|
||||||
const response = await fs.readFile('./devTemplates.yaml', 'utf8')
|
const templates = await fs.readFile('./devTemplates.yaml', 'utf8')
|
||||||
await fs.writeFile('./template.json', JSON.stringify(yaml.load(response), null, 2))
|
await fs.writeFile('./template.json', JSON.stringify(yaml.load(templates)))
|
||||||
|
const tags = await got.get('https://get.coollabs.io/coolify/service-tags.json').text()
|
||||||
|
await fs.writeFile('./tags.json', tags)
|
||||||
} else {
|
} else {
|
||||||
const response = await got.get('https://get.coollabs.io/coolify/service-templates.yaml').text()
|
const response = await got.get('https://get.coollabs.io/coolify/service-templates.yaml').text()
|
||||||
await fs.writeFile('/app/template.json', JSON.stringify(yaml.load(response), null, 2))
|
await fs.writeFile('/app/template.json', JSON.stringify(yaml.load(response)))
|
||||||
|
await fs.writeFile('/app/tags.json', tags)
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -173,18 +178,18 @@ const host = '0.0.0.0';
|
|||||||
setInterval(async () => {
|
setInterval(async () => {
|
||||||
await checkProxies();
|
await checkProxies();
|
||||||
await checkFluentBit();
|
await checkFluentBit();
|
||||||
|
}, 60000)
|
||||||
}, 10000)
|
|
||||||
|
|
||||||
// Refresh and check templates
|
// Refresh and check templates
|
||||||
setInterval(async () => {
|
setInterval(async () => {
|
||||||
await refreshTemplates()
|
await refreshTemplates()
|
||||||
|
await refreshTags()
|
||||||
await migrateServicesToNewTemplate()
|
await migrateServicesToNewTemplate()
|
||||||
}, 10000)
|
}, 60000)
|
||||||
|
|
||||||
setInterval(async () => {
|
setInterval(async () => {
|
||||||
await copySSLCertificates();
|
await copySSLCertificates();
|
||||||
}, 2000)
|
}, 10000)
|
||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
getArch(),
|
getArch(),
|
||||||
|
@ -141,3 +141,12 @@ export async function getTemplates() {
|
|||||||
// }
|
// }
|
||||||
return templates
|
return templates
|
||||||
}
|
}
|
||||||
|
export async function getTags(type?: string) {
|
||||||
|
let tags: any = [];
|
||||||
|
if (isDev) {
|
||||||
|
tags = JSON.parse(await (await fs.readFile('./tags.json')).toString())
|
||||||
|
} else {
|
||||||
|
tags = JSON.parse(await (await fs.readFile('/app/tags.json')).toString())
|
||||||
|
}
|
||||||
|
return tags.find((tag: any) => tag.name.includes(type))
|
||||||
|
}
|
||||||
|
@ -37,18 +37,42 @@ export async function cleanupManually(request: FastifyRequest) {
|
|||||||
return errorHandler({ status, message });
|
return errorHandler({ status, message });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
export async function refreshTags() {
|
||||||
|
try {
|
||||||
|
const { default: got } = await import('got')
|
||||||
|
try {
|
||||||
|
const tags = await got.get('https://get.coollabs.io/coolify/service-tags.json').text()
|
||||||
|
if (isDev) {
|
||||||
|
await fs.writeFile('./tags.json', tags)
|
||||||
|
} else {
|
||||||
|
await fs.writeFile('/app/tags.json', tags)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
throw {
|
||||||
|
status: 500,
|
||||||
|
message: 'Could not fetch templates from get.coollabs.io'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
} catch ({ status, message }) {
|
||||||
|
return errorHandler({ status, message });
|
||||||
|
}
|
||||||
|
}
|
||||||
export async function refreshTemplates() {
|
export async function refreshTemplates() {
|
||||||
try {
|
try {
|
||||||
const { default: got } = await import('got')
|
const { default: got } = await import('got')
|
||||||
try {
|
try {
|
||||||
if (isDev) {
|
if (isDev) {
|
||||||
const response = await fs.readFile('./devTemplates.yaml', 'utf8')
|
const response = await fs.readFile('./devTemplates.yaml', 'utf8')
|
||||||
await fs.writeFile('./template.json', JSON.stringify(yaml.load(response), null, 2))
|
await fs.writeFile('./template.json', JSON.stringify(yaml.load(response)))
|
||||||
} else {
|
} else {
|
||||||
const response = await got.get('https://get.coollabs.io/coolify/service-templates.yaml').text()
|
const response = await got.get('https://get.coollabs.io/coolify/service-templates.yaml').text()
|
||||||
await fs.writeFile('/app/template.json', JSON.stringify(yaml.load(response), null, 2))
|
await fs.writeFile('/app/template.json', JSON.stringify(yaml.load(response)))
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
throw {
|
throw {
|
||||||
status: 500,
|
status: 500,
|
||||||
message: 'Could not fetch templates from get.coollabs.io'
|
message: 'Could not fetch templates from get.coollabs.io'
|
||||||
|
@ -2,17 +2,16 @@ 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 crypto from 'crypto';
|
|
||||||
import { prisma, uniqueName, asyncExecShell, getServiceFromDB, getContainerUsage, isDomainConfigured, saveUpdateableFields, fixType, decrypt, encrypt, ComposeFile, getFreePublicPort, getDomain, errorHandler, generatePassword, isDev, stopTcpHttpProxy, executeDockerCmd, checkDomainsIsValidInDNS, checkExposedPort, listSettings } from '../../../../lib/common';
|
|
||||||
import { day } from '../../../../lib/dayjs';
|
|
||||||
import { checkContainer, isContainerExited } from '../../../../lib/docker';
|
|
||||||
import cuid from 'cuid';
|
import cuid from 'cuid';
|
||||||
|
|
||||||
import type { OnlyId } from '../../../../types';
|
import { prisma, uniqueName, asyncExecShell, getServiceFromDB, getContainerUsage, isDomainConfigured, saveUpdateableFields, fixType, decrypt, encrypt, ComposeFile, getFreePublicPort, getDomain, errorHandler, generatePassword, isDev, stopTcpHttpProxy, executeDockerCmd, checkDomainsIsValidInDNS, checkExposedPort, listSettings } from '../../../../lib/common';
|
||||||
|
import { day } from '../../../../lib/dayjs';
|
||||||
|
import { checkContainer, } from '../../../../lib/docker';
|
||||||
|
import { removeService } from '../../../../lib/services/common';
|
||||||
|
import { getTags, getTemplates } from '../../../../lib/services';
|
||||||
|
|
||||||
import type { ActivateWordpressFtp, CheckService, CheckServiceDomain, DeleteServiceSecret, DeleteServiceStorage, GetServiceLogs, SaveService, SaveServiceDestination, SaveServiceSecret, SaveServiceSettings, SaveServiceStorage, SaveServiceType, SaveServiceVersion, ServiceStartStop, SetGlitchTipSettings, SetWordpressSettings } from './types';
|
import type { ActivateWordpressFtp, CheckService, CheckServiceDomain, DeleteServiceSecret, DeleteServiceStorage, GetServiceLogs, SaveService, SaveServiceDestination, SaveServiceSecret, SaveServiceSettings, SaveServiceStorage, SaveServiceType, SaveServiceVersion, ServiceStartStop, SetGlitchTipSettings, SetWordpressSettings } from './types';
|
||||||
import { configureServiceType, removeService } from '../../../../lib/services/common';
|
import type { OnlyId } from '../../../../types';
|
||||||
import { hashPassword } from '../handlers';
|
|
||||||
import { getTemplates } from '../../../../lib/services';
|
|
||||||
|
|
||||||
export async function listServices(request: FastifyRequest) {
|
export async function listServices(request: FastifyRequest) {
|
||||||
try {
|
try {
|
||||||
@ -224,10 +223,12 @@ export async function getService(request: FastifyRequest<OnlyId>) {
|
|||||||
if (service.type) {
|
if (service.type) {
|
||||||
template = await parseAndFindServiceTemplates(service)
|
template = await parseAndFindServiceTemplates(service)
|
||||||
}
|
}
|
||||||
|
const tags = await getTags(service.type)
|
||||||
return {
|
return {
|
||||||
settings: await listSettings(),
|
settings: await listSettings(),
|
||||||
service,
|
service,
|
||||||
template,
|
template,
|
||||||
|
tags
|
||||||
}
|
}
|
||||||
} catch ({ status, message }) {
|
} catch ({ status, message }) {
|
||||||
console.log(status, message)
|
console.log(status, message)
|
||||||
@ -470,7 +471,7 @@ export async function checkService(request: FastifyRequest<CheckService>) {
|
|||||||
export async function saveService(request: FastifyRequest<SaveService>, reply: FastifyReply) {
|
export async function saveService(request: FastifyRequest<SaveService>, reply: FastifyReply) {
|
||||||
try {
|
try {
|
||||||
const { id } = request.params;
|
const { id } = request.params;
|
||||||
let { name, fqdn, exposePort, type, serviceSetting } = request.body;
|
let { name, fqdn, exposePort, type, serviceSetting, version } = request.body;
|
||||||
if (fqdn) fqdn = fqdn.toLowerCase();
|
if (fqdn) fqdn = fqdn.toLowerCase();
|
||||||
if (exposePort) exposePort = Number(exposePort);
|
if (exposePort) exposePort = Number(exposePort);
|
||||||
type = fixType(type)
|
type = fixType(type)
|
||||||
@ -479,6 +480,7 @@ export async function saveService(request: FastifyRequest<SaveService>, reply: F
|
|||||||
fqdn,
|
fqdn,
|
||||||
name,
|
name,
|
||||||
exposePort,
|
exposePort,
|
||||||
|
version,
|
||||||
}
|
}
|
||||||
const templates = await getTemplates()
|
const templates = await getTemplates()
|
||||||
const service = await prisma.service.findUnique({ where: { id } })
|
const service = await prisma.service.findUnique({ where: { id } })
|
||||||
|
@ -48,6 +48,8 @@ export interface SaveService extends OnlyId {
|
|||||||
name: string,
|
name: string,
|
||||||
fqdn: string,
|
fqdn: string,
|
||||||
exposePort: number,
|
exposePort: number,
|
||||||
|
version: string,
|
||||||
|
serviceSetting: any
|
||||||
type: string
|
type: string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,39 +14,39 @@
|
|||||||
"format": "prettier --write --plugin-search-dir=. ."
|
"format": "prettier --write --plugin-search-dir=. ."
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@floating-ui/dom": "1.0.1",
|
"@floating-ui/dom": "1.0.3",
|
||||||
"@playwright/test": "1.25.1",
|
"@playwright/test": "1.27.1",
|
||||||
"@popperjs/core": "2.11.6",
|
"@popperjs/core": "2.11.6",
|
||||||
"@sveltejs/kit": "1.0.0-next.405",
|
"@sveltejs/kit": "1.0.0-next.405",
|
||||||
"@types/js-cookie": "3.0.2",
|
"@types/js-cookie": "3.0.2",
|
||||||
"@typescript-eslint/eslint-plugin": "5.36.1",
|
"@typescript-eslint/eslint-plugin": "5.41.0",
|
||||||
"@typescript-eslint/parser": "5.36.1",
|
"@typescript-eslint/parser": "5.41.0",
|
||||||
"autoprefixer": "10.4.8",
|
"autoprefixer": "10.4.12",
|
||||||
"classnames": "2.3.1",
|
"classnames": "2.3.2",
|
||||||
"eslint": "8.23.0",
|
"eslint": "8.26.0",
|
||||||
"eslint-config-prettier": "8.5.0",
|
"eslint-config-prettier": "8.5.0",
|
||||||
"eslint-plugin-svelte3": "4.0.0",
|
"eslint-plugin-svelte3": "4.0.0",
|
||||||
"flowbite": "1.5.2",
|
"flowbite": "1.5.3",
|
||||||
"flowbite-svelte": "0.26.2",
|
"flowbite-svelte": "0.27.11",
|
||||||
"postcss": "8.4.16",
|
"postcss": "8.4.18",
|
||||||
"prettier": "2.7.1",
|
"prettier": "2.7.1",
|
||||||
"prettier-plugin-svelte": "2.7.0",
|
"prettier-plugin-svelte": "2.8.0",
|
||||||
"svelte": "3.50.0",
|
"svelte": "3.52.0",
|
||||||
"svelte-check": "2.9.0",
|
"svelte-check": "2.9.2",
|
||||||
"svelte-preprocess": "4.10.7",
|
"svelte-preprocess": "4.10.7",
|
||||||
"tailwindcss": "3.1.8",
|
"tailwindcss": "3.2.1",
|
||||||
"tailwindcss-scrollbar": "0.1.0",
|
"tailwindcss-scrollbar": "0.1.0",
|
||||||
"tslib": "2.4.0",
|
"tslib": "2.4.0",
|
||||||
"typescript": "4.8.2",
|
"typescript": "4.8.4",
|
||||||
"vite": "3.1.0"
|
"vite": "3.2.0"
|
||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sveltejs/adapter-static": "1.0.0-next.39",
|
"@sveltejs/adapter-static": "1.0.0-next.46",
|
||||||
"@tailwindcss/typography": "^0.5.7",
|
"@tailwindcss/typography": "^0.5.7",
|
||||||
"cuid": "2.1.8",
|
"cuid": "2.1.8",
|
||||||
"daisyui": "2.24.2",
|
"daisyui": "2.33.0",
|
||||||
"dayjs": "1.11.5",
|
"dayjs": "1.11.6",
|
||||||
"js-cookie": "3.0.1",
|
"js-cookie": "3.0.1",
|
||||||
"js-yaml": "4.1.0",
|
"js-yaml": "4.1.0",
|
||||||
"p-limit": "4.0.0",
|
"p-limit": "4.0.0",
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
try {
|
try {
|
||||||
let readOnly = false;
|
let readOnly = false;
|
||||||
const response = await get(`/services/${params.id}`);
|
const response = await get(`/services/${params.id}`);
|
||||||
const { service, settings, template } = await response;
|
const { service, settings, template, tags } = await response;
|
||||||
if (!service || Object.entries(service).length === 0) {
|
if (!service || Object.entries(service).length === 0) {
|
||||||
return {
|
return {
|
||||||
status: 302,
|
status: 302,
|
||||||
@ -43,7 +43,8 @@
|
|||||||
service,
|
service,
|
||||||
template,
|
template,
|
||||||
readOnly,
|
readOnly,
|
||||||
settings
|
settings,
|
||||||
|
tags
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
export let service: any;
|
export let service: any;
|
||||||
export let template: any;
|
export let template: any;
|
||||||
|
export let tags: any;
|
||||||
import cuid from 'cuid';
|
import cuid from 'cuid';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { browser } from '$app/env';
|
import { browser } from '$app/env';
|
||||||
@ -33,6 +34,7 @@
|
|||||||
import Explainer from '$lib/components/Explainer.svelte';
|
import Explainer from '$lib/components/Explainer.svelte';
|
||||||
import ServiceStatus from '$lib/components/ServiceStatus.svelte';
|
import ServiceStatus from '$lib/components/ServiceStatus.svelte';
|
||||||
import { saveForm } from './utils';
|
import { saveForm } from './utils';
|
||||||
|
import Select from 'svelte-select';
|
||||||
|
|
||||||
const { id } = $page.params;
|
const { id } = $page.params;
|
||||||
$: isDisabled =
|
$: isDisabled =
|
||||||
@ -53,6 +55,9 @@
|
|||||||
let isNonWWWDomainOK = false;
|
let isNonWWWDomainOK = false;
|
||||||
let isWWWDomainOK = false;
|
let isWWWDomainOK = false;
|
||||||
|
|
||||||
|
function containerClass() {
|
||||||
|
return 'text-white bg-transparent font-thin px-0 w-full border border-dashed border-coolgray-200';
|
||||||
|
}
|
||||||
async function isDNSValid(domain: any, isWWW: any) {
|
async function isDNSValid(domain: any, isWWW: any) {
|
||||||
try {
|
try {
|
||||||
await get(`/services/${id}/check?domain=${domain}`);
|
await get(`/services/${id}/check?domain=${domain}`);
|
||||||
@ -166,6 +171,9 @@
|
|||||||
loading.cleanup = false;
|
loading.cleanup = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
async function selectTag(event: any) {
|
||||||
|
service.version = event.detail.value;
|
||||||
|
}
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
if (browser && window.location.hostname === 'demo.coolify.io' && !service.fqdn) {
|
if (browser && window.location.hostname === 'demo.coolify.io' && !service.fqdn) {
|
||||||
service.fqdn = `http://${cuid()}.demo.coolify.io`;
|
service.fqdn = `http://${cuid()}.demo.coolify.io`;
|
||||||
@ -250,19 +258,19 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-2 items-center">
|
<div class="grid grid-cols-2 items-center">
|
||||||
<label for="version">Version / Tag</label>
|
<label for="version">Version / Tag</label>
|
||||||
<a
|
<div class="custom-select-wrapper w-full">
|
||||||
href={isDisabled ? `/services/${id}/configuration/version?from=/services/${id}` : ''}
|
<Select
|
||||||
class="no-underline"
|
form="saveForm"
|
||||||
>
|
containerClasses={isDisabled && containerClass()}
|
||||||
<input
|
{isDisabled}
|
||||||
class="w-full"
|
id="version"
|
||||||
|
showIndicator={!isDisabled}
|
||||||
|
items={[...tags.tags]}
|
||||||
|
on:select={selectTag}
|
||||||
value={service.version}
|
value={service.version}
|
||||||
id="service"
|
isClearable={false}
|
||||||
readonly={isDisabled}
|
/>
|
||||||
disabled={isDisabled}
|
</div>
|
||||||
class:cursor-pointer={!$status.service.isRunning}
|
|
||||||
/></a
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-2 items-center">
|
<div class="grid grid-cols-2 items-center">
|
||||||
<label for="destination">{$t('application.destination')}</label>
|
<label for="destination">{$t('application.destination')}</label>
|
||||||
@ -439,8 +447,8 @@
|
|||||||
bind:value={variable.value}
|
bind:value={variable.value}
|
||||||
form="saveForm"
|
form="saveForm"
|
||||||
>
|
>
|
||||||
<option value="true">true</option>
|
<option value="true">enabled</option>
|
||||||
<option value="false"> false</option>
|
<option value="false">disabled</option>
|
||||||
</select>
|
</select>
|
||||||
{:else}
|
{:else}
|
||||||
<select
|
<select
|
||||||
|
@ -43,7 +43,7 @@ export async function saveSecret({
|
|||||||
|
|
||||||
export async function saveForm(formData: any, service: any) {
|
export async function saveForm(formData: any, service: any) {
|
||||||
const settings = service.serviceSetting.map((setting: { name: string }) => setting.name);
|
const settings = service.serviceSetting.map((setting: { name: string }) => setting.name);
|
||||||
const baseCoolifySetting = ['name', 'fqdn', 'exposePort'];
|
const baseCoolifySetting = ['name', 'fqdn', 'exposePort', 'version'];
|
||||||
for (let field of formData) {
|
for (let field of formData) {
|
||||||
const [key, value] = field;
|
const [key, value] = field;
|
||||||
service.serviceSetting = service.serviceSetting.map((setting: any) => {
|
service.serviceSetting = service.serviceSetting.map((setting: any) => {
|
||||||
@ -61,6 +61,9 @@ export async function saveForm(formData: any, service: any) {
|
|||||||
isNew: true
|
isNew: true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (baseCoolifySetting.includes(key)) {
|
||||||
|
service[key] = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
await post(`/services/${service.id}`, { ...service });
|
await post(`/services/${service.id}`, { ...service });
|
||||||
const { service: reloadedService } = await get(`/services/${service.id}`);
|
const { service: reloadedService } = await get(`/services/${service.id}`);
|
||||||
|
1037
pnpm-lock.yaml
generated
1037
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user