feat: remote docker engine init
This commit is contained in:
parent
0a8fd0516d
commit
537209d3fb
@ -16,7 +16,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@breejs/ts-worker": "2.0.0",
|
"@breejs/ts-worker": "2.0.0",
|
||||||
"@fastify/autoload": "5.1.0",
|
"@fastify/autoload": "5.1.0",
|
||||||
"@fastify/cookie": "7.1.0",
|
"@fastify/cookie": "7.2.0",
|
||||||
"@fastify/cors": "8.0.0",
|
"@fastify/cors": "8.0.0",
|
||||||
"@fastify/env": "4.0.0",
|
"@fastify/env": "4.0.0",
|
||||||
"@fastify/jwt": "6.3.1",
|
"@fastify/jwt": "6.3.1",
|
||||||
@ -43,16 +43,17 @@
|
|||||||
"node-forge": "1.3.1",
|
"node-forge": "1.3.1",
|
||||||
"node-os-utils": "1.3.7",
|
"node-os-utils": "1.3.7",
|
||||||
"p-queue": "7.2.0",
|
"p-queue": "7.2.0",
|
||||||
|
"ssh-config": "4.1.6",
|
||||||
"strip-ansi": "7.0.1",
|
"strip-ansi": "7.0.1",
|
||||||
"unique-names-generator": "4.7.1"
|
"unique-names-generator": "4.7.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "18.0.4",
|
"@types/node": "18.0.6",
|
||||||
"@types/node-os-utils": "1.3.0",
|
"@types/node-os-utils": "1.3.0",
|
||||||
"@typescript-eslint/eslint-plugin": "5.30.6",
|
"@typescript-eslint/eslint-plugin": "5.30.6",
|
||||||
"@typescript-eslint/parser": "5.30.6",
|
"@typescript-eslint/parser": "5.30.6",
|
||||||
"esbuild": "0.14.49",
|
"esbuild": "0.14.49",
|
||||||
"eslint": "8.19.0",
|
"eslint": "8.20.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.19",
|
"nodemon": "2.0.19",
|
||||||
|
|||||||
@ -0,0 +1,21 @@
|
|||||||
|
-- RedefineTables
|
||||||
|
PRAGMA foreign_keys=OFF;
|
||||||
|
CREATE TABLE "new_DestinationDocker" (
|
||||||
|
"id" TEXT NOT NULL PRIMARY KEY,
|
||||||
|
"network" TEXT NOT NULL,
|
||||||
|
"name" TEXT NOT NULL,
|
||||||
|
"engine" TEXT,
|
||||||
|
"remoteEngine" BOOLEAN NOT NULL DEFAULT false,
|
||||||
|
"remoteIpAddress" TEXT,
|
||||||
|
"remoteUser" TEXT,
|
||||||
|
"remotePort" INTEGER,
|
||||||
|
"isCoolifyProxyUsed" BOOLEAN DEFAULT false,
|
||||||
|
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" DATETIME NOT NULL
|
||||||
|
);
|
||||||
|
INSERT INTO "new_DestinationDocker" ("createdAt", "engine", "id", "isCoolifyProxyUsed", "name", "network", "remoteEngine", "updatedAt") SELECT "createdAt", "engine", "id", "isCoolifyProxyUsed", "name", "network", "remoteEngine", "updatedAt" FROM "DestinationDocker";
|
||||||
|
DROP TABLE "DestinationDocker";
|
||||||
|
ALTER TABLE "new_DestinationDocker" RENAME TO "DestinationDocker";
|
||||||
|
CREATE UNIQUE INDEX "DestinationDocker_network_key" ON "DestinationDocker"("network");
|
||||||
|
PRAGMA foreign_key_check;
|
||||||
|
PRAGMA foreign_keys=ON;
|
||||||
@ -0,0 +1,36 @@
|
|||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "SshKey" (
|
||||||
|
"id" TEXT NOT NULL PRIMARY KEY,
|
||||||
|
"name" TEXT NOT NULL,
|
||||||
|
"privateKey" TEXT NOT NULL,
|
||||||
|
"destinationDockerId" TEXT,
|
||||||
|
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" DATETIME NOT NULL,
|
||||||
|
CONSTRAINT "SshKey_destinationDockerId_fkey" FOREIGN KEY ("destinationDockerId") REFERENCES "DestinationDocker" ("id") ON DELETE SET NULL ON UPDATE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
-- RedefineTables
|
||||||
|
PRAGMA foreign_keys=OFF;
|
||||||
|
CREATE TABLE "new_DestinationDocker" (
|
||||||
|
"id" TEXT NOT NULL PRIMARY KEY,
|
||||||
|
"network" TEXT NOT NULL,
|
||||||
|
"name" TEXT NOT NULL,
|
||||||
|
"engine" TEXT,
|
||||||
|
"remoteEngine" BOOLEAN NOT NULL DEFAULT false,
|
||||||
|
"remoteIpAddress" TEXT,
|
||||||
|
"remoteUser" TEXT,
|
||||||
|
"remotePort" INTEGER,
|
||||||
|
"remoteVerified" BOOLEAN NOT NULL DEFAULT false,
|
||||||
|
"isCoolifyProxyUsed" BOOLEAN DEFAULT false,
|
||||||
|
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" DATETIME NOT NULL
|
||||||
|
);
|
||||||
|
INSERT INTO "new_DestinationDocker" ("createdAt", "engine", "id", "isCoolifyProxyUsed", "name", "network", "remoteEngine", "remoteIpAddress", "remotePort", "remoteUser", "updatedAt") SELECT "createdAt", "engine", "id", "isCoolifyProxyUsed", "name", "network", "remoteEngine", "remoteIpAddress", "remotePort", "remoteUser", "updatedAt" FROM "DestinationDocker";
|
||||||
|
DROP TABLE "DestinationDocker";
|
||||||
|
ALTER TABLE "new_DestinationDocker" RENAME TO "DestinationDocker";
|
||||||
|
CREATE UNIQUE INDEX "DestinationDocker_network_key" ON "DestinationDocker"("network");
|
||||||
|
PRAGMA foreign_key_check;
|
||||||
|
PRAGMA foreign_keys=ON;
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "SshKey_destinationDockerId_key" ON "SshKey"("destinationDockerId");
|
||||||
@ -200,8 +200,12 @@ model DestinationDocker {
|
|||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
network String @unique
|
network String @unique
|
||||||
name String
|
name String
|
||||||
engine String
|
engine String?
|
||||||
remoteEngine Boolean @default(false)
|
remoteEngine Boolean @default(false)
|
||||||
|
remoteIpAddress String?
|
||||||
|
remoteUser String?
|
||||||
|
remotePort Int?
|
||||||
|
remoteVerified Boolean @default(false)
|
||||||
isCoolifyProxyUsed Boolean? @default(false)
|
isCoolifyProxyUsed Boolean? @default(false)
|
||||||
teams Team[]
|
teams Team[]
|
||||||
application Application[]
|
application Application[]
|
||||||
@ -209,6 +213,17 @@ model DestinationDocker {
|
|||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
database Database[]
|
database Database[]
|
||||||
service Service[]
|
service Service[]
|
||||||
|
sshKey SshKey?
|
||||||
|
}
|
||||||
|
|
||||||
|
model SshKey {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
name String
|
||||||
|
privateKey String
|
||||||
|
destinationDocker DestinationDocker? @relation(fields: [destinationDockerId], references: [id])
|
||||||
|
destinationDockerId String? @unique
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @updatedAt
|
||||||
}
|
}
|
||||||
|
|
||||||
model GitSource {
|
model GitSource {
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
import type { FastifyRequest } from 'fastify';
|
import type { FastifyRequest } from 'fastify';
|
||||||
import { FastifyReply } from 'fastify';
|
import { FastifyReply } from 'fastify';
|
||||||
import { asyncExecShell, errorHandler, listSettings, prisma, startCoolifyProxy, startTraefikProxy, stopTraefikProxy } from '../../../../lib/common';
|
import sshConfig from 'ssh-config'
|
||||||
|
import fs from 'fs/promises'
|
||||||
|
import { asyncExecShell, decrypt, errorHandler, listSettings, prisma, startCoolifyProxy, startTraefikProxy, stopTraefikProxy } from '../../../../lib/common';
|
||||||
import { checkContainer, dockerInstance, getEngine } from '../../../../lib/docker';
|
import { checkContainer, dockerInstance, getEngine } from '../../../../lib/docker';
|
||||||
|
|
||||||
import type { OnlyId } from '../../../../types';
|
import type { OnlyId } from '../../../../types';
|
||||||
@ -44,7 +46,8 @@ export async function getDestination(request: FastifyRequest<OnlyId>) {
|
|||||||
const { id } = request.params
|
const { id } = request.params
|
||||||
const teamId = request.user?.teamId;
|
const teamId = request.user?.teamId;
|
||||||
const destination = await prisma.destinationDocker.findFirst({
|
const destination = await prisma.destinationDocker.findFirst({
|
||||||
where: { id, teams: { some: { id: teamId === '0' ? undefined : teamId } } }
|
where: { id, teams: { some: { id: teamId === '0' ? undefined : teamId } } },
|
||||||
|
include: { sshKey: true }
|
||||||
});
|
});
|
||||||
if (!destination && id !== 'new') {
|
if (!destination && id !== 'new') {
|
||||||
throw { status: 404, message: `Destination not found.` };
|
throw { status: 404, message: `Destination not found.` };
|
||||||
@ -80,39 +83,51 @@ export async function getDestination(request: FastifyRequest<OnlyId>) {
|
|||||||
export async function newDestination(request: FastifyRequest<NewDestination>, reply: FastifyReply) {
|
export async function newDestination(request: FastifyRequest<NewDestination>, reply: FastifyReply) {
|
||||||
try {
|
try {
|
||||||
const { id } = request.params
|
const { id } = request.params
|
||||||
let { name, network, engine, isCoolifyProxyUsed } = request.body
|
let { name, network, engine, isCoolifyProxyUsed, ipAddress, user, port, sshPrivateKey } = request.body
|
||||||
const teamId = request.user.teamId;
|
const teamId = request.user.teamId;
|
||||||
if (id === 'new') {
|
if (id === 'new') {
|
||||||
const host = getEngine(engine);
|
if (engine) {
|
||||||
const docker = dockerInstance({ destinationDocker: { engine, network } });
|
const host = getEngine(engine);
|
||||||
const found = await docker.engine.listNetworks({ filters: { name: [`^${network}$`] } });
|
const docker = dockerInstance({ destinationDocker: { engine, network } });
|
||||||
if (found.length === 0) {
|
const found = await docker.engine.listNetworks({ filters: { name: [`^${network}$`] } });
|
||||||
await asyncExecShell(`DOCKER_HOST=${host} docker network create --attachable ${network}`);
|
if (found.length === 0) {
|
||||||
}
|
await asyncExecShell(`DOCKER_HOST=${host} docker network create --attachable ${network}`);
|
||||||
await prisma.destinationDocker.create({
|
}
|
||||||
data: { name, teams: { connect: { id: teamId } }, engine, network, isCoolifyProxyUsed }
|
await prisma.destinationDocker.create({
|
||||||
});
|
data: { name, teams: { connect: { id: teamId } }, engine, network, isCoolifyProxyUsed }
|
||||||
const destinations = await prisma.destinationDocker.findMany({ where: { engine } });
|
});
|
||||||
const destination = destinations.find((destination) => destination.network === network);
|
const destinations = await prisma.destinationDocker.findMany({ where: { engine } });
|
||||||
|
const destination = destinations.find((destination) => destination.network === network);
|
||||||
|
|
||||||
if (destinations.length > 0) {
|
if (destinations.length > 0) {
|
||||||
const proxyConfigured = destinations.find(
|
const proxyConfigured = destinations.find(
|
||||||
(destination) => destination.network !== network && destination.isCoolifyProxyUsed === true
|
(destination) => destination.network !== network && destination.isCoolifyProxyUsed === true
|
||||||
);
|
);
|
||||||
if (proxyConfigured) {
|
if (proxyConfigured) {
|
||||||
isCoolifyProxyUsed = !!proxyConfigured.isCoolifyProxyUsed;
|
isCoolifyProxyUsed = !!proxyConfigured.isCoolifyProxyUsed;
|
||||||
|
}
|
||||||
|
await prisma.destinationDocker.updateMany({ where: { engine }, data: { isCoolifyProxyUsed } });
|
||||||
}
|
}
|
||||||
await prisma.destinationDocker.updateMany({ where: { engine }, data: { isCoolifyProxyUsed } });
|
if (isCoolifyProxyUsed) {
|
||||||
}
|
const settings = await prisma.setting.findFirst();
|
||||||
if (isCoolifyProxyUsed) {
|
if (settings?.isTraefikUsed) {
|
||||||
const settings = await prisma.setting.findFirst();
|
await startTraefikProxy(engine);
|
||||||
if (settings?.isTraefikUsed) {
|
} else {
|
||||||
await startTraefikProxy(engine);
|
await startCoolifyProxy(engine);
|
||||||
} else {
|
}
|
||||||
await startCoolifyProxy(engine);
|
|
||||||
}
|
}
|
||||||
|
return reply.code(201).send({ id: destination.id });
|
||||||
}
|
}
|
||||||
return reply.code(201).send({ id: destination.id });
|
if (ipAddress) {
|
||||||
|
await prisma.destinationDocker.create({
|
||||||
|
data: { name, teams: { connect: { id: teamId } }, engine, network, isCoolifyProxyUsed, remoteEngine: true, remoteIpAddress: ipAddress, remoteUser: user, remotePort: port }
|
||||||
|
});
|
||||||
|
return reply.code(201).send()
|
||||||
|
|
||||||
|
}
|
||||||
|
throw {
|
||||||
|
message: `Cannot save Docker Engine.`
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
await prisma.destinationDocker.update({ where: { id }, data: { name, engine, network } });
|
await prisma.destinationDocker.update({ where: { id }, data: { name, engine, network } });
|
||||||
return reply.code(201).send();
|
return reply.code(201).send();
|
||||||
@ -120,6 +135,8 @@ export async function newDestination(request: FastifyRequest<NewDestination>, re
|
|||||||
|
|
||||||
} catch ({ status, message }) {
|
} catch ({ status, message }) {
|
||||||
return errorHandler({ status, message })
|
return errorHandler({ status, message })
|
||||||
|
} finally {
|
||||||
|
await fs.rm('./id_rsa')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export async function deleteDestination(request: FastifyRequest<OnlyId>) {
|
export async function deleteDestination(request: FastifyRequest<OnlyId>) {
|
||||||
@ -195,3 +212,45 @@ export async function restartProxy(request: FastifyRequest<Proxy>) {
|
|||||||
return errorHandler({ status, message })
|
return errorHandler({ status, message })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function assignSSHKey(request: FastifyRequest) {
|
||||||
|
try {
|
||||||
|
const { id: sshKeyId } = request.body;
|
||||||
|
const { id } = request.params;
|
||||||
|
console.log({ id, sshKeyId })
|
||||||
|
await prisma.destinationDocker.update({ where: { id }, data: { sshKey: { connect: { id: sshKeyId } } } })
|
||||||
|
return {}
|
||||||
|
} catch ({ status, message }) {
|
||||||
|
return errorHandler({ status, message })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export async function verifyRemoteDockerEngine(request: FastifyRequest, reply: FastifyReply) {
|
||||||
|
try {
|
||||||
|
const { id } = request.params;
|
||||||
|
const { sshKey: { privateKey }, remoteIpAddress, remotePort, remoteUser, network } = await prisma.destinationDocker.findFirst({ where: { id }, include: { sshKey: true } })
|
||||||
|
await fs.writeFile('./id_rsa', decrypt(privateKey) + '\n', { encoding: 'utf8', mode: 400 })
|
||||||
|
const host = `ssh://${remoteUser}@${remoteIpAddress}`
|
||||||
|
const config = sshConfig.parse('')
|
||||||
|
const found = config.find({ Host: remoteIpAddress })
|
||||||
|
if (!found) {
|
||||||
|
config.append({
|
||||||
|
Host: remoteIpAddress,
|
||||||
|
Port: remotePort.toString(),
|
||||||
|
User: remoteUser,
|
||||||
|
IdentityFile: '/workspace/coolify/apps/api/id_rsa',
|
||||||
|
StrictHostKeyChecking: 'no'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
await fs.writeFile('/home/gitpod/.ssh/config', sshConfig.stringify(config))
|
||||||
|
const { stdout } = await asyncExecShell(`DOCKER_HOST=${host} docker network ls --filter 'name=${network}' --no-trunc --format "{{json .}}"`);
|
||||||
|
console.log({ stdout })
|
||||||
|
if (!stdout) {
|
||||||
|
await asyncExecShell(`DOCKER_HOST=${host} docker network create --attachable ${network}`);
|
||||||
|
}
|
||||||
|
await prisma.destinationDocker.update({ where: { id }, data: { remoteVerified: true } })
|
||||||
|
return reply.code(201).send()
|
||||||
|
|
||||||
|
} catch ({ status, message }) {
|
||||||
|
return errorHandler({ status, message })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { FastifyPluginAsync } from 'fastify';
|
import { FastifyPluginAsync } from 'fastify';
|
||||||
import { checkDestination, deleteDestination, getDestination, listDestinations, newDestination, restartProxy, saveDestinationSettings, startProxy, stopProxy } from './handlers';
|
import { assignSSHKey, checkDestination, deleteDestination, getDestination, listDestinations, newDestination, restartProxy, saveDestinationSettings, startProxy, stopProxy, verifyRemoteDockerEngine } from './handlers';
|
||||||
|
|
||||||
import type { OnlyId } from '../../../../types';
|
import type { OnlyId } from '../../../../types';
|
||||||
import type { CheckDestination, NewDestination, Proxy, SaveDestinationSettings } from './types';
|
import type { CheckDestination, NewDestination, Proxy, SaveDestinationSettings } from './types';
|
||||||
@ -15,10 +15,14 @@ const root: FastifyPluginAsync = async (fastify): Promise<void> => {
|
|||||||
fastify.post<NewDestination>('/:id', async (request, reply) => await newDestination(request, reply));
|
fastify.post<NewDestination>('/:id', async (request, reply) => await newDestination(request, reply));
|
||||||
fastify.delete<OnlyId>('/:id', async (request) => await deleteDestination(request));
|
fastify.delete<OnlyId>('/:id', async (request) => await deleteDestination(request));
|
||||||
|
|
||||||
fastify.post<SaveDestinationSettings>('/:id/settings', async (request, reply) => await saveDestinationSettings(request));
|
fastify.post<SaveDestinationSettings>('/:id/settings', async (request) => await saveDestinationSettings(request));
|
||||||
fastify.post<Proxy>('/:id/start', async (request, reply) => await startProxy(request));
|
fastify.post<Proxy>('/:id/start', async (request,) => await startProxy(request));
|
||||||
fastify.post<Proxy>('/:id/stop', async (request, reply) => await stopProxy(request));
|
fastify.post<Proxy>('/:id/stop', async (request) => await stopProxy(request));
|
||||||
fastify.post<Proxy>('/:id/restart', async (request, reply) => await restartProxy(request));
|
fastify.post<Proxy>('/:id/restart', async (request) => await restartProxy(request));
|
||||||
|
|
||||||
|
fastify.post('/:id/configuration/sshKey', async (request) => await assignSSHKey(request));
|
||||||
|
|
||||||
|
fastify.post('/:id/verify', async (request, reply) => await verifyRemoteDockerEngine(request, reply));
|
||||||
};
|
};
|
||||||
|
|
||||||
export default root;
|
export default root;
|
||||||
|
|||||||
@ -1,15 +1,23 @@
|
|||||||
import { promises as dns } from 'dns';
|
import { promises as dns } from 'dns';
|
||||||
|
|
||||||
import type { FastifyReply, FastifyRequest } from 'fastify';
|
import type { FastifyReply, FastifyRequest } from 'fastify';
|
||||||
import { checkDomainsIsValidInDNS, errorHandler, getDomain, isDNSValid, isDomainConfigured, listSettings, prisma } from '../../../../lib/common';
|
import { checkDomainsIsValidInDNS, decrypt, encrypt, errorHandler, getDomain, isDNSValid, isDomainConfigured, listSettings, prisma } from '../../../../lib/common';
|
||||||
import { CheckDNS, CheckDomain, DeleteDomain, SaveSettings } from './types';
|
import { CheckDNS, CheckDomain, DeleteDomain, DeleteSSHKey, SaveSettings, SaveSSHKey } from './types';
|
||||||
|
|
||||||
|
|
||||||
export async function listAllSettings(request: FastifyRequest) {
|
export async function listAllSettings(request: FastifyRequest) {
|
||||||
try {
|
try {
|
||||||
const settings = await listSettings();
|
const settings = await listSettings();
|
||||||
|
const sshKeys = await prisma.sshKey.findMany()
|
||||||
|
const unencryptedKeys = []
|
||||||
|
if (sshKeys.length > 0) {
|
||||||
|
for (const key of sshKeys) {
|
||||||
|
unencryptedKeys.push({ id: key.id, name: key.name, privateKey: decrypt(key.privateKey), createdAt: key.createdAt })
|
||||||
|
}
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
settings
|
settings,
|
||||||
|
sshKeys: unencryptedKeys
|
||||||
}
|
}
|
||||||
} catch ({ status, message }) {
|
} catch ({ status, message }) {
|
||||||
return errorHandler({ status, message })
|
return errorHandler({ status, message })
|
||||||
@ -83,4 +91,30 @@ export async function checkDNS(request: FastifyRequest<CheckDNS>) {
|
|||||||
} catch ({ status, message }) {
|
} catch ({ status, message }) {
|
||||||
return errorHandler({ status, message })
|
return errorHandler({ status, message })
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function saveSSHKey(request: FastifyRequest<SaveSSHKey>, reply: FastifyReply) {
|
||||||
|
try {
|
||||||
|
const { privateKey, name } = request.body;
|
||||||
|
const found = await prisma.sshKey.findMany({ where: { name } })
|
||||||
|
if (found.length > 0) {
|
||||||
|
throw {
|
||||||
|
message: "Name already used. Choose another one please."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const encryptedSSHKey = encrypt(privateKey)
|
||||||
|
await prisma.sshKey.create({ data: { name, privateKey: encryptedSSHKey } })
|
||||||
|
return reply.code(201).send()
|
||||||
|
} catch ({ status, message }) {
|
||||||
|
return errorHandler({ status, message })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export async function deleteSSHKey(request: FastifyRequest<DeleteSSHKey>, reply: FastifyReply) {
|
||||||
|
try {
|
||||||
|
const { id } = request.body;
|
||||||
|
await prisma.sshKey.delete({ where: { id } })
|
||||||
|
return reply.code(201).send()
|
||||||
|
} catch ({ status, message }) {
|
||||||
|
return errorHandler({ status, message })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import { FastifyPluginAsync } from 'fastify';
|
import { FastifyPluginAsync } from 'fastify';
|
||||||
import { checkDNS, checkDomain, deleteDomain, listAllSettings, saveSettings } from './handlers';
|
import { checkDNS, checkDomain, deleteDomain, deleteSSHKey, listAllSettings, saveSettings, saveSSHKey } from './handlers';
|
||||||
import { CheckDNS, CheckDomain, DeleteDomain, SaveSettings } from './types';
|
import { CheckDNS, CheckDomain, DeleteDomain, DeleteSSHKey, SaveSettings, SaveSSHKey } from './types';
|
||||||
|
|
||||||
|
|
||||||
const root: FastifyPluginAsync = async (fastify): Promise<void> => {
|
const root: FastifyPluginAsync = async (fastify): Promise<void> => {
|
||||||
@ -13,6 +13,9 @@ const root: FastifyPluginAsync = async (fastify): Promise<void> => {
|
|||||||
|
|
||||||
fastify.get<CheckDNS>('/check', async (request) => await checkDNS(request));
|
fastify.get<CheckDNS>('/check', async (request) => await checkDNS(request));
|
||||||
fastify.post<CheckDomain>('/check', async (request) => await checkDomain(request));
|
fastify.post<CheckDomain>('/check', async (request) => await checkDomain(request));
|
||||||
|
|
||||||
|
fastify.post<SaveSSHKey>('/sshKey', async (request, reply) => await saveSSHKey(request, reply));
|
||||||
|
fastify.delete<DeleteSSHKey>('/sshKey', async (request, reply) => await deleteSSHKey(request, reply));
|
||||||
};
|
};
|
||||||
|
|
||||||
export default root;
|
export default root;
|
||||||
|
|||||||
@ -28,4 +28,15 @@ export interface CheckDNS {
|
|||||||
Params: {
|
Params: {
|
||||||
domain: string,
|
domain: string,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
export interface SaveSSHKey {
|
||||||
|
Body: {
|
||||||
|
privateKey: string,
|
||||||
|
name: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export interface DeleteSSHKey {
|
||||||
|
Body: {
|
||||||
|
id: string
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -15,13 +15,13 @@
|
|||||||
"format": "prettier --write --plugin-search-dir=. ."
|
"format": "prettier --write --plugin-search-dir=. ."
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@playwright/test": "1.23.3",
|
"@playwright/test": "1.23.4",
|
||||||
"@sveltejs/kit": "1.0.0-next.375",
|
"@sveltejs/kit": "1.0.0-next.377",
|
||||||
"@types/js-cookie": "3.0.2",
|
"@types/js-cookie": "3.0.2",
|
||||||
"@typescript-eslint/eslint-plugin": "5.30.6",
|
"@typescript-eslint/eslint-plugin": "5.30.6",
|
||||||
"@typescript-eslint/parser": "5.30.6",
|
"@typescript-eslint/parser": "5.30.6",
|
||||||
"autoprefixer": "10.4.7",
|
"autoprefixer": "10.4.7",
|
||||||
"eslint": "8.19.0",
|
"eslint": "8.20.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",
|
||||||
"postcss": "8.4.14",
|
"postcss": "8.4.14",
|
||||||
@ -34,11 +34,11 @@
|
|||||||
"tailwindcss-scrollbar": "0.1.0",
|
"tailwindcss-scrollbar": "0.1.0",
|
||||||
"tslib": "2.4.0",
|
"tslib": "2.4.0",
|
||||||
"typescript": "4.7.4",
|
"typescript": "4.7.4",
|
||||||
"vite": "^3.0.0"
|
"vite": "3.0.1"
|
||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sveltejs/adapter-static": "1.0.0-next.36",
|
"@sveltejs/adapter-static": "1.0.0-next.37",
|
||||||
"@zerodevx/svelte-toast": "0.7.2",
|
"@zerodevx/svelte-toast": "0.7.2",
|
||||||
"cuid": "2.1.8",
|
"cuid": "2.1.8",
|
||||||
"js-cookie": "3.0.1",
|
"js-cookie": "3.0.1",
|
||||||
|
|||||||
@ -142,9 +142,6 @@
|
|||||||
: $t('destination.force_restart_proxy')}</button
|
: $t('destination.force_restart_proxy')}</button
|
||||||
>
|
>
|
||||||
{/if}
|
{/if}
|
||||||
<!-- <button type="button" class="bg-coollabs hover:bg-coollabs-100" on:click={scanApps}
|
|
||||||
>Scan for applications</button
|
|
||||||
> -->
|
|
||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-2 items-center px-10 ">
|
<div class="grid grid-cols-2 items-center px-10 ">
|
||||||
<label for="name" class="text-base font-bold text-stone-100">{$t('forms.name')}</label>
|
<label for="name" class="text-base font-bold text-stone-100">{$t('forms.name')}</label>
|
||||||
@ -168,10 +165,6 @@
|
|||||||
value={destination.engine}
|
value={destination.engine}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<!-- <div class="flex items-center">
|
|
||||||
<label for="remoteEngine">Remote Engine?</label>
|
|
||||||
<input name="remoteEngine" type="checkbox" bind:checked={payload.remoteEngine} />
|
|
||||||
</div> -->
|
|
||||||
<div class="grid grid-cols-2 items-center px-10">
|
<div class="grid grid-cols-2 items-center px-10">
|
||||||
<label for="network" class="text-base font-bold text-stone-100">{$t('forms.network')}</label>
|
<label for="network" class="text-base font-bold text-stone-100">{$t('forms.network')}</label>
|
||||||
<CopyPasswordField
|
<CopyPasswordField
|
||||||
|
|||||||
@ -44,7 +44,7 @@
|
|||||||
<button class="w-32" on:click={() => setPredefined('localDocker')}
|
<button class="w-32" on:click={() => setPredefined('localDocker')}
|
||||||
>{$t('sources.local_docker')}</button
|
>{$t('sources.local_docker')}</button
|
||||||
>
|
>
|
||||||
<!-- <button class="w-32" on:click={() => setPredefined('remoteDocker')}>Remote Docker</button> -->
|
<button class="w-32" on:click={() => setPredefined('remoteDocker')}>Remote Docker</button>
|
||||||
<!-- <button class="w-32" on:click={() => setPredefined('kubernetes')}>Kubernetes</button> -->
|
<!-- <button class="w-32" on:click={() => setPredefined('kubernetes')}>Kubernetes</button> -->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -11,13 +11,19 @@
|
|||||||
let loading = false;
|
let loading = false;
|
||||||
|
|
||||||
async function handleSubmit() {
|
async function handleSubmit() {
|
||||||
|
if (loading) return;
|
||||||
try {
|
try {
|
||||||
const { id } = await post('/new/destination/docker', {
|
loading = true;
|
||||||
|
await post(`/destinations/check`, { network: payload.network });
|
||||||
|
const { id } = await post(`/destinations/new`, {
|
||||||
...payload
|
...payload
|
||||||
});
|
});
|
||||||
return await goto(`/destinations/${id}`);
|
await goto(`/destinations/${id}`);
|
||||||
|
window.location.reload();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return errorNotification(error);
|
return errorNotification(error);
|
||||||
|
} finally {
|
||||||
|
loading = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@ -64,20 +70,6 @@
|
|||||||
<label for="port" class="text-base font-bold text-stone-100">{$t('forms.port')}</label>
|
<label for="port" class="text-base font-bold text-stone-100">{$t('forms.port')}</label>
|
||||||
<input required name="port" placeholder="{$t('forms.eg')}: 22" bind:value={payload.port} />
|
<input required name="port" placeholder="{$t('forms.eg')}: 22" bind:value={payload.port} />
|
||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-2 items-center px-10">
|
|
||||||
<label for="sshPrivateKey" class="text-base font-bold text-stone-100"
|
|
||||||
>{$t('forms.ssh_private_key')}</label
|
|
||||||
>
|
|
||||||
<textarea
|
|
||||||
rows="10"
|
|
||||||
class="resize-none"
|
|
||||||
required
|
|
||||||
name="sshPrivateKey"
|
|
||||||
placeholder="{$t('forms.eg')}: -----BEGIN...."
|
|
||||||
bind:value={payload.sshPrivateKey}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="grid grid-cols-2 items-center px-10">
|
<div class="grid grid-cols-2 items-center px-10">
|
||||||
<label for="network" class="text-base font-bold text-stone-100">{$t('forms.network')}</label>
|
<label for="network" class="text-base font-bold text-stone-100">{$t('forms.network')}</label>
|
||||||
<input
|
<input
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
export let destination: any;
|
export let destination: any;
|
||||||
export let settings: any
|
export let settings: any;
|
||||||
export let state: any
|
export let state: any;
|
||||||
|
|
||||||
import { toast } from '@zerodevx/svelte-toast';
|
import { toast } from '@zerodevx/svelte-toast';
|
||||||
import { page, session } from '$app/stores';
|
import { page, session } from '$app/stores';
|
||||||
@ -10,50 +10,45 @@
|
|||||||
import CopyPasswordField from '$lib/components/CopyPasswordField.svelte';
|
import CopyPasswordField from '$lib/components/CopyPasswordField.svelte';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { t } from '$lib/translations';
|
import { t } from '$lib/translations';
|
||||||
import { errorNotification, generateRemoteEngine } from '$lib/common';
|
import { errorNotification, generateRemoteEngine } from '$lib/common';
|
||||||
import { appSession } from '$lib/store';
|
import { appSession } from '$lib/store';
|
||||||
const { id } = $page.params;
|
const { id } = $page.params;
|
||||||
let cannotDisable = settings.fqdn && destination.engine === '/var/run/docker.sock';
|
let cannotDisable = settings.fqdn && destination.engine === '/var/run/docker.sock';
|
||||||
// let scannedApps = [];
|
|
||||||
let loading = false;
|
let loading = false;
|
||||||
let restarting = false;
|
let restarting = false;
|
||||||
|
$: isDisabled = !$appSession.isAdmin;
|
||||||
|
|
||||||
async function handleSubmit() {
|
async function handleSubmit() {
|
||||||
loading = true;
|
loading = true;
|
||||||
try {
|
try {
|
||||||
return await post(`/destinations/${id}.json`, { ...destination });
|
return await post(`/destinations/${id}`, { ...destination });
|
||||||
} catch (error ) {
|
} catch (error) {
|
||||||
return errorNotification(error);
|
return errorNotification(error);
|
||||||
} finally {
|
} finally {
|
||||||
loading = false;
|
loading = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// async function scanApps() {
|
|
||||||
// scannedApps = [];
|
|
||||||
// const data = await fetch(`/destinations/${id}/scan.json`);
|
|
||||||
// const { containers } = await data.json();
|
|
||||||
// scannedApps = containers;
|
|
||||||
// }
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
if (state === false && destination.isCoolifyProxyUsed === true) {
|
if (state === false && destination.isCoolifyProxyUsed === true) {
|
||||||
destination.isCoolifyProxyUsed = !destination.isCoolifyProxyUsed;
|
destination.isCoolifyProxyUsed = !destination.isCoolifyProxyUsed;
|
||||||
try {
|
try {
|
||||||
await post(`/destinations/${id}/settings.json`, {
|
await post(`/destinations/${id}/settings`, {
|
||||||
isCoolifyProxyUsed: destination.isCoolifyProxyUsed,
|
isCoolifyProxyUsed: destination.isCoolifyProxyUsed,
|
||||||
engine: destination.engine
|
engine: destination.engine
|
||||||
});
|
});
|
||||||
await stopProxy();
|
await stopProxy();
|
||||||
} catch (error ) {
|
} catch (error) {
|
||||||
return errorNotification(error);
|
return errorNotification(error);
|
||||||
}
|
}
|
||||||
} else if (state === true && destination.isCoolifyProxyUsed === false) {
|
} else if (state === true && destination.isCoolifyProxyUsed === false) {
|
||||||
destination.isCoolifyProxyUsed = !destination.isCoolifyProxyUsed;
|
destination.isCoolifyProxyUsed = !destination.isCoolifyProxyUsed;
|
||||||
try {
|
try {
|
||||||
await post(`/destinations/${id}/settings.json`, {
|
await post(`/destinations/${id}/settings`, {
|
||||||
isCoolifyProxyUsed: destination.isCoolifyProxyUsed,
|
isCoolifyProxyUsed: destination.isCoolifyProxyUsed,
|
||||||
engine: destination.engine
|
engine: destination.engine
|
||||||
});
|
});
|
||||||
await startProxy();
|
await startProxy();
|
||||||
} catch ( error ) {
|
} catch (error) {
|
||||||
return errorNotification(error);
|
return errorNotification(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -73,7 +68,7 @@ import { appSession } from '$lib/store';
|
|||||||
}
|
}
|
||||||
destination.isCoolifyProxyUsed = !destination.isCoolifyProxyUsed;
|
destination.isCoolifyProxyUsed = !destination.isCoolifyProxyUsed;
|
||||||
try {
|
try {
|
||||||
await post(`/destinations/${id}/settings.json`, {
|
await post(`/destinations/${id}/settings`, {
|
||||||
isCoolifyProxyUsed: destination.isCoolifyProxyUsed,
|
isCoolifyProxyUsed: destination.isCoolifyProxyUsed,
|
||||||
engine: destination.engine
|
engine: destination.engine
|
||||||
});
|
});
|
||||||
@ -89,8 +84,7 @@ import { appSession } from '$lib/store';
|
|||||||
}
|
}
|
||||||
async function stopProxy() {
|
async function stopProxy() {
|
||||||
try {
|
try {
|
||||||
const engine = generateRemoteEngine(destination);
|
await post(`/destinations/${id}/stop`, { engine: destination.engine });
|
||||||
await post(`/destinations/${id}/stop.json`, { engine });
|
|
||||||
return toast.push($t('destination.coolify_proxy_stopped'));
|
return toast.push($t('destination.coolify_proxy_stopped'));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return errorNotification(error);
|
return errorNotification(error);
|
||||||
@ -98,8 +92,7 @@ import { appSession } from '$lib/store';
|
|||||||
}
|
}
|
||||||
async function startProxy() {
|
async function startProxy() {
|
||||||
try {
|
try {
|
||||||
const engine = generateRemoteEngine(destination);
|
await post(`/destinations/${id}/start`, { engine: destination.engine });
|
||||||
await post(`/destinations/${id}/start.json`, { engine });
|
|
||||||
return toast.push($t('destination.coolify_proxy_started'));
|
return toast.push($t('destination.coolify_proxy_started'));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return errorNotification(error);
|
return errorNotification(error);
|
||||||
@ -111,7 +104,7 @@ import { appSession } from '$lib/store';
|
|||||||
try {
|
try {
|
||||||
restarting = true;
|
restarting = true;
|
||||||
toast.push($t('destination.coolify_proxy_restarting'));
|
toast.push($t('destination.coolify_proxy_restarting'));
|
||||||
await post(`/destinations/${id}/restart.json`, {
|
await post(`/destinations/${id}/restart`, {
|
||||||
engine: destination.engine,
|
engine: destination.engine,
|
||||||
fqdn: settings.fqdn
|
fqdn: settings.fqdn
|
||||||
});
|
});
|
||||||
@ -119,9 +112,21 @@ import { appSession } from '$lib/store';
|
|||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
}, 5000);
|
}, 5000);
|
||||||
|
} finally {
|
||||||
|
restarting = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
async function verifyRemoteDocker() {
|
||||||
|
try {
|
||||||
|
loading = true;
|
||||||
|
return await post(`/destinations/${id}/verify`, {});
|
||||||
|
} catch (error) {
|
||||||
|
return errorNotification(error);
|
||||||
|
} finally {
|
||||||
|
loading = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<form on:submit|preventDefault={handleSubmit} class="grid grid-flow-row gap-2 py-4">
|
<form on:submit|preventDefault={handleSubmit} class="grid grid-flow-row gap-2 py-4">
|
||||||
@ -136,6 +141,11 @@ import { appSession } from '$lib/store';
|
|||||||
disabled={loading}
|
disabled={loading}
|
||||||
>{loading ? $t('forms.saving') : $t('forms.save')}
|
>{loading ? $t('forms.saving') : $t('forms.save')}
|
||||||
</button>
|
</button>
|
||||||
|
{#if !destination.remoteVerified}
|
||||||
|
<button on:click|preventDefault|stopPropagation={verifyRemoteDocker}
|
||||||
|
>Verify Remote Docker Engine</button
|
||||||
|
>
|
||||||
|
{/if}
|
||||||
<button
|
<button
|
||||||
class={restarting ? '' : 'bg-red-600 hover:bg-red-500'}
|
class={restarting ? '' : 'bg-red-600 hover:bg-red-500'}
|
||||||
disabled={restarting}
|
disabled={restarting}
|
||||||
@ -145,9 +155,6 @@ import { appSession } from '$lib/store';
|
|||||||
: $t('destination.force_restart_proxy')}</button
|
: $t('destination.force_restart_proxy')}</button
|
||||||
>
|
>
|
||||||
{/if}
|
{/if}
|
||||||
<!-- <button type="button" class="bg-coollabs hover:bg-coollabs-100" on:click={scanApps}
|
|
||||||
>Scan for applications</button
|
|
||||||
> -->
|
|
||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-2 items-center px-10 ">
|
<div class="grid grid-cols-2 items-center px-10 ">
|
||||||
<label for="name" class="text-base font-bold text-stone-100">{$t('forms.name')}</label>
|
<label for="name" class="text-base font-bold text-stone-100">{$t('forms.name')}</label>
|
||||||
@ -159,22 +166,6 @@ import { appSession } from '$lib/store';
|
|||||||
bind:value={destination.name}
|
bind:value={destination.name}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="grid grid-cols-2 items-center px-10">
|
|
||||||
<label for="engine" class="text-base font-bold text-stone-100">{$t('forms.engine')}</label>
|
|
||||||
<CopyPasswordField
|
|
||||||
id="engine"
|
|
||||||
readonly
|
|
||||||
disabled
|
|
||||||
name="engine"
|
|
||||||
placeholder="{$t('forms.eg')}: /var/run/docker.sock"
|
|
||||||
value={destination.engine}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<!-- <div class="flex items-center">
|
|
||||||
<label for="remoteEngine">Remote Engine?</label>
|
|
||||||
<input name="remoteEngine" type="checkbox" bind:checked={payload.remoteEngine} />
|
|
||||||
</div> -->
|
|
||||||
<div class="grid grid-cols-2 items-center px-10">
|
<div class="grid grid-cols-2 items-center px-10">
|
||||||
<label for="network" class="text-base font-bold text-stone-100">{$t('forms.network')}</label>
|
<label for="network" class="text-base font-bold text-stone-100">{$t('forms.network')}</label>
|
||||||
<CopyPasswordField
|
<CopyPasswordField
|
||||||
@ -186,6 +177,49 @@ import { appSession } from '$lib/store';
|
|||||||
value={destination.network}
|
value={destination.network}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="grid grid-cols-2 items-center px-10">
|
||||||
|
<label for="remoteIpAddress" class="text-base font-bold text-stone-100">IP Address</label>
|
||||||
|
<CopyPasswordField
|
||||||
|
id="remoteIpAddress"
|
||||||
|
readonly
|
||||||
|
disabled
|
||||||
|
name="remoteIpAddress"
|
||||||
|
value={destination.remoteIpAddress}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 items-center px-10">
|
||||||
|
<label for="remoteUser" class="text-base font-bold text-stone-100">User</label>
|
||||||
|
<CopyPasswordField
|
||||||
|
id="remoteUser"
|
||||||
|
readonly
|
||||||
|
disabled
|
||||||
|
name="remoteUser"
|
||||||
|
value={destination.remoteUser}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 items-center px-10">
|
||||||
|
<label for="remotePort" class="text-base font-bold text-stone-100">Port</label>
|
||||||
|
<CopyPasswordField
|
||||||
|
id="remotePort"
|
||||||
|
readonly
|
||||||
|
disabled
|
||||||
|
name="remotePort"
|
||||||
|
value={destination.remotePort}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 items-center px-10">
|
||||||
|
<label for="sshKey" class="text-base font-bold text-stone-100">SSH Key</label>
|
||||||
|
<a
|
||||||
|
href={!isDisabled ? `/destinations/${id}/configuration/sshkey?from=/destinations/${id}` : ''}
|
||||||
|
class="no-underline"
|
||||||
|
><input
|
||||||
|
value={destination.sshKey.name}
|
||||||
|
id="sshKey"
|
||||||
|
disabled
|
||||||
|
class="cursor-pointer hover:bg-coolgray-500"
|
||||||
|
/></a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
<div class="grid grid-cols-2 items-center">
|
<div class="grid grid-cols-2 items-center">
|
||||||
<Setting
|
<Setting
|
||||||
disabled={cannotDisable}
|
disabled={cannotDisable}
|
||||||
@ -200,27 +234,3 @@ import { appSession } from '$lib/store';
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<!-- <div class="flex justify-center">
|
|
||||||
{#if payload.isCoolifyProxyUsed}
|
|
||||||
{#if state}
|
|
||||||
<button on:click={stopProxy}>Stop proxy</button>
|
|
||||||
{:else}
|
|
||||||
<button on:click={startProxy}>Start proxy</button>
|
|
||||||
{/if}
|
|
||||||
{/if}
|
|
||||||
</div> -->
|
|
||||||
|
|
||||||
<!-- {#if scannedApps.length > 0}
|
|
||||||
<div class="flex justify-center px-6 pb-10">
|
|
||||||
<div class="flex space-x-2 h-8 items-center">
|
|
||||||
<div class="font-bold text-xl text-white">Found applications</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="max-w-4xl mx-auto px-6">
|
|
||||||
<div class="flex space-x-2 justify-center">
|
|
||||||
{#each scannedApps as app}
|
|
||||||
<FoundApp {app} />
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/if} -->
|
|
||||||
|
|||||||
@ -1,6 +1,14 @@
|
|||||||
<script context="module" lang="ts">
|
<script context="module" lang="ts">
|
||||||
import type { Load } from '@sveltejs/kit';
|
import type { Load } from '@sveltejs/kit';
|
||||||
export const load: Load = async ({ fetch, url, params }) => {
|
function checkConfiguration(destination: any): string | null {
|
||||||
|
let configurationPhase = null;
|
||||||
|
if (!destination?.remoteEngine) return configurationPhase;
|
||||||
|
if (!destination?.sshKey) {
|
||||||
|
configurationPhase = 'sshkey';
|
||||||
|
}
|
||||||
|
return configurationPhase;
|
||||||
|
}
|
||||||
|
export const load: Load = async ({ url, params }) => {
|
||||||
try {
|
try {
|
||||||
const { id } = params;
|
const { id } = params;
|
||||||
const response = await get(`/destinations/${id}`);
|
const response = await get(`/destinations/${id}`);
|
||||||
@ -11,6 +19,17 @@
|
|||||||
redirect: '/destinations'
|
redirect: '/destinations'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
const configurationPhase = checkConfiguration(destination);
|
||||||
|
if (
|
||||||
|
configurationPhase &&
|
||||||
|
url.pathname !== `/destinations/${params.id}/configuration/${configurationPhase}`
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
status: 302,
|
||||||
|
redirect: `/destinations/${params.id}/configuration/${configurationPhase}`
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
destination
|
destination
|
||||||
@ -22,6 +41,7 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
return handlerNotFoundLoad(error, url);
|
return handlerNotFoundLoad(error, url);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -0,0 +1,59 @@
|
|||||||
|
<script context="module" lang="ts">
|
||||||
|
import type { Load } from '@sveltejs/kit';
|
||||||
|
export const load: Load = async ({ fetch, params, url, stuff }) => {
|
||||||
|
try {
|
||||||
|
const response = await get(`/settings`);
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
...response
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
status: 500,
|
||||||
|
error: new Error(`Could not load ${url}`)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
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');
|
||||||
|
|
||||||
|
export let sshKeys: any;
|
||||||
|
|
||||||
|
async function handleSubmit(sshKeyId: string) {
|
||||||
|
try {
|
||||||
|
await post(`/destinations/${id}/configuration/sshKey`, { id: sshKeyId });
|
||||||
|
return await goto(from || `/destinations/${id}`);
|
||||||
|
} catch (error) {
|
||||||
|
return errorNotification(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="flex space-x-1 p-6 font-bold">
|
||||||
|
<div class="mr-4 text-2xl tracking-tight">SSH Keys</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col justify-center">
|
||||||
|
<div class="flex flex-col flex-wrap justify-center px-2 md:flex-row ">
|
||||||
|
{#each sshKeys as sshKey}
|
||||||
|
<div class="p-2 relative">
|
||||||
|
<form on:submit|preventDefault={() => handleSubmit(sshKey.id)}>
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
class="disabled:opacity-95 bg-coolgray-200 disabled:text-white box-selection hover:bg-orange-700 group"
|
||||||
|
>
|
||||||
|
<div class="font-bold text-xl text-center truncate">{sshKey.name}</div>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@ -73,6 +73,9 @@
|
|||||||
<div class="truncate text-center">{destination.teams[0].name}</div>
|
<div class="truncate text-center">{destination.teams[0].name}</div>
|
||||||
{/if}
|
{/if}
|
||||||
<div class="truncate text-center">{destination.network}</div>
|
<div class="truncate text-center">{destination.network}</div>
|
||||||
|
{#if $appSession.teamId === '0' && destination.remoteVerified === false && destination.remoteEngine}
|
||||||
|
<div class="truncate text-center text-sm text-red-500">Not verified yet</div>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
{/each}
|
{/each}
|
||||||
|
|||||||
@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
export let settings: any;
|
export let settings: any;
|
||||||
|
export let sshKeys: any;
|
||||||
import Setting from '$lib/components/Setting.svelte';
|
import Setting from '$lib/components/Setting.svelte';
|
||||||
import Explainer from '$lib/components/Explainer.svelte';
|
import Explainer from '$lib/components/Explainer.svelte';
|
||||||
import { del, get, post } from '$lib/api';
|
import { del, get, post } from '$lib/api';
|
||||||
@ -51,13 +51,20 @@
|
|||||||
proxyMigration: false
|
proxyMigration: false
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let subMenuActive: any = 'globalsettings';
|
||||||
|
let isModalActive = false;
|
||||||
|
|
||||||
|
let newSSHKey = {
|
||||||
|
name: null,
|
||||||
|
privateKey: null
|
||||||
|
};
|
||||||
async function removeFqdn() {
|
async function removeFqdn() {
|
||||||
if (fqdn) {
|
if (fqdn) {
|
||||||
loading.remove = true;
|
loading.remove = true;
|
||||||
try {
|
try {
|
||||||
const { redirect } = await del(`/settings`, { fqdn });
|
const { redirect } = await del(`/settings`, { fqdn });
|
||||||
return redirect ? window.location.replace(redirect) : window.location.reload();
|
return redirect ? window.location.replace(redirect) : window.location.reload();
|
||||||
} catch (error ) {
|
} catch (error) {
|
||||||
return errorNotification(error);
|
return errorNotification(error);
|
||||||
} finally {
|
} finally {
|
||||||
loading.remove = false;
|
loading.remove = false;
|
||||||
@ -107,7 +114,7 @@
|
|||||||
settings.maxPort = maxPort;
|
settings.maxPort = maxPort;
|
||||||
}
|
}
|
||||||
forceSave = false;
|
forceSave = false;
|
||||||
} catch (error ) {
|
} catch (error) {
|
||||||
if (error.message?.startsWith($t('application.dns_not_set_partial_error'))) {
|
if (error.message?.startsWith($t('application.dns_not_set_partial_error'))) {
|
||||||
forceSave = true;
|
forceSave = true;
|
||||||
if (dualCerts) {
|
if (dualCerts) {
|
||||||
@ -122,7 +129,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log(error)
|
console.log(error);
|
||||||
return errorNotification(error);
|
return errorNotification(error);
|
||||||
} finally {
|
} finally {
|
||||||
loading.save = false;
|
loading.save = false;
|
||||||
@ -143,18 +150,23 @@
|
|||||||
function resetView() {
|
function resetView() {
|
||||||
forceSave = false;
|
forceSave = false;
|
||||||
}
|
}
|
||||||
async function migrateProxy(to: any) {
|
async function saveSSHKey() {
|
||||||
if (loading.proxyMigration) return;
|
|
||||||
try {
|
try {
|
||||||
loading.proxyMigration = true;
|
await post(`/settings/sshKey`, { ...newSSHKey });
|
||||||
await post(`/update`, { type: to });
|
return window.location.reload();
|
||||||
const data = await get(`/settings`);
|
|
||||||
$isTraefikUsed = data.settings.isTraefikUsed;
|
|
||||||
return toast.push('Proxy migration started, it takes a few seconds.');
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return errorNotification(error);
|
errorNotification(error);
|
||||||
} finally {
|
return false;
|
||||||
loading.proxyMigration = false;
|
}
|
||||||
|
}
|
||||||
|
async function deleteSSHKey(id: string) {
|
||||||
|
try {
|
||||||
|
if (!id) return
|
||||||
|
await del(`/settings/sshKey`, { id });
|
||||||
|
return window.location.reload();
|
||||||
|
} catch (error) {
|
||||||
|
errorNotification(error);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@ -162,196 +174,303 @@
|
|||||||
<div class="flex space-x-1 p-6 font-bold">
|
<div class="flex space-x-1 p-6 font-bold">
|
||||||
<div class="mr-4 text-2xl tracking-tight">{$t('index.settings')}</div>
|
<div class="mr-4 text-2xl tracking-tight">{$t('index.settings')}</div>
|
||||||
</div>
|
</div>
|
||||||
{#if $appSession.teamId === '0'}
|
<div class="mx-auto w-full">
|
||||||
<div class="mx-auto max-w-4xl px-6">
|
<div class="flex flex-row">
|
||||||
<form on:submit|preventDefault={handleSubmit} class="grid grid-flow-row gap-2 py-4">
|
<div class="flex flex-col pt-4 space-y-6 w-96 px-20">
|
||||||
<div class="flex space-x-1 pb-6">
|
<div
|
||||||
<div class="title font-bold">{$t('index.global_settings')}</div>
|
class="sub-menu"
|
||||||
<button
|
class:sub-menu-active={subMenuActive === 'globalsettings'}
|
||||||
type="submit"
|
on:click={() => (subMenuActive = 'globalsettings')}
|
||||||
class:bg-green-600={!loading.save}
|
>
|
||||||
class:bg-orange-600={forceSave}
|
Global Settings
|
||||||
class:hover:bg-green-500={!loading.save}
|
|
||||||
class:hover:bg-orange-400={forceSave}
|
|
||||||
disabled={loading.save}
|
|
||||||
>{loading.save
|
|
||||||
? $t('forms.saving')
|
|
||||||
: forceSave
|
|
||||||
? $t('forms.confirm_continue')
|
|
||||||
: $t('forms.save')}</button
|
|
||||||
>
|
|
||||||
|
|
||||||
{#if isFqdnSet}
|
|
||||||
<button
|
|
||||||
on:click|preventDefault={removeFqdn}
|
|
||||||
disabled={loading.remove}
|
|
||||||
class:bg-red-600={!loading.remove}
|
|
||||||
class:hover:bg-red-500={!loading.remove}
|
|
||||||
>{loading.remove ? $t('forms.removing') : $t('forms.remove_domain')}</button
|
|
||||||
>
|
|
||||||
{/if}
|
|
||||||
</div>
|
</div>
|
||||||
<div class="grid grid-flow-row gap-2 px-10">
|
<div
|
||||||
<!-- <Language /> -->
|
class="sub-menu"
|
||||||
<div class="grid grid-cols-2 items-start">
|
class:sub-menu-active={subMenuActive === 'sshkey'}
|
||||||
<div class="flex-col">
|
on:click={() => (subMenuActive = 'sshkey')}
|
||||||
<div class="pt-2 text-base font-bold text-stone-100">
|
>
|
||||||
{$t('application.url_fqdn')}
|
SSH Keys
|
||||||
</div>
|
</div>
|
||||||
<Explainer text={$t('setting.ssl_explainer')} />
|
</div>
|
||||||
</div>
|
<div class="pl-40">
|
||||||
<div class="justify-start text-left">
|
{#if $appSession.teamId === '0'}
|
||||||
<input
|
{#if subMenuActive === 'globalsettings'}
|
||||||
bind:value={fqdn}
|
<form on:submit|preventDefault={handleSubmit} class="grid grid-flow-row gap-2 py-4">
|
||||||
readonly={!$appSession.isAdmin || isFqdnSet}
|
<div class="flex space-x-1 pb-6">
|
||||||
disabled={!$appSession.isAdmin || isFqdnSet}
|
<div class="title font-bold">{$t('index.global_settings')}</div>
|
||||||
on:input={resetView}
|
<button
|
||||||
name="fqdn"
|
type="submit"
|
||||||
id="fqdn"
|
class:bg-yellow-500={!loading.save}
|
||||||
pattern="^https?://([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{'{'}2,{'}'}$"
|
class:bg-orange-600={forceSave}
|
||||||
placeholder="{$t('forms.eg')}: https://coolify.io"
|
class:hover:bg-yellow-500={!loading.save}
|
||||||
/>
|
class:hover:bg-orange-400={forceSave}
|
||||||
|
disabled={loading.save}
|
||||||
|
>{loading.save
|
||||||
|
? $t('forms.saving')
|
||||||
|
: forceSave
|
||||||
|
? $t('forms.confirm_continue')
|
||||||
|
: $t('forms.save')}</button
|
||||||
|
>
|
||||||
|
|
||||||
{#if forceSave}
|
{#if isFqdnSet}
|
||||||
<div class="flex-col space-y-2 pt-4 text-center">
|
<button
|
||||||
{#if isNonWWWDomainOK}
|
on:click|preventDefault={removeFqdn}
|
||||||
<button
|
disabled={loading.remove}
|
||||||
class="bg-green-600 hover:bg-green-500"
|
class:bg-red-600={!loading.remove}
|
||||||
on:click|preventDefault={() => isDNSValid(getDomain(nonWWWDomain), false)}
|
class:hover:bg-red-500={!loading.remove}
|
||||||
>DNS settings for {nonWWWDomain} is OK, click to recheck.</button
|
>{loading.remove ? $t('forms.removing') : $t('forms.remove_domain')}</button
|
||||||
>
|
>
|
||||||
{:else}
|
{/if}
|
||||||
<button
|
</div>
|
||||||
class="bg-red-600 hover:bg-red-500"
|
<div class="grid grid-flow-row gap-2 px-10">
|
||||||
on:click|preventDefault={() => isDNSValid(getDomain(nonWWWDomain), false)}
|
<!-- <Language /> -->
|
||||||
>DNS settings for {nonWWWDomain} is invalid, click to recheck.</button
|
<div class="grid grid-cols-2 items-start">
|
||||||
>
|
<div class="flex-col">
|
||||||
{/if}
|
<div class="pt-2 text-base font-bold text-stone-100">
|
||||||
{#if dualCerts}
|
{$t('application.url_fqdn')}
|
||||||
{#if isWWWDomainOK}
|
</div>
|
||||||
<button
|
<Explainer text={$t('setting.ssl_explainer')} />
|
||||||
class="bg-green-600 hover:bg-green-500"
|
</div>
|
||||||
on:click|preventDefault={() =>
|
<div class="justify-start text-left">
|
||||||
isDNSValid(getDomain(`www.${nonWWWDomain}`), true)}
|
<input
|
||||||
>DNS settings for www.{nonWWWDomain} is OK, click to recheck.</button
|
bind:value={fqdn}
|
||||||
>
|
readonly={!$appSession.isAdmin || isFqdnSet}
|
||||||
{:else}
|
disabled={!$appSession.isAdmin || isFqdnSet}
|
||||||
<button
|
on:input={resetView}
|
||||||
class="bg-red-600 hover:bg-red-500"
|
name="fqdn"
|
||||||
on:click|preventDefault={() =>
|
id="fqdn"
|
||||||
isDNSValid(getDomain(`www.${nonWWWDomain}`), true)}
|
pattern="^https?://([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{'{'}2,{'}'}$"
|
||||||
>DNS settings for www.{nonWWWDomain} is invalid, click to recheck.</button
|
placeholder="{$t('forms.eg')}: https://coolify.io"
|
||||||
>
|
/>
|
||||||
|
|
||||||
|
{#if forceSave}
|
||||||
|
<div class="flex-col space-y-2 pt-4 text-center">
|
||||||
|
{#if isNonWWWDomainOK}
|
||||||
|
<button
|
||||||
|
class="bg-green-600 hover:bg-green-500"
|
||||||
|
on:click|preventDefault={() => isDNSValid(getDomain(nonWWWDomain), false)}
|
||||||
|
>DNS settings for {nonWWWDomain} is OK, click to recheck.</button
|
||||||
|
>
|
||||||
|
{:else}
|
||||||
|
<button
|
||||||
|
class="bg-red-600 hover:bg-red-500"
|
||||||
|
on:click|preventDefault={() => isDNSValid(getDomain(nonWWWDomain), false)}
|
||||||
|
>DNS settings for {nonWWWDomain} is invalid, click to recheck.</button
|
||||||
|
>
|
||||||
|
{/if}
|
||||||
|
{#if dualCerts}
|
||||||
|
{#if isWWWDomainOK}
|
||||||
|
<button
|
||||||
|
class="bg-green-600 hover:bg-green-500"
|
||||||
|
on:click|preventDefault={() =>
|
||||||
|
isDNSValid(getDomain(`www.${nonWWWDomain}`), true)}
|
||||||
|
>DNS settings for www.{nonWWWDomain} is OK, click to recheck.</button
|
||||||
|
>
|
||||||
|
{:else}
|
||||||
|
<button
|
||||||
|
class="bg-red-600 hover:bg-red-500"
|
||||||
|
on:click|preventDefault={() =>
|
||||||
|
isDNSValid(getDomain(`www.${nonWWWDomain}`), true)}
|
||||||
|
>DNS settings for www.{nonWWWDomain} is invalid, click to recheck.</button
|
||||||
|
>
|
||||||
|
{/if}
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
<div class="grid grid-cols-2 items-start py-6">
|
||||||
</div>
|
<div class="flex-col">
|
||||||
</div>
|
<div class="pt-2 text-base font-bold text-stone-100">
|
||||||
<div class="grid grid-cols-2 items-start py-6">
|
{$t('forms.public_port_range')}
|
||||||
<div class="flex-col">
|
</div>
|
||||||
<div class="pt-2 text-base font-bold text-stone-100">
|
<Explainer text={$t('forms.public_port_range_explainer')} />
|
||||||
{$t('forms.public_port_range')}
|
</div>
|
||||||
|
<div class="mx-auto flex-row items-center justify-center space-y-2">
|
||||||
|
<input
|
||||||
|
class="h-8 w-20 px-2"
|
||||||
|
type="number"
|
||||||
|
bind:value={minPort}
|
||||||
|
min="1024"
|
||||||
|
max={maxPort}
|
||||||
|
/>
|
||||||
|
-
|
||||||
|
<input
|
||||||
|
class="h-8 w-20 px-2"
|
||||||
|
type="number"
|
||||||
|
bind:value={maxPort}
|
||||||
|
min={minPort}
|
||||||
|
max="65543"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 items-center">
|
||||||
|
<Setting
|
||||||
|
bind:setting={isDNSCheckEnabled}
|
||||||
|
title={$t('setting.is_dns_check_enabled')}
|
||||||
|
description={$t('setting.is_dns_check_enabled_explainer')}
|
||||||
|
on:click={() => changeSettings('isDNSCheckEnabled')}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 items-center">
|
||||||
|
<Setting
|
||||||
|
dataTooltip={$t('setting.must_remove_domain_before_changing')}
|
||||||
|
disabled={isFqdnSet}
|
||||||
|
bind:setting={dualCerts}
|
||||||
|
title={$t('application.ssl_www_and_non_www')}
|
||||||
|
description={$t('setting.generate_www_non_www_ssl')}
|
||||||
|
on:click={() => !isFqdnSet && changeSettings('dualCerts')}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 items-center">
|
||||||
|
<Setting
|
||||||
|
bind:setting={isRegistrationEnabled}
|
||||||
|
title={$t('setting.registration_allowed')}
|
||||||
|
description={$t('setting.registration_allowed_explainer')}
|
||||||
|
on:click={() => changeSettings('isRegistrationEnabled')}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{#if browser && $features.beta}
|
||||||
|
<div class="grid grid-cols-2 items-center">
|
||||||
|
<Setting
|
||||||
|
bind:setting={isAutoUpdateEnabled}
|
||||||
|
title={$t('setting.auto_update_enabled')}
|
||||||
|
description={$t('setting.auto_update_enabled_explainer')}
|
||||||
|
on:click={() => changeSettings('isAutoUpdateEnabled')}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<Explainer text={$t('forms.public_port_range_explainer')} />
|
</form>
|
||||||
</div>
|
{#if !settings.isTraefikUsed}
|
||||||
<div class="mx-auto flex-row items-center justify-center space-y-2">
|
<div class="flex space-x-1 pt-6 font-bold">
|
||||||
<input
|
<div class="title">{$t('setting.coolify_proxy_settings')}</div>
|
||||||
class="h-8 w-20 px-2"
|
</div>
|
||||||
type="number"
|
<Explainer
|
||||||
bind:value={minPort}
|
text={$t('setting.credential_stat_explainer', {
|
||||||
min="1024"
|
link: fqdn
|
||||||
max={maxPort}
|
? `http://${settings.proxyUser}:${settings.proxyPassword}@` +
|
||||||
/>
|
getDomain(fqdn) +
|
||||||
-
|
':8404'
|
||||||
<input
|
: browser &&
|
||||||
class="h-8 w-20 px-2"
|
`http://${settings.proxyUser}:${settings.proxyPassword}@` +
|
||||||
type="number"
|
window.location.hostname +
|
||||||
bind:value={maxPort}
|
':8404'
|
||||||
min={minPort}
|
})}
|
||||||
max="65543"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="grid grid-cols-2 items-center">
|
|
||||||
<Setting
|
|
||||||
bind:setting={isDNSCheckEnabled}
|
|
||||||
title={$t('setting.is_dns_check_enabled')}
|
|
||||||
description={$t('setting.is_dns_check_enabled_explainer')}
|
|
||||||
on:click={() => changeSettings('isDNSCheckEnabled')}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="grid grid-cols-2 items-center">
|
|
||||||
<Setting
|
|
||||||
dataTooltip={$t('setting.must_remove_domain_before_changing')}
|
|
||||||
disabled={isFqdnSet}
|
|
||||||
bind:setting={dualCerts}
|
|
||||||
title={$t('application.ssl_www_and_non_www')}
|
|
||||||
description={$t('setting.generate_www_non_www_ssl')}
|
|
||||||
on:click={() => !isFqdnSet && changeSettings('dualCerts')}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="grid grid-cols-2 items-center">
|
|
||||||
<Setting
|
|
||||||
bind:setting={isRegistrationEnabled}
|
|
||||||
title={$t('setting.registration_allowed')}
|
|
||||||
description={$t('setting.registration_allowed_explainer')}
|
|
||||||
on:click={() => changeSettings('isRegistrationEnabled')}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
{#if browser && $features.beta}
|
|
||||||
<div class="grid grid-cols-2 items-center">
|
|
||||||
<Setting
|
|
||||||
bind:setting={isAutoUpdateEnabled}
|
|
||||||
title={$t('setting.auto_update_enabled')}
|
|
||||||
description={$t('setting.auto_update_enabled_explainer')}
|
|
||||||
on:click={() => changeSettings('isAutoUpdateEnabled')}
|
|
||||||
/>
|
/>
|
||||||
|
<div class="space-y-2 px-10 py-5">
|
||||||
|
<div class="grid grid-cols-2 items-center">
|
||||||
|
<label for="proxyUser">{$t('forms.user')}</label>
|
||||||
|
<CopyPasswordField
|
||||||
|
readonly
|
||||||
|
disabled
|
||||||
|
id="proxyUser"
|
||||||
|
name="proxyUser"
|
||||||
|
value={settings.proxyUser}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 items-center">
|
||||||
|
<label for="proxyPassword">{$t('forms.password')}</label>
|
||||||
|
<CopyPasswordField
|
||||||
|
readonly
|
||||||
|
disabled
|
||||||
|
id="proxyPassword"
|
||||||
|
name="proxyPassword"
|
||||||
|
isPasswordField
|
||||||
|
value={settings.proxyPassword}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{/if}
|
||||||
|
{#if subMenuActive === 'sshkey'}
|
||||||
|
<div class="grid grid-flow-row gap-2 py-4">
|
||||||
|
<div class="flex space-x-1 pb-6">
|
||||||
|
<div class="title font-bold">SSH Keys</div>
|
||||||
|
<button
|
||||||
|
on:click={() => (isModalActive = true)}
|
||||||
|
class:bg-yellow-500={!loading.save}
|
||||||
|
class:hover:bg-yellow-400={!loading.save}
|
||||||
|
disabled={loading.save}>New SSH Key</button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-flow-col gap-2 px-10">
|
||||||
|
{#if sshKeys.length === 0}
|
||||||
|
<div class="text-sm ">No SSH keys found</div>
|
||||||
|
{:else}
|
||||||
|
{#each sshKeys as key}
|
||||||
|
<div class="box-selection group relative">
|
||||||
|
<div class="text-xl font-bold">{key.name}</div>
|
||||||
|
<div class="py-3 text-stone-600">Added on {key.createdAt}</div>
|
||||||
|
<button on:click={() => deleteSSHKey(key.id)} class="bg-red-500">Delete</button>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
{/if}
|
||||||
</form>
|
|
||||||
{#if !settings.isTraefikUsed}
|
|
||||||
<div class="flex space-x-1 pt-6 font-bold">
|
|
||||||
<div class="title">{$t('setting.coolify_proxy_settings')}</div>
|
|
||||||
</div>
|
</div>
|
||||||
<Explainer
|
|
||||||
text={$t('setting.credential_stat_explainer', {
|
|
||||||
link: fqdn
|
|
||||||
? `http://${settings.proxyUser}:${settings.proxyPassword}@` + getDomain(fqdn) + ':8404'
|
|
||||||
: browser &&
|
|
||||||
`http://${settings.proxyUser}:${settings.proxyPassword}@` +
|
|
||||||
window.location.hostname +
|
|
||||||
':8404'
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
<div class="space-y-2 px-10 py-5">
|
|
||||||
<div class="grid grid-cols-2 items-center">
|
|
||||||
<label for="proxyUser">{$t('forms.user')}</label>
|
|
||||||
<CopyPasswordField
|
|
||||||
readonly
|
|
||||||
disabled
|
|
||||||
id="proxyUser"
|
|
||||||
name="proxyUser"
|
|
||||||
value={settings.proxyUser}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="grid grid-cols-2 items-center">
|
|
||||||
<label for="proxyPassword">{$t('forms.password')}</label>
|
|
||||||
<CopyPasswordField
|
|
||||||
readonly
|
|
||||||
disabled
|
|
||||||
id="proxyPassword"
|
|
||||||
name="proxyPassword"
|
|
||||||
isPasswordField
|
|
||||||
value={settings.proxyPassword}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
</div>
|
||||||
<div class="mx-auto max-w-4xl px-6">
|
|
||||||
<!-- <Language /> -->
|
{#if isModalActive}
|
||||||
|
<div class="relative z-10" aria-labelledby="modal-title" role="dialog" aria-modal="true">
|
||||||
|
<div class="fixed inset-0 bg-coolgray-500 bg-opacity-75 transition-opacity" />
|
||||||
|
|
||||||
|
<div class="fixed z-10 inset-0 overflow-y-auto text-white">
|
||||||
|
<div class="flex items-end sm:items-center justify-center min-h-full p-4 text-center sm:p-0">
|
||||||
|
<div
|
||||||
|
class="relative bg-coolblack rounded-lg px-4 pt-5 pb-4 text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:max-w-lg sm:w-full sm:p-6 border border-coolgray-500"
|
||||||
|
>
|
||||||
|
<div class="hidden sm:block absolute top-0 right-0 pt-4 pr-4">
|
||||||
|
<button
|
||||||
|
on:click={() => (isModalActive = false)}
|
||||||
|
type="button"
|
||||||
|
class=" rounded-md text-white focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
|
||||||
|
>
|
||||||
|
<span class="sr-only">Close</span>
|
||||||
|
<svg
|
||||||
|
class="h-6 w-6"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke="currentColor"
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="sm:flex sm:items-start">
|
||||||
|
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
|
||||||
|
<h3 class="text-lg leading-6 font-medium pb-4" id="modal-title">New SSH Key</h3>
|
||||||
|
<div class="text-xs text-stone-400">Add an SSH key to your Coolify instance.</div>
|
||||||
|
<div class="mt-2">
|
||||||
|
<label for="privateKey" class="pb-2">Key</label>
|
||||||
|
<textarea
|
||||||
|
id="privateKey"
|
||||||
|
required
|
||||||
|
bind:value={newSSHKey.privateKey}
|
||||||
|
class="w-full"
|
||||||
|
rows={15}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="mt-2">
|
||||||
|
<label for="name" class="pb-2">Name</label>
|
||||||
|
<input id="name" required bind:value={newSSHKey.name} class="w-full" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-5 flex space-x-4 justify-end">
|
||||||
|
<button on:click={saveSSHKey} type="button" class="bg-green-600 hover:bg-green-500"
|
||||||
|
>Save</button
|
||||||
|
>
|
||||||
|
<button on:click={() => (isModalActive = false)} type="button" class="">Cancel</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@ -395,3 +395,11 @@ a {
|
|||||||
transform: scale(0.9);
|
transform: scale(0.9);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sub-menu {
|
||||||
|
@apply text-xl font-bold hover:bg-coolgray-500 rounded p-2 hover:text-white text-stone-200 cursor-pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sub-menu-active {
|
||||||
|
@apply bg-coolgray-500 text-white;
|
||||||
|
}
|
||||||
182
pnpm-lock.yaml
generated
182
pnpm-lock.yaml
generated
@ -14,14 +14,14 @@ importers:
|
|||||||
specifiers:
|
specifiers:
|
||||||
'@breejs/ts-worker': 2.0.0
|
'@breejs/ts-worker': 2.0.0
|
||||||
'@fastify/autoload': 5.1.0
|
'@fastify/autoload': 5.1.0
|
||||||
'@fastify/cookie': 7.1.0
|
'@fastify/cookie': 7.2.0
|
||||||
'@fastify/cors': 8.0.0
|
'@fastify/cors': 8.0.0
|
||||||
'@fastify/env': 4.0.0
|
'@fastify/env': 4.0.0
|
||||||
'@fastify/jwt': 6.3.1
|
'@fastify/jwt': 6.3.1
|
||||||
'@fastify/static': 6.4.0
|
'@fastify/static': 6.4.0
|
||||||
'@iarna/toml': 2.2.5
|
'@iarna/toml': 2.2.5
|
||||||
'@prisma/client': 3.15.2
|
'@prisma/client': 3.15.2
|
||||||
'@types/node': 18.0.4
|
'@types/node': 18.0.6
|
||||||
'@types/node-os-utils': 1.3.0
|
'@types/node-os-utils': 1.3.0
|
||||||
'@typescript-eslint/eslint-plugin': 5.30.6
|
'@typescript-eslint/eslint-plugin': 5.30.6
|
||||||
'@typescript-eslint/parser': 5.30.6
|
'@typescript-eslint/parser': 5.30.6
|
||||||
@ -35,7 +35,7 @@ importers:
|
|||||||
dockerode: 3.3.2
|
dockerode: 3.3.2
|
||||||
dotenv-extended: 2.9.0
|
dotenv-extended: 2.9.0
|
||||||
esbuild: 0.14.49
|
esbuild: 0.14.49
|
||||||
eslint: 8.19.0
|
eslint: 8.20.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
|
||||||
fastify: 4.2.1
|
fastify: 4.2.1
|
||||||
@ -53,15 +53,15 @@ importers:
|
|||||||
prettier: 2.7.1
|
prettier: 2.7.1
|
||||||
prisma: 3.15.2
|
prisma: 3.15.2
|
||||||
rimraf: 3.0.2
|
rimraf: 3.0.2
|
||||||
shared: workspace:*
|
ssh-config: ^4.1.6
|
||||||
strip-ansi: 7.0.1
|
strip-ansi: 7.0.1
|
||||||
tsconfig-paths: 4.0.0
|
tsconfig-paths: 4.0.0
|
||||||
typescript: 4.7.4
|
typescript: 4.7.4
|
||||||
unique-names-generator: 4.7.1
|
unique-names-generator: 4.7.1
|
||||||
dependencies:
|
dependencies:
|
||||||
'@breejs/ts-worker': 2.0.0_t3dw2jfpvj5qtbx4qztd4nt754
|
'@breejs/ts-worker': 2.0.0_25g7irgsr6ywin2g3nrhhgteo4
|
||||||
'@fastify/autoload': 5.1.0
|
'@fastify/autoload': 5.1.0
|
||||||
'@fastify/cookie': 7.1.0
|
'@fastify/cookie': 7.2.0
|
||||||
'@fastify/cors': 8.0.0
|
'@fastify/cors': 8.0.0
|
||||||
'@fastify/env': 4.0.0
|
'@fastify/env': 4.0.0
|
||||||
'@fastify/jwt': 6.3.1
|
'@fastify/jwt': 6.3.1
|
||||||
@ -88,18 +88,18 @@ importers:
|
|||||||
node-forge: 1.3.1
|
node-forge: 1.3.1
|
||||||
node-os-utils: 1.3.7
|
node-os-utils: 1.3.7
|
||||||
p-queue: 7.2.0
|
p-queue: 7.2.0
|
||||||
shared: link:../shared
|
ssh-config: 4.1.6
|
||||||
strip-ansi: 7.0.1
|
strip-ansi: 7.0.1
|
||||||
unique-names-generator: 4.7.1
|
unique-names-generator: 4.7.1
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@types/node': 18.0.4
|
'@types/node': 18.0.6
|
||||||
'@types/node-os-utils': 1.3.0
|
'@types/node-os-utils': 1.3.0
|
||||||
'@typescript-eslint/eslint-plugin': 5.30.6_2vt5mtrqleafs33qg2bhpmbaqm
|
'@typescript-eslint/eslint-plugin': 5.30.6_b7n364ggt6o4xlkgyoaww3ph3q
|
||||||
'@typescript-eslint/parser': 5.30.6_4x5o4skxv6sl53vpwefgt23khm
|
'@typescript-eslint/parser': 5.30.6_he2ccbldppg44uulnyq4rwocfa
|
||||||
esbuild: 0.14.49
|
esbuild: 0.14.49
|
||||||
eslint: 8.19.0
|
eslint: 8.20.0
|
||||||
eslint-config-prettier: 8.5.0_eslint@8.19.0
|
eslint-config-prettier: 8.5.0_eslint@8.20.0
|
||||||
eslint-plugin-prettier: 4.2.1_7uxdfn2xinezdgvmbammh6ev5i
|
eslint-plugin-prettier: 4.2.1_g4fztgbwjyq2fvmcscny2sj6fy
|
||||||
nodemon: 2.0.19
|
nodemon: 2.0.19
|
||||||
prettier: 2.7.1
|
prettier: 2.7.1
|
||||||
prisma: 3.15.2
|
prisma: 3.15.2
|
||||||
@ -107,28 +107,18 @@ importers:
|
|||||||
tsconfig-paths: 4.0.0
|
tsconfig-paths: 4.0.0
|
||||||
typescript: 4.7.4
|
typescript: 4.7.4
|
||||||
|
|
||||||
apps/shared:
|
|
||||||
specifiers:
|
|
||||||
esbuild: 0.14.49
|
|
||||||
nodemon: 2.0.19
|
|
||||||
rimraf: 3.0.2
|
|
||||||
devDependencies:
|
|
||||||
esbuild: 0.14.49
|
|
||||||
nodemon: 2.0.19
|
|
||||||
rimraf: 3.0.2
|
|
||||||
|
|
||||||
apps/ui:
|
apps/ui:
|
||||||
specifiers:
|
specifiers:
|
||||||
'@playwright/test': 1.23.3
|
'@playwright/test': 1.23.4
|
||||||
'@sveltejs/adapter-static': 1.0.0-next.36
|
'@sveltejs/adapter-static': 1.0.0-next.37
|
||||||
'@sveltejs/kit': 1.0.0-next.375
|
'@sveltejs/kit': 1.0.0-next.377
|
||||||
'@types/js-cookie': 3.0.2
|
'@types/js-cookie': 3.0.2
|
||||||
'@typescript-eslint/eslint-plugin': 5.30.6
|
'@typescript-eslint/eslint-plugin': 5.30.6
|
||||||
'@typescript-eslint/parser': 5.30.6
|
'@typescript-eslint/parser': 5.30.6
|
||||||
'@zerodevx/svelte-toast': 0.7.2
|
'@zerodevx/svelte-toast': 0.7.2
|
||||||
autoprefixer: 10.4.7
|
autoprefixer: 10.4.7
|
||||||
cuid: 2.1.8
|
cuid: 2.1.8
|
||||||
eslint: 8.19.0
|
eslint: 8.20.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
|
||||||
js-cookie: 3.0.1
|
js-cookie: 3.0.1
|
||||||
@ -136,7 +126,6 @@ importers:
|
|||||||
postcss: 8.4.14
|
postcss: 8.4.14
|
||||||
prettier: 2.7.1
|
prettier: 2.7.1
|
||||||
prettier-plugin-svelte: 2.7.0
|
prettier-plugin-svelte: 2.7.0
|
||||||
shared: workspace:*
|
|
||||||
svelte: 3.49.0
|
svelte: 3.49.0
|
||||||
svelte-check: 2.8.0
|
svelte-check: 2.8.0
|
||||||
svelte-preprocess: 4.10.7
|
svelte-preprocess: 4.10.7
|
||||||
@ -146,26 +135,25 @@ importers:
|
|||||||
tailwindcss-scrollbar: 0.1.0
|
tailwindcss-scrollbar: 0.1.0
|
||||||
tslib: 2.4.0
|
tslib: 2.4.0
|
||||||
typescript: 4.7.4
|
typescript: 4.7.4
|
||||||
vite: ^3.0.0
|
vite: 3.0.1
|
||||||
dependencies:
|
dependencies:
|
||||||
'@sveltejs/adapter-static': 1.0.0-next.36
|
'@sveltejs/adapter-static': 1.0.0-next.37
|
||||||
'@zerodevx/svelte-toast': 0.7.2
|
'@zerodevx/svelte-toast': 0.7.2
|
||||||
cuid: 2.1.8
|
cuid: 2.1.8
|
||||||
js-cookie: 3.0.1
|
js-cookie: 3.0.1
|
||||||
p-limit: 4.0.0
|
p-limit: 4.0.0
|
||||||
shared: link:../shared
|
|
||||||
svelte-select: 4.4.7
|
svelte-select: 4.4.7
|
||||||
sveltekit-i18n: 2.2.2_svelte@3.49.0
|
sveltekit-i18n: 2.2.2_svelte@3.49.0
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@playwright/test': 1.23.3
|
'@playwright/test': 1.23.4
|
||||||
'@sveltejs/kit': 1.0.0-next.375_svelte@3.49.0+vite@3.0.0
|
'@sveltejs/kit': 1.0.0-next.377_svelte@3.49.0+vite@3.0.1
|
||||||
'@types/js-cookie': 3.0.2
|
'@types/js-cookie': 3.0.2
|
||||||
'@typescript-eslint/eslint-plugin': 5.30.6_2vt5mtrqleafs33qg2bhpmbaqm
|
'@typescript-eslint/eslint-plugin': 5.30.6_b7n364ggt6o4xlkgyoaww3ph3q
|
||||||
'@typescript-eslint/parser': 5.30.6_4x5o4skxv6sl53vpwefgt23khm
|
'@typescript-eslint/parser': 5.30.6_he2ccbldppg44uulnyq4rwocfa
|
||||||
autoprefixer: 10.4.7_postcss@8.4.14
|
autoprefixer: 10.4.7_postcss@8.4.14
|
||||||
eslint: 8.19.0
|
eslint: 8.20.0
|
||||||
eslint-config-prettier: 8.5.0_eslint@8.19.0
|
eslint-config-prettier: 8.5.0_eslint@8.20.0
|
||||||
eslint-plugin-svelte3: 4.0.0_jxmmfmurkts274jdspwh3cyqve
|
eslint-plugin-svelte3: 4.0.0_piwa6j2njmnknm35bh3wz5v52y
|
||||||
postcss: 8.4.14
|
postcss: 8.4.14
|
||||||
prettier: 2.7.1
|
prettier: 2.7.1
|
||||||
prettier-plugin-svelte: 2.7.0_o3ioganyptcsrh6x4hnxvjkpqi
|
prettier-plugin-svelte: 2.7.0_o3ioganyptcsrh6x4hnxvjkpqi
|
||||||
@ -176,7 +164,7 @@ importers:
|
|||||||
tailwindcss-scrollbar: 0.1.0_tailwindcss@3.1.6
|
tailwindcss-scrollbar: 0.1.0_tailwindcss@3.1.6
|
||||||
tslib: 2.4.0
|
tslib: 2.4.0
|
||||||
typescript: 4.7.4
|
typescript: 4.7.4
|
||||||
vite: 3.0.0
|
vite: 3.0.1
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
@ -213,14 +201,14 @@ packages:
|
|||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@breejs/ts-worker/2.0.0_t3dw2jfpvj5qtbx4qztd4nt754:
|
/@breejs/ts-worker/2.0.0_25g7irgsr6ywin2g3nrhhgteo4:
|
||||||
resolution: {integrity: sha512-6anHRcmgYlF7mrm/YVRn6rx2cegLuiY3VBxkkimOTWC/dVQeH336imVSuIKEGKTwiuNTPr2hswVdDSneNuXg3A==}
|
resolution: {integrity: sha512-6anHRcmgYlF7mrm/YVRn6rx2cegLuiY3VBxkkimOTWC/dVQeH336imVSuIKEGKTwiuNTPr2hswVdDSneNuXg3A==}
|
||||||
engines: {node: '>= 12.11'}
|
engines: {node: '>= 12.11'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
bree: '>=9.0.0'
|
bree: '>=9.0.0'
|
||||||
dependencies:
|
dependencies:
|
||||||
bree: 9.1.1
|
bree: 9.1.1
|
||||||
ts-node: 10.8.2_2zqz24ol5yhbv2blv4fh7akzrq
|
ts-node: 10.8.2_tdn3ypgnfy6bmey2q4hu5jonwi
|
||||||
tsconfig-paths: 4.0.0
|
tsconfig-paths: 4.0.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@swc/core'
|
- '@swc/core'
|
||||||
@ -267,8 +255,8 @@ packages:
|
|||||||
pkg-up: 3.1.0
|
pkg-up: 3.1.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@fastify/cookie/7.1.0:
|
/@fastify/cookie/7.2.0:
|
||||||
resolution: {integrity: sha512-ofAlIthvJ2aWOrzdbUen1Lx09AKk2zvdaUrWh2+0aNt+gajRA7KyR8bzwCD2AwS+2nacjEuSRIyckotMHG95hQ==}
|
resolution: {integrity: sha512-eM/OoTPEW/83uTEWVVZhVVQCtwRx3vmMs7J68U1DFNf42Ar4nTTZ7qGNYXvJPLUQqGKYS/gxML2soNMmZD8z0Q==}
|
||||||
dependencies:
|
dependencies:
|
||||||
cookie: 0.5.0
|
cookie: 0.5.0
|
||||||
cookie-signature: 1.2.0
|
cookie-signature: 1.2.0
|
||||||
@ -385,13 +373,13 @@ packages:
|
|||||||
fastq: 1.13.0
|
fastq: 1.13.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@playwright/test/1.23.3:
|
/@playwright/test/1.23.4:
|
||||||
resolution: {integrity: sha512-kR4vo2UGHC84DGqE6EwvAeaehj3xCAK6LoC1P1eu6ZGdC79rlqRKf8cFDx6q6c9T8MQSL1O9eOlup0BpwqNF0w==}
|
resolution: {integrity: sha512-iIsoMJDS/lyuhw82FtcV/B3PXikgVD3hNe5hyvOpRM0uRr1OIpN3LgPeRbBjhzBWmyf6RgRg5fqK5sVcpA03yA==}
|
||||||
engines: {node: '>=14'}
|
engines: {node: '>=14'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 18.0.3
|
'@types/node': 18.0.4
|
||||||
playwright-core: 1.23.3
|
playwright-core: 1.23.4
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@prisma/client/3.15.2_prisma@3.15.2:
|
/@prisma/client/3.15.2_prisma@3.15.2:
|
||||||
@ -429,31 +417,31 @@ packages:
|
|||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@sveltejs/adapter-static/1.0.0-next.36:
|
/@sveltejs/adapter-static/1.0.0-next.37:
|
||||||
resolution: {integrity: sha512-1g3W4wHPyBtUGy5zCDBA2nMG3mM36FKTP1zb0vNRBpoUmtNuzVFF74UVsHCpMC1GpPyrgOq9idfjkm4gRabisw==}
|
resolution: {integrity: sha512-BDFkx4CGAd6pG4e3+zYjy/eM9UDbhkRgXqavUzCO5oT8xXao5TeprY1AIbdzjMTmFjsWdeSXE9TbIsT0iikpyQ==}
|
||||||
dependencies:
|
dependencies:
|
||||||
tiny-glob: 0.2.9
|
tiny-glob: 0.2.9
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@sveltejs/kit/1.0.0-next.375_svelte@3.49.0+vite@3.0.0:
|
/@sveltejs/kit/1.0.0-next.377_svelte@3.49.0+vite@3.0.1:
|
||||||
resolution: {integrity: sha512-9+gKm97TW/xIz6DfWOqdsIwGY4yckUkmMFlsJmEGkjcTy60Q6ZCfrQhMULzL/fILLydF0wZcD/fWE/urAbp2nw==}
|
resolution: {integrity: sha512-DH2v2yUBUuDZ7vzjPXUd/yt1AMR3BIkZN0ubLAvS2C+q5Wbvk7ZvAJhfPZ3OYc3ZpQXe4ZGEcptOjvEYvd1lLA==}
|
||||||
engines: {node: '>=16.9'}
|
engines: {node: '>=16.9'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
svelte: ^3.44.0
|
svelte: ^3.44.0
|
||||||
vite: ^3.0.0
|
vite: ^3.0.0
|
||||||
dependencies:
|
dependencies:
|
||||||
'@sveltejs/vite-plugin-svelte': 1.0.1_svelte@3.49.0+vite@3.0.0
|
'@sveltejs/vite-plugin-svelte': 1.0.1_svelte@3.49.0+vite@3.0.1
|
||||||
chokidar: 3.5.3
|
chokidar: 3.5.3
|
||||||
sade: 1.8.1
|
sade: 1.8.1
|
||||||
svelte: 3.49.0
|
svelte: 3.49.0
|
||||||
vite: 3.0.0
|
vite: 3.0.1
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- diff-match-patch
|
- diff-match-patch
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@sveltejs/vite-plugin-svelte/1.0.1_svelte@3.49.0+vite@3.0.0:
|
/@sveltejs/vite-plugin-svelte/1.0.1_svelte@3.49.0+vite@3.0.1:
|
||||||
resolution: {integrity: sha512-PorCgUounn0VXcpeJu+hOweZODKmGuLHsLomwqSj+p26IwjjGffmYQfVHtiTWq+NqaUuuHWWG7vPge6UFw4Aeg==}
|
resolution: {integrity: sha512-PorCgUounn0VXcpeJu+hOweZODKmGuLHsLomwqSj+p26IwjjGffmYQfVHtiTWq+NqaUuuHWWG7vPge6UFw4Aeg==}
|
||||||
engines: {node: ^14.18.0 || >= 16}
|
engines: {node: ^14.18.0 || >= 16}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@ -471,7 +459,7 @@ packages:
|
|||||||
magic-string: 0.26.2
|
magic-string: 0.26.2
|
||||||
svelte: 3.49.0
|
svelte: 3.49.0
|
||||||
svelte-hmr: 0.14.12_svelte@3.49.0
|
svelte-hmr: 0.14.12_svelte@3.49.0
|
||||||
vite: 3.0.0
|
vite: 3.0.1
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
@ -518,7 +506,7 @@ packages:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@types/http-cache-semantics': 4.0.1
|
'@types/http-cache-semantics': 4.0.1
|
||||||
'@types/keyv': 3.1.4
|
'@types/keyv': 3.1.4
|
||||||
'@types/node': 18.0.4
|
'@types/node': 18.0.6
|
||||||
'@types/responselike': 1.0.0
|
'@types/responselike': 1.0.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
@ -541,7 +529,7 @@ packages:
|
|||||||
/@types/keyv/3.1.4:
|
/@types/keyv/3.1.4:
|
||||||
resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==}
|
resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 18.0.4
|
'@types/node': 18.0.6
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@types/lodash/4.14.182:
|
/@types/lodash/4.14.182:
|
||||||
@ -552,12 +540,12 @@ packages:
|
|||||||
resolution: {integrity: sha512-XwVteWQx/XkfRPyaGkw8dEbrCAkoRZ73pI3XznUYIpzbCfpQB3UnDlR5TnmdhetlT889tUJGF8QWo9xrgTpsiA==}
|
resolution: {integrity: sha512-XwVteWQx/XkfRPyaGkw8dEbrCAkoRZ73pI3XznUYIpzbCfpQB3UnDlR5TnmdhetlT889tUJGF8QWo9xrgTpsiA==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@types/node/18.0.3:
|
|
||||||
resolution: {integrity: sha512-HzNRZtp4eepNitP+BD6k2L6DROIDG4Q0fm4x+dwfsr6LGmROENnok75VGw40628xf+iR24WeMFcHuuBDUAzzsQ==}
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/@types/node/18.0.4:
|
/@types/node/18.0.4:
|
||||||
resolution: {integrity: sha512-M0+G6V0Y4YV8cqzHssZpaNCqvYwlCiulmm0PwpNLF55r/+cT8Ol42CHRU1SEaYFH2rTwiiE1aYg/2g2rrtGdPA==}
|
resolution: {integrity: sha512-M0+G6V0Y4YV8cqzHssZpaNCqvYwlCiulmm0PwpNLF55r/+cT8Ol42CHRU1SEaYFH2rTwiiE1aYg/2g2rrtGdPA==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/@types/node/18.0.6:
|
||||||
|
resolution: {integrity: sha512-/xUq6H2aQm261exT6iZTMifUySEt4GR5KX8eYyY+C4MSNPqSh9oNIP7tz2GLKTlFaiBbgZNxffoR3CVRG+cljw==}
|
||||||
|
|
||||||
/@types/normalize-package-data/2.4.1:
|
/@types/normalize-package-data/2.4.1:
|
||||||
resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==}
|
resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==}
|
||||||
@ -570,16 +558,16 @@ packages:
|
|||||||
/@types/responselike/1.0.0:
|
/@types/responselike/1.0.0:
|
||||||
resolution: {integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==}
|
resolution: {integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 18.0.4
|
'@types/node': 18.0.6
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@types/sass/1.43.1:
|
/@types/sass/1.43.1:
|
||||||
resolution: {integrity: sha512-BPdoIt1lfJ6B7rw35ncdwBZrAssjcwzI5LByIrYs+tpXlj/CAkuVdRsgZDdP4lq5EjyWzwxZCqAoFyHKFwp32g==}
|
resolution: {integrity: sha512-BPdoIt1lfJ6B7rw35ncdwBZrAssjcwzI5LByIrYs+tpXlj/CAkuVdRsgZDdP4lq5EjyWzwxZCqAoFyHKFwp32g==}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 18.0.3
|
'@types/node': 18.0.4
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@typescript-eslint/eslint-plugin/5.30.6_2vt5mtrqleafs33qg2bhpmbaqm:
|
/@typescript-eslint/eslint-plugin/5.30.6_b7n364ggt6o4xlkgyoaww3ph3q:
|
||||||
resolution: {integrity: sha512-J4zYMIhgrx4MgnZrSDD7sEnQp7FmhKNOaqaOpaoQ/SfdMfRB/0yvK74hTnvH+VQxndZynqs5/Hn4t+2/j9bADg==}
|
resolution: {integrity: sha512-J4zYMIhgrx4MgnZrSDD7sEnQp7FmhKNOaqaOpaoQ/SfdMfRB/0yvK74hTnvH+VQxndZynqs5/Hn4t+2/j9bADg==}
|
||||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@ -590,12 +578,12 @@ packages:
|
|||||||
typescript:
|
typescript:
|
||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/parser': 5.30.6_4x5o4skxv6sl53vpwefgt23khm
|
'@typescript-eslint/parser': 5.30.6_he2ccbldppg44uulnyq4rwocfa
|
||||||
'@typescript-eslint/scope-manager': 5.30.6
|
'@typescript-eslint/scope-manager': 5.30.6
|
||||||
'@typescript-eslint/type-utils': 5.30.6_4x5o4skxv6sl53vpwefgt23khm
|
'@typescript-eslint/type-utils': 5.30.6_he2ccbldppg44uulnyq4rwocfa
|
||||||
'@typescript-eslint/utils': 5.30.6_4x5o4skxv6sl53vpwefgt23khm
|
'@typescript-eslint/utils': 5.30.6_he2ccbldppg44uulnyq4rwocfa
|
||||||
debug: 4.3.4
|
debug: 4.3.4
|
||||||
eslint: 8.19.0
|
eslint: 8.20.0
|
||||||
functional-red-black-tree: 1.0.1
|
functional-red-black-tree: 1.0.1
|
||||||
ignore: 5.2.0
|
ignore: 5.2.0
|
||||||
regexpp: 3.2.0
|
regexpp: 3.2.0
|
||||||
@ -606,7 +594,7 @@ packages:
|
|||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@typescript-eslint/parser/5.30.6_4x5o4skxv6sl53vpwefgt23khm:
|
/@typescript-eslint/parser/5.30.6_he2ccbldppg44uulnyq4rwocfa:
|
||||||
resolution: {integrity: sha512-gfF9lZjT0p2ZSdxO70Xbw8w9sPPJGfAdjK7WikEjB3fcUI/yr9maUVEdqigBjKincUYNKOmf7QBMiTf719kbrA==}
|
resolution: {integrity: sha512-gfF9lZjT0p2ZSdxO70Xbw8w9sPPJGfAdjK7WikEjB3fcUI/yr9maUVEdqigBjKincUYNKOmf7QBMiTf719kbrA==}
|
||||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@ -620,7 +608,7 @@ packages:
|
|||||||
'@typescript-eslint/types': 5.30.6
|
'@typescript-eslint/types': 5.30.6
|
||||||
'@typescript-eslint/typescript-estree': 5.30.6_typescript@4.7.4
|
'@typescript-eslint/typescript-estree': 5.30.6_typescript@4.7.4
|
||||||
debug: 4.3.4
|
debug: 4.3.4
|
||||||
eslint: 8.19.0
|
eslint: 8.20.0
|
||||||
typescript: 4.7.4
|
typescript: 4.7.4
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
@ -634,7 +622,7 @@ packages:
|
|||||||
'@typescript-eslint/visitor-keys': 5.30.6
|
'@typescript-eslint/visitor-keys': 5.30.6
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@typescript-eslint/type-utils/5.30.6_4x5o4skxv6sl53vpwefgt23khm:
|
/@typescript-eslint/type-utils/5.30.6_he2ccbldppg44uulnyq4rwocfa:
|
||||||
resolution: {integrity: sha512-GFVVzs2j0QPpM+NTDMXtNmJKlF842lkZKDSanIxf+ArJsGeZUIaeT4jGg+gAgHt7AcQSFwW7htzF/rbAh2jaVA==}
|
resolution: {integrity: sha512-GFVVzs2j0QPpM+NTDMXtNmJKlF842lkZKDSanIxf+ArJsGeZUIaeT4jGg+gAgHt7AcQSFwW7htzF/rbAh2jaVA==}
|
||||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@ -644,9 +632,9 @@ packages:
|
|||||||
typescript:
|
typescript:
|
||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/utils': 5.30.6_4x5o4skxv6sl53vpwefgt23khm
|
'@typescript-eslint/utils': 5.30.6_he2ccbldppg44uulnyq4rwocfa
|
||||||
debug: 4.3.4
|
debug: 4.3.4
|
||||||
eslint: 8.19.0
|
eslint: 8.20.0
|
||||||
tsutils: 3.21.0_typescript@4.7.4
|
tsutils: 3.21.0_typescript@4.7.4
|
||||||
typescript: 4.7.4
|
typescript: 4.7.4
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
@ -679,7 +667,7 @@ packages:
|
|||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@typescript-eslint/utils/5.30.6_4x5o4skxv6sl53vpwefgt23khm:
|
/@typescript-eslint/utils/5.30.6_he2ccbldppg44uulnyq4rwocfa:
|
||||||
resolution: {integrity: sha512-xFBLc/esUbLOJLk9jKv0E9gD/OH966M40aY9jJ8GiqpSkP2xOV908cokJqqhVd85WoIvHVHYXxSFE4cCSDzVvA==}
|
resolution: {integrity: sha512-xFBLc/esUbLOJLk9jKv0E9gD/OH966M40aY9jJ8GiqpSkP2xOV908cokJqqhVd85WoIvHVHYXxSFE4cCSDzVvA==}
|
||||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@ -689,9 +677,9 @@ packages:
|
|||||||
'@typescript-eslint/scope-manager': 5.30.6
|
'@typescript-eslint/scope-manager': 5.30.6
|
||||||
'@typescript-eslint/types': 5.30.6
|
'@typescript-eslint/types': 5.30.6
|
||||||
'@typescript-eslint/typescript-estree': 5.30.6_typescript@4.7.4
|
'@typescript-eslint/typescript-estree': 5.30.6_typescript@4.7.4
|
||||||
eslint: 8.19.0
|
eslint: 8.20.0
|
||||||
eslint-scope: 5.1.1
|
eslint-scope: 5.1.1
|
||||||
eslint-utils: 3.0.0_eslint@8.19.0
|
eslint-utils: 3.0.0_eslint@8.20.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
- typescript
|
- typescript
|
||||||
@ -2531,16 +2519,16 @@ packages:
|
|||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/eslint-config-prettier/8.5.0_eslint@8.19.0:
|
/eslint-config-prettier/8.5.0_eslint@8.20.0:
|
||||||
resolution: {integrity: sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==}
|
resolution: {integrity: sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
eslint: '>=7.0.0'
|
eslint: '>=7.0.0'
|
||||||
dependencies:
|
dependencies:
|
||||||
eslint: 8.19.0
|
eslint: 8.20.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/eslint-plugin-prettier/4.2.1_7uxdfn2xinezdgvmbammh6ev5i:
|
/eslint-plugin-prettier/4.2.1_g4fztgbwjyq2fvmcscny2sj6fy:
|
||||||
resolution: {integrity: sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==}
|
resolution: {integrity: sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==}
|
||||||
engines: {node: '>=12.0.0'}
|
engines: {node: '>=12.0.0'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@ -2551,19 +2539,19 @@ packages:
|
|||||||
eslint-config-prettier:
|
eslint-config-prettier:
|
||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
eslint: 8.19.0
|
eslint: 8.20.0
|
||||||
eslint-config-prettier: 8.5.0_eslint@8.19.0
|
eslint-config-prettier: 8.5.0_eslint@8.20.0
|
||||||
prettier: 2.7.1
|
prettier: 2.7.1
|
||||||
prettier-linter-helpers: 1.0.0
|
prettier-linter-helpers: 1.0.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/eslint-plugin-svelte3/4.0.0_jxmmfmurkts274jdspwh3cyqve:
|
/eslint-plugin-svelte3/4.0.0_piwa6j2njmnknm35bh3wz5v52y:
|
||||||
resolution: {integrity: sha512-OIx9lgaNzD02+MDFNLw0GEUbuovNcglg+wnd/UY0fbZmlQSz7GlQiQ1f+yX0XvC07XPcDOnFcichqI3xCwp71g==}
|
resolution: {integrity: sha512-OIx9lgaNzD02+MDFNLw0GEUbuovNcglg+wnd/UY0fbZmlQSz7GlQiQ1f+yX0XvC07XPcDOnFcichqI3xCwp71g==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
eslint: '>=8.0.0'
|
eslint: '>=8.0.0'
|
||||||
svelte: ^3.2.0
|
svelte: ^3.2.0
|
||||||
dependencies:
|
dependencies:
|
||||||
eslint: 8.19.0
|
eslint: 8.20.0
|
||||||
svelte: 3.49.0
|
svelte: 3.49.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
@ -2583,13 +2571,13 @@ packages:
|
|||||||
estraverse: 5.3.0
|
estraverse: 5.3.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/eslint-utils/3.0.0_eslint@8.19.0:
|
/eslint-utils/3.0.0_eslint@8.20.0:
|
||||||
resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==}
|
resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==}
|
||||||
engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0}
|
engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
eslint: '>=5'
|
eslint: '>=5'
|
||||||
dependencies:
|
dependencies:
|
||||||
eslint: 8.19.0
|
eslint: 8.20.0
|
||||||
eslint-visitor-keys: 2.1.0
|
eslint-visitor-keys: 2.1.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
@ -2603,8 +2591,8 @@ packages:
|
|||||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/eslint/8.19.0:
|
/eslint/8.20.0:
|
||||||
resolution: {integrity: sha512-SXOPj3x9VKvPe81TjjUJCYlV4oJjQw68Uek+AM0X4p+33dj2HY5bpTZOgnQHcG2eAm1mtCU9uNMnJi7exU/kYw==}
|
resolution: {integrity: sha512-d4ixhz5SKCa1D6SCPrivP7yYVi7nyD6A4vs6HIAul9ujBzcEmZVM3/0NN/yu5nKhmO1wjp5xQ46iRfmDGlOviA==}
|
||||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -2617,7 +2605,7 @@ packages:
|
|||||||
doctrine: 3.0.0
|
doctrine: 3.0.0
|
||||||
escape-string-regexp: 4.0.0
|
escape-string-regexp: 4.0.0
|
||||||
eslint-scope: 7.1.1
|
eslint-scope: 7.1.1
|
||||||
eslint-utils: 3.0.0_eslint@8.19.0
|
eslint-utils: 3.0.0_eslint@8.20.0
|
||||||
eslint-visitor-keys: 3.3.0
|
eslint-visitor-keys: 3.3.0
|
||||||
espree: 9.3.2
|
espree: 9.3.2
|
||||||
esquery: 1.4.0
|
esquery: 1.4.0
|
||||||
@ -4259,8 +4247,8 @@ packages:
|
|||||||
find-up: 3.0.0
|
find-up: 3.0.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/playwright-core/1.23.3:
|
/playwright-core/1.23.4:
|
||||||
resolution: {integrity: sha512-x35yzsXDyo0BIXYimLnUFNyb42c//NadUNH6IPGOteZm96oTGA1kn4Hq6qJTI1/f9wEc1F9O1DsznXIgXMil7A==}
|
resolution: {integrity: sha512-h5V2yw7d8xIwotjyNrkLF13nV9RiiZLHdXeHo+nVJIYGVlZ8U2qV0pMxNJKNTvfQVT0N8/A4CW6/4EW2cOcTiA==}
|
||||||
engines: {node: '>=14'}
|
engines: {node: '>=14'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
dev: true
|
dev: true
|
||||||
@ -4860,6 +4848,10 @@ packages:
|
|||||||
engines: {node: '>= 10.x'}
|
engines: {node: '>= 10.x'}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/ssh-config/4.1.6:
|
||||||
|
resolution: {integrity: sha512-YdPYn/2afoBonSFoMSvC1FraA/LKKrvy8UvbvAFGJ8gdlKuANvufLLkf8ynF2uq7Tl5+DQBIFyN37//09nAgNQ==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/ssh2/1.10.0:
|
/ssh2/1.10.0:
|
||||||
resolution: {integrity: sha512-OnKAAmf4j8wCRrXXZv3Tp5lCZkLJZtgZbn45ELiShCg27djDQ3XFGvIzuGsIsf4hdHslP+VdhA9BhUQdTdfd9w==}
|
resolution: {integrity: sha512-OnKAAmf4j8wCRrXXZv3Tp5lCZkLJZtgZbn45ELiShCg27djDQ3XFGvIzuGsIsf4hdHslP+VdhA9BhUQdTdfd9w==}
|
||||||
engines: {node: '>=10.16.0'}
|
engines: {node: '>=10.16.0'}
|
||||||
@ -5217,7 +5209,7 @@ packages:
|
|||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/ts-node/10.8.2_2zqz24ol5yhbv2blv4fh7akzrq:
|
/ts-node/10.8.2_tdn3ypgnfy6bmey2q4hu5jonwi:
|
||||||
resolution: {integrity: sha512-LYdGnoGddf1D6v8REPtIH+5iq/gTDuZqv2/UJUU7tKjuEU8xVZorBM+buCGNjj+pGEud+sOoM4CX3/YzINpENA==}
|
resolution: {integrity: sha512-LYdGnoGddf1D6v8REPtIH+5iq/gTDuZqv2/UJUU7tKjuEU8xVZorBM+buCGNjj+pGEud+sOoM4CX3/YzINpENA==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@ -5236,7 +5228,7 @@ packages:
|
|||||||
'@tsconfig/node12': 1.0.9
|
'@tsconfig/node12': 1.0.9
|
||||||
'@tsconfig/node14': 1.0.1
|
'@tsconfig/node14': 1.0.1
|
||||||
'@tsconfig/node16': 1.0.2
|
'@tsconfig/node16': 1.0.2
|
||||||
'@types/node': 18.0.4
|
'@types/node': 18.0.6
|
||||||
acorn: 8.7.1
|
acorn: 8.7.1
|
||||||
acorn-walk: 8.2.0
|
acorn-walk: 8.2.0
|
||||||
arg: 4.1.3
|
arg: 4.1.3
|
||||||
@ -5373,9 +5365,9 @@ packages:
|
|||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/vite/3.0.0:
|
/vite/3.0.1:
|
||||||
resolution: {integrity: sha512-M7phQhY3+fRZa0H+1WzI6N+/onruwPTBTMvaj7TzgZ0v2TE+N2sdLKxJOfOv9CckDWt5C4HmyQP81xB4dwRKzA==}
|
resolution: {integrity: sha512-nefKSglkoEsDpYUkBuT2++L04ktcP8fz8dxLtmZdDdMyhubFSOLFw6BTh/46Fc6tIX/cibs/NVYWNrsqn0k6pQ==}
|
||||||
engines: {node: '>=14.18.0'}
|
engines: {node: ^14.18.0 || >=16.0.0}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
less: '*'
|
less: '*'
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user