fix + cleanup
This commit is contained in:
parent
1225786fc0
commit
0d12f3043b
@ -2204,6 +2204,7 @@
|
||||
Server, SQLite & MariaDB into a smart-spreadsheet.
|
||||
services:
|
||||
$$id:
|
||||
name: NocoDB
|
||||
image: nocodb/nocodb:$$core_version
|
||||
environment:
|
||||
- PORT=$$config_port
|
||||
|
@ -1091,7 +1091,7 @@ export const createDirectories = async ({
|
||||
repository: string;
|
||||
buildId: string;
|
||||
}): Promise<{ workdir: string; repodir: string }> => {
|
||||
repository = repository.replaceAll(' ','')
|
||||
repository = repository.replaceAll(' ', '')
|
||||
const repodir = `/tmp/build-sources/${repository}/`;
|
||||
const workdir = `/tmp/build-sources/${repository}/${buildId}`;
|
||||
let workdirFound = false;
|
||||
|
@ -35,7 +35,6 @@ export async function startService(request: FastifyRequest<ServiceStartStop>) {
|
||||
const teamId = request.user.teamId;
|
||||
const service = await getServiceFromDB({ id, teamId });
|
||||
const arm = isARM(service.arch)
|
||||
console.log(arm)
|
||||
const { type, destinationDockerId, destinationDocker, persistentStorage } =
|
||||
service;
|
||||
|
||||
@ -76,6 +75,16 @@ export async function startService(request: FastifyRequest<ServiceStartStop>) {
|
||||
}
|
||||
}
|
||||
}
|
||||
const customVolumes = await prisma.servicePersistentStorage.findMany({ where: { serviceId: service } })
|
||||
let volumes = arm ? template.services[service].volumesArm : template.services[service].volumes
|
||||
if (customVolumes.length > 0) {
|
||||
for (const customVolume of customVolumes) {
|
||||
const { volumeName, path } = customVolume
|
||||
if (!volumes.includes(`${volumeName}:${path}`)) {
|
||||
volumes.push(`${volumeName}:${path}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
config[service] = {
|
||||
container_name: service,
|
||||
build: template.services[service].build || undefined,
|
||||
@ -84,7 +93,7 @@ export async function startService(request: FastifyRequest<ServiceStartStop>) {
|
||||
image: arm ? template.services[service].imageArm : template.services[service].image,
|
||||
expose: template.services[service].ports,
|
||||
// ...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
||||
volumes: arm ? template.services[service].volumesArm : template.services[service].volumes,
|
||||
volumes,
|
||||
environment: newEnvironments,
|
||||
depends_on: template.services[service]?.depends_on,
|
||||
ulimits: template.services[service]?.ulimits,
|
||||
@ -93,7 +102,7 @@ export async function startService(request: FastifyRequest<ServiceStartStop>) {
|
||||
labels: makeLabelForServices(type),
|
||||
...defaultComposeConfiguration(network),
|
||||
}
|
||||
|
||||
|
||||
// Generate files for builds
|
||||
if (template.services[service]?.files?.length > 0) {
|
||||
if (!template.services[service].build) {
|
||||
@ -113,7 +122,6 @@ export async function startService(request: FastifyRequest<ServiceStartStop>) {
|
||||
await fs.writeFile(`${workdir}/Dockerfile.${service}`, Dockerfile);
|
||||
}
|
||||
}
|
||||
|
||||
const { volumeMounts } = persistentVolumes(id, persistentStorage, config)
|
||||
const composeFile: ComposeFile = {
|
||||
version: '3.8',
|
||||
|
@ -1,278 +0,0 @@
|
||||
/*
|
||||
Example of a supported version:
|
||||
{
|
||||
// Name used to identify the service internally
|
||||
name: 'umami',
|
||||
// Fancier name to show to the user
|
||||
fancyName: 'Umami',
|
||||
// Docker base image for the service
|
||||
baseImage: 'ghcr.io/mikecao/umami',
|
||||
// Optional: If there is any dependent image, you should list it here
|
||||
images: [],
|
||||
// Usable tags
|
||||
versions: ['postgresql-latest'],
|
||||
// Which tag is the recommended
|
||||
recommendedVersion: 'postgresql-latest',
|
||||
// Application's default port, Umami listens on 3000
|
||||
ports: {
|
||||
main: 3000
|
||||
}
|
||||
}
|
||||
*/
|
||||
export const supportedServiceTypesAndVersions = [
|
||||
{
|
||||
name: 'plausibleanalytics',
|
||||
fancyName: 'Plausible Analytics',
|
||||
baseImage: 'plausible/analytics',
|
||||
images: ['bitnami/postgresql:13.2.0', 'yandex/clickhouse-server:21.3.2.5'],
|
||||
versions: ['latest', 'stable'],
|
||||
recommendedVersion: 'stable',
|
||||
ports: {
|
||||
main: 8000
|
||||
},
|
||||
labels: ['analytics', 'plausible', 'plausible-analytics', 'gdpr', 'no-cookie']
|
||||
},
|
||||
{
|
||||
name: 'nocodb',
|
||||
fancyName: 'NocoDB',
|
||||
baseImage: 'nocodb/nocodb',
|
||||
versions: ['latest'],
|
||||
recommendedVersion: 'latest',
|
||||
ports: {
|
||||
main: 8080
|
||||
},
|
||||
labels: ['nocodb', 'airtable', 'database']
|
||||
},
|
||||
{
|
||||
name: 'minio',
|
||||
fancyName: 'MinIO',
|
||||
baseImage: 'minio/minio',
|
||||
versions: ['latest'],
|
||||
recommendedVersion: 'latest',
|
||||
ports: {
|
||||
main: 9001
|
||||
},
|
||||
labels: ['minio', 's3', 'storage']
|
||||
},
|
||||
{
|
||||
name: 'vscodeserver',
|
||||
fancyName: 'VSCode Server',
|
||||
baseImage: 'codercom/code-server',
|
||||
versions: ['latest'],
|
||||
recommendedVersion: 'latest',
|
||||
ports: {
|
||||
main: 8080
|
||||
},
|
||||
labels: ['vscodeserver', 'vscode', 'code-server', 'ide']
|
||||
},
|
||||
{
|
||||
name: 'wordpress',
|
||||
fancyName: 'WordPress',
|
||||
baseImage: 'wordpress',
|
||||
images: ['bitnami/mysql:5.7'],
|
||||
versions: ['latest', 'php8.1', 'php8.0', 'php7.4', 'php7.3'],
|
||||
recommendedVersion: 'latest',
|
||||
ports: {
|
||||
main: 80
|
||||
},
|
||||
labels: ['wordpress', 'blog', 'cms']
|
||||
},
|
||||
{
|
||||
name: 'vaultwarden',
|
||||
fancyName: 'Vaultwarden',
|
||||
baseImage: 'vaultwarden/server',
|
||||
versions: ['latest'],
|
||||
recommendedVersion: 'latest',
|
||||
ports: {
|
||||
main: 80
|
||||
},
|
||||
labels: ['vaultwarden', 'password-manager', 'passwords']
|
||||
},
|
||||
{
|
||||
name: 'languagetool',
|
||||
fancyName: 'LanguageTool',
|
||||
baseImage: 'silviof/docker-languagetool',
|
||||
versions: ['latest'],
|
||||
recommendedVersion: 'latest',
|
||||
ports: {
|
||||
main: 8010
|
||||
},
|
||||
labels: ['languagetool', 'grammar', 'spell-checker']
|
||||
},
|
||||
{
|
||||
name: 'n8n',
|
||||
fancyName: 'n8n',
|
||||
baseImage: 'n8nio/n8n',
|
||||
versions: ['latest'],
|
||||
recommendedVersion: 'latest',
|
||||
ports: {
|
||||
main: 5678
|
||||
},
|
||||
labels: ['n8n', 'workflow', 'automation', 'ifttt', 'zapier', 'nodered']
|
||||
},
|
||||
{
|
||||
name: 'uptimekuma',
|
||||
fancyName: 'Uptime Kuma',
|
||||
baseImage: 'louislam/uptime-kuma',
|
||||
versions: ['latest'],
|
||||
recommendedVersion: 'latest',
|
||||
ports: {
|
||||
main: 3001
|
||||
},
|
||||
labels: ['uptimekuma', 'uptime', 'monitoring']
|
||||
},
|
||||
{
|
||||
name: 'ghost',
|
||||
fancyName: 'Ghost',
|
||||
baseImage: 'bitnami/ghost',
|
||||
images: ['bitnami/mariadb'],
|
||||
versions: ['latest'],
|
||||
recommendedVersion: 'latest',
|
||||
ports: {
|
||||
main: 2368
|
||||
},
|
||||
labels: ['ghost', 'blog', 'cms']
|
||||
},
|
||||
{
|
||||
name: 'meilisearch',
|
||||
fancyName: 'Meilisearch',
|
||||
baseImage: 'getmeili/meilisearch',
|
||||
images: [],
|
||||
versions: ['latest'],
|
||||
recommendedVersion: 'latest',
|
||||
ports: {
|
||||
main: 7700
|
||||
},
|
||||
labels: ['meilisearch', 'search', 'search-engine']
|
||||
},
|
||||
{
|
||||
name: 'umami',
|
||||
fancyName: 'Umami',
|
||||
baseImage: 'ghcr.io/umami-software/umami',
|
||||
images: ['postgres:12-alpine'],
|
||||
versions: ['postgresql-latest'],
|
||||
recommendedVersion: 'postgresql-latest',
|
||||
ports: {
|
||||
main: 3000
|
||||
},
|
||||
labels: ['umami', 'analytics', 'gdpr', 'no-cookie']
|
||||
},
|
||||
{
|
||||
name: 'hasura',
|
||||
fancyName: 'Hasura',
|
||||
baseImage: 'hasura/graphql-engine',
|
||||
images: ['postgres:12-alpine'],
|
||||
versions: ['latest', 'v2.10.0', 'v2.5.1'],
|
||||
recommendedVersion: 'v2.10.0',
|
||||
ports: {
|
||||
main: 8080
|
||||
},
|
||||
labels: ['hasura', 'graphql', 'database']
|
||||
},
|
||||
{
|
||||
name: 'fider',
|
||||
fancyName: 'Fider',
|
||||
baseImage: 'getfider/fider',
|
||||
images: ['postgres:12-alpine'],
|
||||
versions: ['stable'],
|
||||
recommendedVersion: 'stable',
|
||||
ports: {
|
||||
main: 3000
|
||||
},
|
||||
labels: ['fider', 'feedback', 'suggestions']
|
||||
},
|
||||
{
|
||||
name: 'appwrite',
|
||||
fancyName: 'Appwrite',
|
||||
baseImage: 'appwrite/appwrite',
|
||||
images: ['mariadb:10.7', 'redis:6.2-alpine', 'appwrite/telegraf:1.4.0'],
|
||||
versions: ['latest', '1.0', '0.15.3'],
|
||||
recommendedVersion: '1.0',
|
||||
ports: {
|
||||
main: 80
|
||||
},
|
||||
labels: ['appwrite', 'database', 'storage', 'api', 'serverless']
|
||||
},
|
||||
// {
|
||||
// name: 'moodle',
|
||||
// fancyName: 'Moodle',
|
||||
// baseImage: 'bitnami/moodle',
|
||||
// images: [],
|
||||
// versions: ['latest', 'v4.0.2'],
|
||||
// recommendedVersion: 'latest',
|
||||
// ports: {
|
||||
// main: 8080
|
||||
// }
|
||||
// }
|
||||
{
|
||||
name: 'glitchTip',
|
||||
fancyName: 'GlitchTip',
|
||||
baseImage: 'glitchtip/glitchtip',
|
||||
images: ['postgres:14-alpine', 'redis:7-alpine'],
|
||||
versions: ['latest'],
|
||||
recommendedVersion: 'latest',
|
||||
ports: {
|
||||
main: 8000
|
||||
},
|
||||
labels: ['glitchtip', 'error-reporting', 'error', 'sentry', 'bugsnag']
|
||||
},
|
||||
{
|
||||
name: 'searxng',
|
||||
fancyName: 'SearXNG',
|
||||
baseImage: 'searxng/searxng',
|
||||
images: [],
|
||||
versions: ['latest'],
|
||||
recommendedVersion: 'latest',
|
||||
ports: {
|
||||
main: 8080
|
||||
},
|
||||
labels: ['searxng', 'search', 'search-engine']
|
||||
},
|
||||
{
|
||||
name: 'weblate',
|
||||
fancyName: 'Weblate',
|
||||
baseImage: 'weblate/weblate',
|
||||
images: ['postgres:14-alpine', 'redis:6-alpine'],
|
||||
versions: ['latest'],
|
||||
recommendedVersion: 'latest',
|
||||
ports: {
|
||||
main: 8080
|
||||
},
|
||||
labels: ['weblate', 'translation', 'localization']
|
||||
},
|
||||
// {
|
||||
// name: 'taiga',
|
||||
// fancyName: 'Taiga',
|
||||
// baseImage: 'taigaio/taiga-front',
|
||||
// images: ['postgres:12.3', 'rabbitmq:3.8-management-alpine', 'taigaio/taiga-back', 'taigaio/taiga-events', 'taigaio/taiga-protected'],
|
||||
// versions: ['latest'],
|
||||
// recommendedVersion: 'latest',
|
||||
// ports: {
|
||||
// main: 80
|
||||
// }
|
||||
// },
|
||||
{
|
||||
name: 'grafana',
|
||||
fancyName: 'Grafana',
|
||||
baseImage: 'grafana/grafana',
|
||||
images: [],
|
||||
versions: ['latest', '9.1.3', '9.1.2', '9.0.8', '8.3.11', '8.4.11', '8.5.11'],
|
||||
recommendedVersion: 'latest',
|
||||
ports: {
|
||||
main: 3000
|
||||
},
|
||||
labels: ['grafana', 'monitoring', 'metrics', 'dashboard']
|
||||
},
|
||||
{
|
||||
name: 'trilium',
|
||||
fancyName: 'Trilium Notes',
|
||||
baseImage: 'zadam/trilium',
|
||||
images: [],
|
||||
versions: ['latest'],
|
||||
recommendedVersion: 'latest',
|
||||
ports: {
|
||||
main: 8080
|
||||
},
|
||||
labels: ['trilium', 'notes', 'note-taking', 'wiki']
|
||||
},
|
||||
];
|
@ -15,7 +15,6 @@ import {
|
||||
uniqueName,
|
||||
version,
|
||||
} from "../../../lib/common";
|
||||
import { supportedServiceTypesAndVersions } from "../../../lib/services/supportedVersions";
|
||||
import { scheduler } from "../../../lib/scheduler";
|
||||
import type { FastifyReply, FastifyRequest } from "fastify";
|
||||
import type { Login, Update } from ".";
|
||||
@ -382,7 +381,6 @@ export async function getCurrentUser(
|
||||
return {
|
||||
settings: await prisma.setting.findFirst(),
|
||||
pendingInvitations,
|
||||
supportedServiceTypesAndVersions,
|
||||
token,
|
||||
...request.user,
|
||||
};
|
||||
|
@ -10,7 +10,6 @@ import cuid from 'cuid';
|
||||
|
||||
import type { OnlyId } from '../../../../types';
|
||||
import type { ActivateWordpressFtp, CheckService, CheckServiceDomain, DeleteServiceSecret, DeleteServiceStorage, GetServiceLogs, SaveService, SaveServiceDestination, SaveServiceSecret, SaveServiceSettings, SaveServiceStorage, SaveServiceType, SaveServiceVersion, ServiceStartStop, SetGlitchTipSettings, SetWordpressSettings } from './types';
|
||||
import { supportedServiceTypesAndVersions } from '../../../../lib/services/supportedVersions';
|
||||
import { configureServiceType, removeService } from '../../../../lib/services/common';
|
||||
import { hashPassword } from '../handlers';
|
||||
import { getTemplates } from '../../../../lib/services';
|
||||
@ -316,19 +315,7 @@ export async function saveServiceType(request: FastifyRequest<SaveServiceType>,
|
||||
return errorHandler({ status, message })
|
||||
}
|
||||
}
|
||||
export async function getServiceVersions(request: FastifyRequest<OnlyId>) {
|
||||
try {
|
||||
const teamId = request.user.teamId;
|
||||
const { id } = request.params;
|
||||
const { type } = await getServiceFromDB({ id, teamId });
|
||||
return {
|
||||
type,
|
||||
versions: supportedServiceTypesAndVersions.find((name) => name.name === type).versions
|
||||
}
|
||||
} catch ({ status, message }) {
|
||||
return errorHandler({ status, message })
|
||||
}
|
||||
}
|
||||
|
||||
export async function saveServiceVersion(request: FastifyRequest<SaveServiceVersion>, reply: FastifyReply) {
|
||||
try {
|
||||
const { id } = request.params;
|
||||
@ -601,16 +588,21 @@ export async function getServiceStorages(request: FastifyRequest<OnlyId>) {
|
||||
export async function saveServiceStorage(request: FastifyRequest<SaveServiceStorage>, reply: FastifyReply) {
|
||||
try {
|
||||
const { id } = request.params
|
||||
const { path, newStorage, storageId } = request.body
|
||||
const { path, isNewStorage, storageId, containerId } = request.body
|
||||
|
||||
if (newStorage) {
|
||||
if (isNewStorage) {
|
||||
const volumeName = `${id}-custom${path.replace(/\//gi, '-')}`
|
||||
const found = await prisma.servicePersistentStorage.findFirst({ where: { path, containerId } });
|
||||
if (found) {
|
||||
throw { status: 500, message: 'Persistent storage already exists for this container and path.' }
|
||||
}
|
||||
await prisma.servicePersistentStorage.create({
|
||||
data: { path, service: { connect: { id } } }
|
||||
data: { path, volumeName, containerId, service: { connect: { id } } }
|
||||
});
|
||||
} else {
|
||||
await prisma.servicePersistentStorage.update({
|
||||
where: { id: storageId },
|
||||
data: { path }
|
||||
data: { path, containerId }
|
||||
});
|
||||
}
|
||||
return reply.code(201).send()
|
||||
|
@ -16,7 +16,6 @@ import {
|
||||
getServiceStorages,
|
||||
getServiceType,
|
||||
getServiceUsage,
|
||||
getServiceVersions,
|
||||
listServices,
|
||||
newService,
|
||||
saveService,
|
||||
@ -64,7 +63,6 @@ const root: FastifyPluginAsync = async (fastify): Promise<void> => {
|
||||
fastify.get('/:id/configuration/type', async (request) => await getServiceType(request));
|
||||
fastify.post<SaveServiceType>('/:id/configuration/type', async (request, reply) => await saveServiceType(request, reply));
|
||||
|
||||
fastify.get<OnlyId>('/:id/configuration/version', async (request) => await getServiceVersions(request));
|
||||
fastify.post<SaveServiceVersion>('/:id/configuration/version', async (request, reply) => await saveServiceVersion(request, reply));
|
||||
|
||||
fastify.post<SaveServiceDestination>('/:id/configuration/destination', async (request, reply) => await saveServiceDestination(request, reply));
|
||||
|
@ -66,8 +66,9 @@ export interface DeleteServiceSecret extends OnlyId {
|
||||
export interface SaveServiceStorage extends OnlyId {
|
||||
Body: {
|
||||
path: string,
|
||||
newStorage: string,
|
||||
containerId: string,
|
||||
storageId: string,
|
||||
isNewStorage: boolean,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { FastifyRequest } from "fastify";
|
||||
import { errorHandler, getDomain, isDev, prisma, executeDockerCmd, fixType } from "../../../lib/common";
|
||||
import { supportedServiceTypesAndVersions } from "../../../lib/services/supportedVersions";
|
||||
import { TraefikOtherConfiguration } from "./types";
|
||||
import { OnlyId } from "../../../types";
|
||||
import { getTemplates } from "../../../lib/services";
|
||||
@ -873,7 +872,8 @@ export async function remoteTraefikConfiguration(request: FastifyRequest<OnlyId>
|
||||
plausibleAnalytics
|
||||
} = service;
|
||||
if (destinationDockerId) {
|
||||
const found = supportedServiceTypesAndVersions.find((a) => a.name === type);
|
||||
const templates = await getTemplates();
|
||||
let found = templates.find((a) => fixType(a.name) === fixType(type));
|
||||
if (found) {
|
||||
const port = found.ports.main;
|
||||
const publicPort = service[type]?.publicPort;
|
||||
|
@ -19,7 +19,6 @@ interface AppSession {
|
||||
github: string | null,
|
||||
gitlab: string | null,
|
||||
},
|
||||
supportedServiceTypesAndVersions: Array<any>
|
||||
pendingInvitations: Array<any>
|
||||
}
|
||||
interface AddToast {
|
||||
@ -48,7 +47,6 @@ export const appSession: Writable<AppSession> = writable({
|
||||
github: null,
|
||||
gitlab: null
|
||||
},
|
||||
supportedServiceTypesAndVersions: [],
|
||||
pendingInvitations: []
|
||||
});
|
||||
export const disabledButton: Writable<boolean> = writable(false);
|
||||
|
@ -65,7 +65,6 @@
|
||||
|
||||
<script lang="ts">
|
||||
export let baseSettings: any;
|
||||
export let supportedServiceTypesAndVersions: any;
|
||||
export let pendingInvitations: any = 0;
|
||||
|
||||
$appSession.isRegistrationEnabled = baseSettings.isRegistrationEnabled;
|
||||
@ -74,7 +73,6 @@
|
||||
$appSession.version = baseSettings.version;
|
||||
$appSession.whiteLabeled = baseSettings.whiteLabeled;
|
||||
$appSession.whiteLabeledDetails.icon = baseSettings.whiteLabeledIcon;
|
||||
$appSession.supportedServiceTypesAndVersions = supportedServiceTypesAndVersions;
|
||||
|
||||
$appSession.pendingInvitations = pendingInvitations;
|
||||
|
||||
|
@ -1,9 +1,7 @@
|
||||
<script lang="ts">
|
||||
export let isNew = false;
|
||||
export let storage: any = {
|
||||
id: null,
|
||||
path: null
|
||||
};
|
||||
export let storage: any = {};
|
||||
export let services: any = [];
|
||||
import { del, post } from '$lib/api';
|
||||
import { page } from '$app/stores';
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
@ -14,23 +12,36 @@
|
||||
const { id } = $page.params;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
async function saveStorage(newStorage = false) {
|
||||
async function saveStorage(e: any) {
|
||||
try {
|
||||
if (!storage.path) return errorNotification($t('application.storage.path_is_required'));
|
||||
storage.path = storage.path.startsWith('/') ? storage.path : `/${storage.path}`;
|
||||
storage.path = storage.path.endsWith('/') ? storage.path.slice(0, -1) : storage.path;
|
||||
storage.path.replace(/\/\//g, '/');
|
||||
const formData = new FormData(e.target);
|
||||
let isNewStorage = true;
|
||||
let newStorage: any = {
|
||||
id: null,
|
||||
containerId: null,
|
||||
path: null
|
||||
};
|
||||
for (let field of formData) {
|
||||
const [key, value] = field;
|
||||
newStorage[key] = value;
|
||||
}
|
||||
newStorage.path = newStorage.path.startsWith('/') ? newStorage.path : `/${newStorage.path}`;
|
||||
newStorage.path = newStorage.path.endsWith('/')
|
||||
? newStorage.path.slice(0, -1)
|
||||
: newStorage.path;
|
||||
newStorage.path.replace(/\/\//g, '/');
|
||||
await post(`/services/${id}/storages`, {
|
||||
path: storage.path,
|
||||
storageId: storage.id,
|
||||
newStorage
|
||||
path: newStorage.path,
|
||||
storageId: newStorage.id,
|
||||
containerId: newStorage.containerId,
|
||||
isNewStorage
|
||||
});
|
||||
dispatch('refresh');
|
||||
if (isNew) {
|
||||
storage.path = null;
|
||||
storage.id = null;
|
||||
}
|
||||
if (newStorage) {
|
||||
if (isNewStorage) {
|
||||
addToast({
|
||||
message: $t('application.storage.storage_saved'),
|
||||
type: 'success'
|
||||
@ -45,7 +56,7 @@
|
||||
return errorNotification(error);
|
||||
}
|
||||
}
|
||||
async function removeStorage() {
|
||||
async function removeStorage(path: string) {
|
||||
try {
|
||||
await del(`/services/${id}/storages`, { path: storage.path });
|
||||
dispatch('refresh');
|
||||
@ -61,74 +72,89 @@
|
||||
|
||||
<div class="w-full lg:px-0 px-4">
|
||||
{#if storage.predefined}
|
||||
<div class="grid grid-col-1 lg:grid-cols-2 pt-2">
|
||||
<div class="grid grid-col-1 lg:grid-cols-2 pt-2 gap-2">
|
||||
<div>
|
||||
<input
|
||||
id={storage.volumeName}
|
||||
id={storage.containerId}
|
||||
disabled
|
||||
readonly
|
||||
class="w-full"
|
||||
value={`${
|
||||
services.find((s) => s.id === storage.containerId).name || storage.containerId
|
||||
}`}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<input
|
||||
id={storage.volumeName}
|
||||
disabled
|
||||
readonly
|
||||
class="w-full"
|
||||
value={`${storage.volumeName}:${storage.path}`}
|
||||
/>
|
||||
</div>
|
||||
<div class="lg:px-2">
|
||||
<input
|
||||
id={storage.containerId}
|
||||
disabled
|
||||
readonly
|
||||
class="w-full"
|
||||
value={`${storage.containerId}`}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="grid grid-col-1 lg:grid-cols-3 lg:space-x-4" class:pt-8={isNew}>
|
||||
{#if storage.id}
|
||||
<div class="flex flex-col">
|
||||
<input
|
||||
disabled
|
||||
readonly
|
||||
class="w-full"
|
||||
value="{storage.id}{storage.path.replace(/\//gi, '-')}"
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="flex flex-col">
|
||||
{#if isNew}
|
||||
<label for="name" class="pb-2 uppercase font-bold">Path</label>
|
||||
{/if}
|
||||
<input
|
||||
disabled={storage.predefined}
|
||||
readonly={storage.predefined}
|
||||
class="w-full lg:w-64"
|
||||
bind:value={storage.path}
|
||||
required
|
||||
placeholder="eg: /sqlite.db"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class:pt-8={isNew} class:pt-2={!isNew}>
|
||||
{#if isNew}
|
||||
<div class="flex items-center justify-center w-full lg:w-64">
|
||||
<button class="btn btn-sm btn-primary w-full" on:click={() => saveStorage(true)}
|
||||
>{$t('forms.add')}</button
|
||||
{:else if isNew}
|
||||
<form id="saveVolumesForm" on:submit|preventDefault={saveStorage}>
|
||||
<div class="grid grid-col-1 lg:grid-cols-2 lg:space-x-4 pt-8">
|
||||
<div class="flex flex-row gap-2">
|
||||
<div class="flex flex-col">
|
||||
<label for="name" class="pb-2 uppercase font-bold">Container</label>
|
||||
<select
|
||||
form="saveVolumesForm"
|
||||
name="containerId"
|
||||
class="w-full lg:w-64 font-normal"
|
||||
disabled={storage.predefined}
|
||||
readonly={storage.predefined}
|
||||
bind:value={storage.containerId}
|
||||
>
|
||||
{#if services.length === 1}
|
||||
{#if services[0].name}
|
||||
<option selected value={services[0].id}>{services[0].name}</option>
|
||||
{:else}
|
||||
<option selected value={services[0]}>{services[0]}</option>
|
||||
{/if}
|
||||
{:else}
|
||||
{#each services as service}
|
||||
{#if service.name}
|
||||
<option value={service.id}>{service.name}</option>
|
||||
{:else}
|
||||
<option value={service}>{service}</option>
|
||||
{/if}
|
||||
{/each}
|
||||
{/if}
|
||||
</select>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="flex flex-row items-center justify-center space-x-2 w-full lg:w-64">
|
||||
<div class="flex items-center justify-center">
|
||||
<button class="btn btn-sm btn-primary" on:click={() => saveStorage(false)}
|
||||
>{$t('forms.set')}</button
|
||||
>
|
||||
</div>
|
||||
<div class="flex justify-center">
|
||||
<button class="btn btn-sm btn-error" on:click={removeStorage}
|
||||
>{$t('forms.remove')}</button
|
||||
>
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<label for="name" class="pb-2 uppercase font-bold">Path</label>
|
||||
<input
|
||||
name="path"
|
||||
disabled={storage.predefined}
|
||||
readonly={storage.predefined}
|
||||
class="w-full lg:w-64"
|
||||
bind:value={storage.path}
|
||||
required
|
||||
placeholder="eg: /sqlite.db"
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="pt-8">
|
||||
<div class="flex items-center justify-center w-full lg:w-64">
|
||||
<button type="submit" class="btn btn-sm btn-primary w-full">{$t('forms.add')}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{:else}
|
||||
<div class="flex lg:flex-row flex-col items-center gap-2 py-1">
|
||||
<input disabled readonly class="w-full" value={`${storage.containerId}`} />
|
||||
<input disabled readonly class="w-full" value={`${storage.volumeName}:${storage.path}`} />
|
||||
<button
|
||||
class="btn btn-sm btn-error"
|
||||
on:click|stopPropagation|preventDefault={() => removeStorage(storage.path)}
|
||||
>{$t('forms.remove')}</button
|
||||
>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
@ -37,9 +37,6 @@
|
||||
|
||||
const { id } = $page.params;
|
||||
const from = $page.url.searchParams.get('from');
|
||||
let recommendedVersion = $appSession.supportedServiceTypesAndVersions.find(
|
||||
({ name }) => name === type
|
||||
)?.recommendedVersion;
|
||||
|
||||
onMount(async () => {
|
||||
if (versions.length === 1) {
|
||||
|
@ -81,7 +81,7 @@
|
||||
// exposePort: service.exposePort
|
||||
// });
|
||||
const formData = new FormData(e.target);
|
||||
service = await saveForm(formData, service);
|
||||
if (formData) service = await saveForm(formData, service);
|
||||
setLocation(service);
|
||||
forceSave = false;
|
||||
$isDeploymentEnabled = checkIfDeploymentEnabledServices($appSession.isAdmin, service);
|
||||
|
@ -5,6 +5,7 @@
|
||||
const response = await get(`/services/${params.id}/storages`);
|
||||
return {
|
||||
props: {
|
||||
template: stuff.template,
|
||||
...response
|
||||
}
|
||||
};
|
||||
@ -19,6 +20,7 @@
|
||||
|
||||
<script lang="ts">
|
||||
export let persistentStorages: any;
|
||||
export let template: any;
|
||||
import { page } from '$app/stores';
|
||||
import Storage from './_Storage.svelte';
|
||||
import { get } from '$lib/api';
|
||||
@ -30,6 +32,16 @@
|
||||
const data = await get(`/services/${id}/storages`);
|
||||
persistentStorages = [...data.persistentStorages];
|
||||
}
|
||||
let services = Object.keys(template).map((service) => {
|
||||
if (template[service]?.name) {
|
||||
return {
|
||||
name: template[service].name,
|
||||
id: service
|
||||
};
|
||||
} else {
|
||||
return service;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="w-full">
|
||||
@ -43,19 +55,27 @@
|
||||
</div>
|
||||
</div>
|
||||
{#if persistentStorages.filter((s) => s.predefined).length > 0}
|
||||
<div class="text-base font-bold">Predefined</div>
|
||||
<div class="title">Predefined Volumes</div>
|
||||
<div class="w-full lg:px-0 px-4">
|
||||
<div class="grid grid-col-1 lg:grid-cols-2 pt-2 gap-2">
|
||||
<div class="font-bold uppercase">Container</div>
|
||||
<div class="font-bold uppercase">Volume ID : Mount Dir</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
{#each persistentStorages.filter((s) => s.predefined) as storage}
|
||||
{#key storage.id}
|
||||
<Storage on:refresh={refreshStorage} {storage} />
|
||||
<Storage on:refresh={refreshStorage} {storage} {services} />
|
||||
{/key}
|
||||
{/each}
|
||||
<div class="text-base font-bold" class:pt-10={persistentStorages.filter((s) => s.predefined).length > 0}>User Defined</div>
|
||||
<div class="title" class:pt-10={persistentStorages.filter((s) => s.predefined).length > 0}>
|
||||
Custom Volumes
|
||||
</div>
|
||||
{#each persistentStorages.filter((s) => !s.predefined) as storage}
|
||||
{#key storage.id}
|
||||
<Storage on:refresh={refreshStorage} {storage} />
|
||||
{/key}
|
||||
{/each}
|
||||
<Storage on:refresh={refreshStorage} isNew />
|
||||
<Storage on:refresh={refreshStorage} isNew {services} />
|
||||
</div>
|
||||
</div>
|
||||
|
Loading…
x
Reference in New Issue
Block a user