mirror of
https://github.com/tiennm99/coolify.git
synced 2026-10-13 16:14:42 +00:00
Merge remote-tracking branch 'origin/next' into feat/noindex-domains
This commit is contained in:
commit
8c9a7413d0
91 files changed
+2889
-2201
No files matched your search
@@ -38,6 +38,7 @@ docker/coolify-realtime/node_modules
|
||||
.DS_Store
|
||||
CHANGELOG.md
|
||||
/.workspaces
|
||||
/.superpowers/
|
||||
tests/Browser/Screenshots
|
||||
tests/v4/Browser/Screenshots
|
||||
ref
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Livewire\Dashboard;
|
||||
|
||||
use App\Models\Server;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Livewire\Component;
|
||||
|
||||
class ServerMetricsChart extends Component
|
||||
{
|
||||
public Server $server;
|
||||
|
||||
public function loadData(): void
|
||||
{
|
||||
try {
|
||||
$this->dispatch("dashboard-server-metrics-{$this->server->uuid}", [
|
||||
'cpu' => $this->server->getCpuMetrics(10),
|
||||
'memory' => $this->server->getMemoryMetrics(10),
|
||||
]);
|
||||
} catch (\Throwable $e) {
|
||||
report($e);
|
||||
}
|
||||
}
|
||||
|
||||
public function render(): View
|
||||
{
|
||||
return view('livewire.dashboard.server-metrics-chart');
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ namespace App\Livewire\Storage;
|
||||
|
||||
use App\Models\S3Storage;
|
||||
use App\Models\ScheduledDatabaseBackup;
|
||||
use App\Models\ScheduledVolumeBackup;
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Livewire\Component;
|
||||
|
||||
@@ -15,6 +16,8 @@ class Resources extends Component
|
||||
|
||||
public array $selectedStorages = [];
|
||||
|
||||
public array $selectedVolumeStorages = [];
|
||||
|
||||
public function mount(): void
|
||||
{
|
||||
$this->authorize('view', $this->storage);
|
||||
@@ -26,6 +29,13 @@ class Resources extends Component
|
||||
foreach ($backups as $backup) {
|
||||
$this->selectedStorages[$backup->id] = $this->storage->id;
|
||||
}
|
||||
|
||||
ScheduledVolumeBackup::query()
|
||||
->where('s3_storage_id', $this->storage->id)
|
||||
->where('save_s3', true)
|
||||
->each(function (ScheduledVolumeBackup $backup): void {
|
||||
$this->selectedVolumeStorages[$backup->id] = $this->storage->id;
|
||||
});
|
||||
}
|
||||
|
||||
public function disableS3(int $backupId): void
|
||||
@@ -80,6 +90,61 @@ class Resources extends Component
|
||||
$this->dispatch('success', 'Backup moved.', "Moved to {$newStorage->name}.");
|
||||
}
|
||||
|
||||
public function disableVolumeS3(int $backupId): void
|
||||
{
|
||||
$this->authorize('update', $this->storage);
|
||||
|
||||
$backup = ScheduledVolumeBackup::query()
|
||||
->where('id', $backupId)
|
||||
->where('s3_storage_id', $this->storage->id)
|
||||
->firstOrFail();
|
||||
|
||||
$backup->update([
|
||||
'save_s3' => false,
|
||||
's3_storage_id' => null,
|
||||
]);
|
||||
|
||||
unset($this->selectedVolumeStorages[$backupId]);
|
||||
|
||||
$this->dispatch('success', 'S3 disabled.', 'S3 backup has been disabled for this schedule.');
|
||||
}
|
||||
|
||||
public function moveVolumeBackup(int $backupId): void
|
||||
{
|
||||
$this->authorize('update', $this->storage);
|
||||
|
||||
$backup = ScheduledVolumeBackup::query()
|
||||
->where('id', $backupId)
|
||||
->where('s3_storage_id', $this->storage->id)
|
||||
->firstOrFail();
|
||||
$newStorageId = $this->selectedVolumeStorages[$backupId] ?? null;
|
||||
|
||||
if (! $newStorageId || (int) $newStorageId === $this->storage->id) {
|
||||
$this->dispatch('error', 'No change.', 'The backup is already using this storage.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$newStorage = S3Storage::query()
|
||||
->where('id', $newStorageId)
|
||||
->where('team_id', $this->storage->team_id)
|
||||
->first();
|
||||
|
||||
if (! $newStorage) {
|
||||
$this->dispatch('error', 'Storage not found.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->authorize('update', $newStorage);
|
||||
|
||||
$backup->update(['s3_storage_id' => $newStorage->id]);
|
||||
|
||||
unset($this->selectedVolumeStorages[$backupId]);
|
||||
|
||||
$this->dispatch('success', 'Backup moved.', "Moved to {$newStorage->name}.");
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
$backups = ScheduledDatabaseBackup::where('s3_storage_id', $this->storage->id)
|
||||
@@ -92,8 +157,15 @@ class Resources extends Component
|
||||
->orderBy('name')
|
||||
->get(['id', 'name', 'is_usable']);
|
||||
|
||||
$volumeBackups = ScheduledVolumeBackup::query()
|
||||
->where('s3_storage_id', $this->storage->id)
|
||||
->where('save_s3', true)
|
||||
->with('backupable.resource')
|
||||
->get();
|
||||
|
||||
return view('livewire.storage.resources', [
|
||||
'groupedBackups' => $backups,
|
||||
'volumeBackups' => $volumeBackups,
|
||||
'allStorages' => $allStorages,
|
||||
]);
|
||||
}
|
||||
|
||||
+43
-43
@@ -12,69 +12,69 @@
|
||||
],
|
||||
"require": {
|
||||
"php": "^8.4",
|
||||
"danharrin/livewire-rate-limiting": "^2.1.0",
|
||||
"doctrine/dbal": "^4.4.1",
|
||||
"guzzlehttp/guzzle": "^7.10.0",
|
||||
"inertiajs/inertia-laravel": "^3.1",
|
||||
"laravel/fortify": "^1.34.0",
|
||||
"laravel/framework": "^12.49.0",
|
||||
"laravel/horizon": "^5.43.0",
|
||||
"danharrin/livewire-rate-limiting": "^2.2.1",
|
||||
"doctrine/dbal": "^4.4.4",
|
||||
"guzzlehttp/guzzle": "^7.15.3",
|
||||
"inertiajs/inertia-laravel": "^3.3",
|
||||
"laravel/fortify": "^1.37.3",
|
||||
"laravel/framework": "^12.65.0",
|
||||
"laravel/horizon": "^5.48.2",
|
||||
"laravel/mcp": "^0.6.7",
|
||||
"laravel/nightwatch": "^1.24",
|
||||
"laravel/pail": "^1.2.4",
|
||||
"laravel/prompts": "^0.3.11|^0.3.11|^0.3.11",
|
||||
"laravel/sanctum": "^4.3.0",
|
||||
"laravel/socialite": "^5.24.2",
|
||||
"laravel/tinker": "^2.11.0",
|
||||
"laravel/ui": "^4.6.1",
|
||||
"laravel/nightwatch": "^1.28.6",
|
||||
"laravel/pail": "^1.2.7",
|
||||
"laravel/prompts": "^0.3.22|^0.3.22|^0.3.22",
|
||||
"laravel/sanctum": "^4.3.3",
|
||||
"laravel/socialite": "^5.29.0",
|
||||
"laravel/tinker": "^2.11.1",
|
||||
"laravel/ui": "^4.6.3",
|
||||
"lcobucci/jwt": "^5.6.0",
|
||||
"league/flysystem-aws-s3-v3": "^3.31.0",
|
||||
"league/flysystem-sftp-v3": "^3.31",
|
||||
"livewire/livewire": "^3.7.8",
|
||||
"league/flysystem-aws-s3-v3": "^3.35.2",
|
||||
"league/flysystem-sftp-v3": "^3.33",
|
||||
"livewire/livewire": "^3.8.3",
|
||||
"log1x/laravel-webfonts": "^2.0.1",
|
||||
"lorisleiva/laravel-actions": "^2.9.1",
|
||||
"lorisleiva/laravel-actions": "^2.10.2",
|
||||
"nubs/random-name-generator": "^2.2",
|
||||
"phpseclib/phpseclib": "^3.0.49",
|
||||
"pion/laravel-chunk-upload": "^1.5.6",
|
||||
"poliander/cron": "^3.3.0",
|
||||
"phpseclib/phpseclib": "^3.0.56",
|
||||
"pion/laravel-chunk-upload": "^1.6.1",
|
||||
"poliander/cron": "^3.3.1",
|
||||
"purplepixie/phpdns": "^2.3.6",
|
||||
"pusher/pusher-php-server": "^7.2.7",
|
||||
"pusher/pusher-php-server": "^7.3.0",
|
||||
"resend/resend-laravel": "^0.20.0",
|
||||
"sentry/sentry-laravel": "^4.20.1",
|
||||
"socialiteproviders/authentik": "^5.2",
|
||||
"sentry/sentry-laravel": "^4.27.0",
|
||||
"socialiteproviders/authentik": "^5.3",
|
||||
"socialiteproviders/clerk": "^5.1",
|
||||
"socialiteproviders/discord": "^4.2",
|
||||
"socialiteproviders/google": "^4.1",
|
||||
"socialiteproviders/infomaniak": "^4.0",
|
||||
"socialiteproviders/microsoft-azure": "^5.2",
|
||||
"socialiteproviders/zitadel": "^4.2",
|
||||
"spatie/laravel-activitylog": "^4.11.0",
|
||||
"spatie/laravel-data": "^4.19.1",
|
||||
"spatie/laravel-markdown": "^2.7.1",
|
||||
"spatie/laravel-schemaless-attributes": "^2.5.1",
|
||||
"spatie/laravel-activitylog": "^4.12.3",
|
||||
"spatie/laravel-data": "^4.23.0",
|
||||
"spatie/laravel-markdown": "^2.8.0",
|
||||
"spatie/laravel-schemaless-attributes": "^2.6.0",
|
||||
"spatie/url": "^2.4",
|
||||
"stevebauman/purify": "^6.3.1",
|
||||
"stevebauman/purify": "^6.3.2",
|
||||
"stripe/stripe-php": "^16.6.0",
|
||||
"symfony/yaml": "^7.4.1",
|
||||
"symfony/yaml": "^7.4.15",
|
||||
"visus/cuid2": "^6.0.0",
|
||||
"yosymfony/toml": "^1.0.4",
|
||||
"zircote/swagger-php": "^5.8.0"
|
||||
"zircote/swagger-php": "^5.8.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"driftingly/rector-laravel": "^2.1.9",
|
||||
"driftingly/rector-laravel": "^2.5.0",
|
||||
"fakerphp/faker": "^1.24.1",
|
||||
"laravel/boost": "^2.1",
|
||||
"laravel/dusk": "^8.3.4",
|
||||
"laravel/pint": "^1.27",
|
||||
"laravel/boost": "^2.4.8",
|
||||
"laravel/dusk": "^8.6.0",
|
||||
"laravel/pint": "^1.30.4",
|
||||
"mockery/mockery": "^1.6.12",
|
||||
"nunomaduro/collision": "^8.8.3",
|
||||
"pestphp/pest": "^4.3.2",
|
||||
"pestphp/pest-plugin-browser": "^4.2",
|
||||
"phpstan/phpstan": "^2.1.38",
|
||||
"rector/rector": "^2.3.5",
|
||||
"serversideup/spin": "^3.1.1",
|
||||
"spatie/laravel-ignition": "^2.10.0",
|
||||
"symfony/http-client": "^7.4.5"
|
||||
"nunomaduro/collision": "^8.9.5",
|
||||
"pestphp/pest": "^4.7.8",
|
||||
"pestphp/pest-plugin-browser": "^4.3.1",
|
||||
"phpstan/phpstan": "^2.2.8",
|
||||
"rector/rector": "^2.6.1",
|
||||
"serversideup/spin": "^3.3.0",
|
||||
"spatie/laravel-ignition": "^2.12.0",
|
||||
"symfony/http-client": "^7.4.16"
|
||||
},
|
||||
"minimum-stability": "stable",
|
||||
"prefer-stable": true,
|
||||
|
||||
Generated
+627
-608
File diff suppressed because it is too large.
Load diff
@@ -4,7 +4,7 @@ return [
|
||||
'coolify' => [
|
||||
'version' => '4.3.0',
|
||||
'helper_version' => '1.0.14',
|
||||
'realtime_version' => '1.0.16',
|
||||
'realtime_version' => '1.0.17',
|
||||
'railpack_version' => '0.23.0',
|
||||
'self_hosted' => env('SELF_HOSTED', true),
|
||||
'autoupdate' => env('AUTOUPDATE'),
|
||||
|
||||
@@ -13,7 +13,7 @@ services:
|
||||
- COOLIFY_CLI_VERSION=${COOLIFY_CLI_VERSION:-nightly}
|
||||
- COOLIFY_CLI_CHECKSUM=${COOLIFY_CLI_CHECKSUM:-unknown}
|
||||
ports:
|
||||
- "${APP_PORT:-8000}:8080"
|
||||
- "${DEV_BIND_ADDRESS:-0.0.0.0}:${APP_PORT:-8000}:8080"
|
||||
- "${FORWARD_FLUX_PORT:-6443}:6443"
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
@@ -82,8 +82,8 @@ services:
|
||||
env_file:
|
||||
- .env
|
||||
ports:
|
||||
- "${FORWARD_SOKETI_PORT:-6001}:6001"
|
||||
- "6002:6002"
|
||||
- "${DEV_BIND_ADDRESS:-0.0.0.0}:${FORWARD_SOKETI_PORT:-6001}:6001"
|
||||
- "${DEV_BIND_ADDRESS:-0.0.0.0}:6002:6002"
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
volumes:
|
||||
@@ -111,8 +111,9 @@ services:
|
||||
# Set VITE_HOST in .env to a browser-reachable IP/hostname for LAN/Tailscale access
|
||||
VITE_HOST: "${VITE_HOST:-localhost}"
|
||||
VITE_PORT: "${VITE_PORT:-5173}"
|
||||
VITE_PROTOCOL: "${VITE_PROTOCOL:-http}"
|
||||
ports:
|
||||
- "${VITE_PORT:-5173}:${VITE_PORT:-5173}"
|
||||
- "${DEV_BIND_ADDRESS:-0.0.0.0}:${VITE_PORT:-5173}:${VITE_PORT:-5173}"
|
||||
volumes:
|
||||
- .:/var/www/html/:cached
|
||||
command: sh -c "npm install && npm run dev"
|
||||
|
||||
@@ -60,7 +60,7 @@ services:
|
||||
retries: 10
|
||||
timeout: 2s
|
||||
soketi:
|
||||
image: '${REGISTRY_URL:-docker.io}/coollabsio/coolify-realtime:1.0.16'
|
||||
image: '${REGISTRY_URL:-docker.io}/coollabsio/coolify-realtime:1.0.17'
|
||||
ports:
|
||||
- "${SOKETI_PORT:-6001}:6001"
|
||||
- "6002:6002"
|
||||
|
||||
@@ -96,7 +96,7 @@ services:
|
||||
retries: 10
|
||||
timeout: 2s
|
||||
soketi:
|
||||
image: 'ghcr.io/coollabsio/coolify-realtime:1.0.16'
|
||||
image: 'ghcr.io/coollabsio/coolify-realtime:1.0.17'
|
||||
pull_policy: always
|
||||
container_name: coolify-realtime
|
||||
restart: always
|
||||
|
||||
+13
-13
@@ -7,10 +7,10 @@
|
||||
"dependencies": {
|
||||
"@xterm/addon-fit": "0.11.0",
|
||||
"@xterm/xterm": "6.0.0",
|
||||
"cookie": "1.1.1",
|
||||
"dotenv": "17.3.1",
|
||||
"cookie": "2.0.1",
|
||||
"dotenv": "17.4.2",
|
||||
"node-pty": "1.1.0",
|
||||
"ws": "8.20.1"
|
||||
"ws": "8.21.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@xterm/addon-fit": {
|
||||
@@ -29,12 +29,12 @@
|
||||
]
|
||||
},
|
||||
"node_modules/cookie": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz",
|
||||
"integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==",
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-2.0.1.tgz",
|
||||
"integrity": "sha512-yuToqVvRrj6pfDXREyQAAv8SkAEk/8GS3jQRTiUMm66TVtBYmqQeoEjL2Lmq8Rpo6271vH76InTChTitEAm65w==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
"node": ">=22"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
@@ -42,9 +42,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/dotenv": {
|
||||
"version": "17.3.1",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.3.1.tgz",
|
||||
"integrity": "sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==",
|
||||
"version": "17.4.2",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz",
|
||||
"integrity": "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==",
|
||||
"license": "BSD-2-Clause",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
@@ -70,9 +70,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/ws": {
|
||||
"version": "8.20.1",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.20.1.tgz",
|
||||
"integrity": "sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==",
|
||||
"version": "8.21.3",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.21.3.tgz",
|
||||
"integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
"dependencies": {
|
||||
"@xterm/addon-fit": "0.11.0",
|
||||
"@xterm/xterm": "6.0.0",
|
||||
"cookie": "1.1.1",
|
||||
"dotenv": "17.3.1",
|
||||
"cookie": "2.0.1",
|
||||
"dotenv": "17.4.2",
|
||||
"node-pty": "1.1.0",
|
||||
"ws": "8.20.1"
|
||||
"ws": "8.21.3"
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import { WebSocketServer } from 'ws';
|
||||
import http from 'http';
|
||||
import pty from 'node-pty';
|
||||
import cookie from 'cookie';
|
||||
import { parseCookie } from 'cookie';
|
||||
import 'dotenv/config';
|
||||
import {
|
||||
extractHereDocContent,
|
||||
@@ -96,7 +96,7 @@ const server = http.createServer((req, res) => {
|
||||
});
|
||||
|
||||
const getSessionCookie = (req) => {
|
||||
const cookies = cookie.parse(req.headers.cookie || '');
|
||||
const cookies = parseCookie(req.headers.cookie || '');
|
||||
const xsrfToken = cookies['XSRF-TOKEN'];
|
||||
const appName = process.env.APP_NAME || 'laravel';
|
||||
const sessionCookieName = `${appName.replace(/[^a-zA-Z0-9]/g, '_').toLowerCase()}_session`;
|
||||
|
||||
@@ -60,7 +60,7 @@ services:
|
||||
retries: 10
|
||||
timeout: 2s
|
||||
soketi:
|
||||
image: '${REGISTRY_URL:-docker.io}/coollabsio/coolify-realtime:1.0.16'
|
||||
image: '${REGISTRY_URL:-docker.io}/coollabsio/coolify-realtime:1.0.17'
|
||||
ports:
|
||||
- "${SOKETI_PORT:-6001}:6001"
|
||||
- "6002:6002"
|
||||
|
||||
@@ -96,7 +96,7 @@ services:
|
||||
retries: 10
|
||||
timeout: 2s
|
||||
soketi:
|
||||
image: 'ghcr.io/coollabsio/coolify-realtime:1.0.16'
|
||||
image: 'ghcr.io/coollabsio/coolify-realtime:1.0.17'
|
||||
pull_policy: always
|
||||
container_name: coolify-realtime
|
||||
restart: always
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"version": "1.0.14"
|
||||
},
|
||||
"realtime": {
|
||||
"version": "1.0.16"
|
||||
"version": "1.0.17"
|
||||
},
|
||||
"sentinel": {
|
||||
"version": "0.0.22"
|
||||
|
||||
Generated
+704
-1091
File diff suppressed because it is too large.
Load diff
+14
-11
@@ -11,31 +11,34 @@
|
||||
"clean": "docker compose -f docker-compose.yml -f docker-compose.dev.yml down --remove-orphans"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/postcss": "4.1.18",
|
||||
"@tailwindcss/postcss": "4.3.3",
|
||||
"@testing-library/react": "^16.3.2",
|
||||
"@types/react": "^19.2.17",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"@vitejs/plugin-react": "^5.2.0",
|
||||
"jsdom": "^29.1.1",
|
||||
"laravel-vite-plugin": "3.1.0",
|
||||
"postcss": "8.5.15",
|
||||
"@vitejs/plugin-react": "^6.0.5",
|
||||
"jsdom": "^30.0.1",
|
||||
"laravel-vite-plugin": "3.1.3",
|
||||
"postcss": "8.5.26",
|
||||
"shadcn": "^4.11.0",
|
||||
"tailwind-scrollbar": "4.0.2",
|
||||
"tailwindcss": "4.1.18",
|
||||
"tailwindcss": "4.3.3",
|
||||
"typescript": "^6.0.3",
|
||||
"vite": "8.0.16",
|
||||
"vite": "8.2.1",
|
||||
"vitest": "^4.1.10"
|
||||
},
|
||||
"overrides": {
|
||||
"@babel/plugin-transform-runtime": "^7.29.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@base-ui/react": "^1.5.0",
|
||||
"@fontsource-variable/geist": "^5.2.9",
|
||||
"@inertiajs/react": "^3.3.0",
|
||||
"@inertiajs/vite": "^3.3.0",
|
||||
"@phosphor-icons/react": "^2.1.10",
|
||||
"@tailwindcss/forms": "0.5.10",
|
||||
"@tailwindcss/typography": "0.5.16",
|
||||
"@xterm/addon-fit": "0.10.0",
|
||||
"@xterm/xterm": "5.5.0",
|
||||
"@tailwindcss/forms": "0.5.11",
|
||||
"@tailwindcss/typography": "0.5.20",
|
||||
"@xterm/addon-fit": "0.11.0",
|
||||
"@xterm/xterm": "6.0.0",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"playwright": "^1.58.2",
|
||||
|
||||
+21
-10
@@ -1,6 +1,7 @@
|
||||
@import "./fonts.css" layer(base);
|
||||
|
||||
@import "tailwindcss";
|
||||
@import "tw-animate-css";
|
||||
|
||||
@import "./utilities.css";
|
||||
|
||||
@@ -307,7 +308,7 @@ a {
|
||||
|
||||
button:focus-visible,
|
||||
a:focus-visible {
|
||||
@apply outline-none ring-2 ring-coollabs dark:ring-warning ring-offset-2 dark:ring-offset-coolgray-100;
|
||||
@apply outline-none ring-2 ring-coollabs dark:ring-1 dark:ring-warning ring-offset-2 dark:ring-offset-coolgray-100;
|
||||
}
|
||||
|
||||
label {
|
||||
@@ -366,24 +367,24 @@ tr td:first-child {
|
||||
animation: lds-heart 1.2s infinite cubic-bezier(0.215, 0.61, 0.355, 1);
|
||||
}
|
||||
|
||||
/* Loading feedback uses the yellow brand accent consistently in dark mode. */
|
||||
/* Loading feedback uses the Coolify brand accent consistently in dark mode. */
|
||||
.dark .animate-spin {
|
||||
color: var(--color-warning) !important;
|
||||
color: var(--color-coollabs) !important;
|
||||
}
|
||||
|
||||
.dark #nprogress .bar {
|
||||
background: var(--color-warning) !important;
|
||||
background: var(--color-coollabs) !important;
|
||||
}
|
||||
|
||||
.dark #nprogress .peg {
|
||||
box-shadow:
|
||||
0 0 10px var(--color-warning),
|
||||
0 0 5px var(--color-warning) !important;
|
||||
0 0 10px var(--color-coollabs),
|
||||
0 0 5px var(--color-coollabs) !important;
|
||||
}
|
||||
|
||||
.dark #nprogress .spinner-icon {
|
||||
border-top-color: var(--color-warning) !important;
|
||||
border-left-color: var(--color-warning) !important;
|
||||
border-top-color: var(--color-coollabs) !important;
|
||||
border-left-color: var(--color-coollabs) !important;
|
||||
}
|
||||
|
||||
html[data-theme="custom"] .loading-indicator,
|
||||
@@ -2673,6 +2674,16 @@ input[type="search"]::-webkit-search-results-decoration {
|
||||
|
||||
/* Shared logs viewer (deployment + runtime) — mobile-first toolbar
|
||||
Mobile stacks: search → meta → full-width actions (no side-by-side overlap). */
|
||||
.logs-viewer {
|
||||
background: #fff;
|
||||
color: #262626;
|
||||
}
|
||||
|
||||
.dark .logs-viewer {
|
||||
background: var(--color-log);
|
||||
color: #f5f5f5;
|
||||
}
|
||||
|
||||
.logs-viewer-toolbar {
|
||||
flex-shrink: 0;
|
||||
border-bottom: 1px solid var(--color-neutral-200);
|
||||
@@ -2934,7 +2945,7 @@ html[data-theme="custom"] .logs-viewer-timestamp {
|
||||
|
||||
.logs-viewer-viewport {
|
||||
min-width: 0;
|
||||
padding: 0.5rem 0.75rem;
|
||||
padding: 0.5rem 0.75rem 2rem;
|
||||
}
|
||||
|
||||
.logs-viewer-line {
|
||||
@@ -3024,7 +3035,7 @@ html[data-theme="custom"] .logs-viewer-timestamp {
|
||||
}
|
||||
|
||||
.logs-viewer-viewport {
|
||||
padding: 0.5rem 1rem;
|
||||
padding: 0.5rem 1rem 2rem;
|
||||
}
|
||||
|
||||
.logs-viewer-line {
|
||||
|
||||
@@ -131,15 +131,15 @@
|
||||
}
|
||||
|
||||
@utility button-highlighted {
|
||||
@apply border-2 text-coollabs-200 dark:text-white bg-coollabs-50 dark:bg-coollabs/20 border-coollabs dark:border-coollabs-100 hover:bg-coollabs hover:text-white dark:hover:bg-coollabs-100 dark:hover:text-white;
|
||||
@apply border-coollabs-200 bg-linear-to-b from-coollabs-100 to-coollabs-200 text-white! hover:from-coollabs-100 hover:to-coollabs hover:text-white!;
|
||||
}
|
||||
|
||||
@utility control-selected {
|
||||
@apply bg-coollabs text-white dark:bg-coollabs dark:text-white;
|
||||
@apply bg-linear-to-b from-coollabs-100 to-coollabs-200 text-white;
|
||||
}
|
||||
|
||||
@utility loading-indicator {
|
||||
@apply text-coollabs dark:text-warning;
|
||||
@apply text-coollabs dark:text-coollabs;
|
||||
}
|
||||
|
||||
/* Compact icon-only control (gear, chevrons, etc.) */
|
||||
@@ -273,7 +273,7 @@
|
||||
}
|
||||
|
||||
@utility scrollbar {
|
||||
@apply scrollbar-thumb-coollabs-100 scrollbar-track-neutral-200 dark:scrollbar-thumb-warning dark:scrollbar-track-coolgray-200 scrollbar-thin;
|
||||
@apply scrollbar-thumb-coollabs-100 scrollbar-track-neutral-200 dark:scrollbar-thumb-coollabs-100 dark:scrollbar-track-coolgray-200 scrollbar-thin;
|
||||
}
|
||||
|
||||
@utility main {
|
||||
|
||||
@@ -145,7 +145,7 @@
|
||||
}
|
||||
|
||||
:where(a, button, input, select, textarea, [role="button"], [tabindex]:not([tabindex="-1"])):focus-visible {
|
||||
@apply outline-none ring-2 ring-ring ring-offset-2;
|
||||
@apply outline-none ring-2 dark:ring-1 ring-ring ring-offset-2;
|
||||
}
|
||||
|
||||
html,
|
||||
|
||||
@@ -52,12 +52,12 @@
|
||||
'visible' => ! $application->destination->server->isSwarm() && auth()->user()?->can('canAccessTerminal'),
|
||||
],
|
||||
[
|
||||
'label' => 'Deployment',
|
||||
'label' => 'Deployment Logs',
|
||||
'route' => 'project.application.deployment.index',
|
||||
'active' => str($currentRoute)->startsWith('project.application.deployment'),
|
||||
],
|
||||
[
|
||||
'label' => 'Runtime',
|
||||
'label' => 'Runtime Logs',
|
||||
'route' => 'project.application.logs',
|
||||
'active' => $currentRoute === 'project.application.logs',
|
||||
],
|
||||
@@ -142,8 +142,8 @@
|
||||
'Persistent Storage' => 'storages',
|
||||
'Backups' => 'database',
|
||||
'Terminal' => 'browser-terminal',
|
||||
'Deployment' => 'time-back',
|
||||
'Runtime' => 'unordered-list',
|
||||
'Deployment Logs' => 'time-back',
|
||||
'Runtime Logs' => 'unordered-list',
|
||||
'Git Source' => 'sources',
|
||||
'Servers' => 'servers',
|
||||
'Scheduled Tasks' => 'calendar',
|
||||
@@ -160,14 +160,17 @@
|
||||
|
||||
// Discord-style groups for the settings sidebar
|
||||
$menuGroups = [
|
||||
'Settings' => ['General', 'Domains', 'Advanced', 'Swarm', 'Environment Variables', 'Persistent Storage', 'Backups'],
|
||||
'Build & deploy' => ['Git Source', 'Servers', 'Healthcheck'],
|
||||
'Automation' => ['Scheduled Tasks', 'Webhooks', 'Preview Deployments'],
|
||||
'Logs' => ['Deployment', 'Runtime'],
|
||||
'Operations' => ['Terminal', 'Rollback', 'Resource Limits', 'Resource Operations', 'Metrics', 'Tags', 'Danger Zone'],
|
||||
'Settings' => ['General', 'Domains', 'Environment Variables', 'Persistent Storage', 'Advanced', 'Swarm', 'Healthcheck'],
|
||||
'Observe & troubleshoot' => ['Runtime Logs', 'Deployment Logs', 'Terminal', 'Metrics'],
|
||||
'Deploy' => ['Git Source', 'Servers', 'Preview Deployments'],
|
||||
'Automation' => ['Scheduled Tasks', 'Webhooks', 'Backups'],
|
||||
'Operations' => ['Resource Operations', 'Resource Limits', 'Rollback', 'Tags', 'Danger Zone'],
|
||||
];
|
||||
$groupedMenuItems = collect($menuGroups)
|
||||
->map(fn (array $labels) => collect($configurationMenuItems)->whereIn('label', $labels)->values())
|
||||
->map(fn (array $labels) => collect($labels)
|
||||
->map(fn (string $label) => collect($configurationMenuItems)->firstWhere('label', $label))
|
||||
->filter()
|
||||
->values())
|
||||
->filter(fn ($items) => $items->isNotEmpty());
|
||||
|
||||
// In-page sections (cards) shown as sub-items under the active page
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
['label' => 'Backups', 'route' => 'project.database.backup.index', 'icon' => 'database', 'visible' => $database->isBackupSolutionAvailable()],
|
||||
['label' => 'Import Backup', 'route' => 'project.database.import-backup', 'icon' => 'upload', 'navigate' => false, 'visible' => auth()->user()?->can('update', $database)],
|
||||
['label' => 'Servers', 'route' => 'project.database.servers', 'icon' => 'servers'],
|
||||
['label' => 'Runtime', 'route' => 'project.database.logs', 'icon' => 'unordered-list', 'navigate' => false],
|
||||
['label' => 'Runtime Logs', 'route' => 'project.database.logs', 'icon' => 'unordered-list', 'navigate' => false],
|
||||
['label' => 'Terminal', 'route' => 'project.database.command', 'icon' => 'browser-terminal', 'navigate' => false, 'visible' => auth()->user()?->can('canAccessTerminal')],
|
||||
['label' => 'Webhooks', 'route' => 'project.database.webhooks', 'icon' => 'notifications'],
|
||||
['label' => 'Healthcheck', 'route' => 'project.database.healthcheck', 'icon' => 'feedback'],
|
||||
@@ -32,14 +32,18 @@
|
||||
]);
|
||||
|
||||
$menuGroups = [
|
||||
'Settings' => ['General', 'Environment Variables', 'Persistent Storage', 'Backups', 'Import Backup', 'Servers'],
|
||||
'Automation' => ['Webhooks', 'Healthcheck'],
|
||||
'Logs' => ['Runtime'],
|
||||
'Operations' => ['Terminal', 'Resource Limits', 'Resource Operations', 'Metrics', 'Tags', 'Danger Zone'],
|
||||
'Settings' => ['General', 'Environment Variables', 'Persistent Storage', 'Healthcheck'],
|
||||
'Observe & troubleshoot' => ['Runtime Logs', 'Terminal', 'Metrics'],
|
||||
'Deploy' => ['Servers'],
|
||||
'Automation' => ['Webhooks', 'Backups', 'Import Backup'],
|
||||
'Operations' => ['Resource Operations', 'Resource Limits', 'Tags', 'Danger Zone'],
|
||||
];
|
||||
|
||||
$groupedItems = collect($menuGroups)
|
||||
->map(fn (array $labels) => $configurationItems->whereIn('label', $labels)->values())
|
||||
->map(fn (array $labels) => collect($labels)
|
||||
->map(fn (string $label) => $configurationItems->firstWhere('label', $label))
|
||||
->filter()
|
||||
->values())
|
||||
->filter(fn ($items) => $items->isNotEmpty());
|
||||
|
||||
$pageSections = $database->type() === 'standalone-postgresql'
|
||||
|
||||
@@ -13,10 +13,12 @@
|
||||
'value' => null, // initial value when wire=false
|
||||
'disabled' => false,
|
||||
'tooltip' => true,
|
||||
'portal' => false,
|
||||
])
|
||||
|
||||
@php
|
||||
$triggerId = ($htmlId ?? $id).'-trigger';
|
||||
$panelId = ($htmlId ?? $id).'-panel';
|
||||
@endphp
|
||||
|
||||
<div class="w-full min-w-0">
|
||||
@@ -41,6 +43,7 @@
|
||||
@endif
|
||||
<div class="relative min-w-0" x-data="{
|
||||
open: false,
|
||||
positioned: false,
|
||||
options: @js(array_values($options)),
|
||||
value: @if (!$wire) @js($value) @elseif ($live) @entangle($id).live @else @entangle($id) @endif,
|
||||
get current() {
|
||||
@@ -53,11 +56,42 @@
|
||||
if (String(option.value) === String(this.value)) return;
|
||||
this.value = option.value;
|
||||
@if ($onChange) this.$nextTick(() => this.$wire.{{ $onChange }}()); @endif
|
||||
},
|
||||
toggle() {
|
||||
this.open = !this.open;
|
||||
this.positioned = false;
|
||||
if (this.open && @js($portal)) {
|
||||
this.$nextTick(() => requestAnimationFrame(() => this.positionPanel()));
|
||||
}
|
||||
},
|
||||
positionPanel(panel = null) {
|
||||
const trigger = this.$refs.trigger;
|
||||
panel ??= document.getElementById(@js($panelId));
|
||||
if (!trigger || !panel) return;
|
||||
|
||||
const gap = 4;
|
||||
const edge = 12;
|
||||
const triggerRect = trigger.getBoundingClientRect();
|
||||
const panelWidth = Math.max(triggerRect.width, panel.offsetWidth);
|
||||
const panelHeight = Math.min(panel.scrollHeight, 256);
|
||||
const fitsBelow = window.innerHeight - triggerRect.bottom - gap >= panelHeight;
|
||||
const top = fitsBelow
|
||||
? triggerRect.bottom + gap
|
||||
: Math.max(edge, triggerRect.top - gap - panelHeight);
|
||||
const left = Math.min(
|
||||
Math.max(edge, triggerRect.left),
|
||||
window.innerWidth - panelWidth - edge,
|
||||
);
|
||||
|
||||
panel.style.top = `${top}px`;
|
||||
panel.style.left = `${left}px`;
|
||||
panel.style.minWidth = `${triggerRect.width}px`;
|
||||
this.positioned = true;
|
||||
}
|
||||
}" x-modelable="value" {{ $attributes->whereStartsWith('x-model') }}
|
||||
{{ $attributes->whereStartsWith('x-effect') }}
|
||||
@click.outside="open = false" @keydown.escape="open = false">
|
||||
<button id="{{ $triggerId }}" type="button" class="listbox-trigger" @click="open = !open"
|
||||
@click.outside="open = false" @keydown.escape="open = false" @resize.window="open && positionPanel()">
|
||||
<button x-ref="trigger" id="{{ $triggerId }}" type="button" class="listbox-trigger" @click="toggle()"
|
||||
@disabled($disabled) {{ $attributes->whereStartsWith('x-bind:disabled') }} aria-haspopup="listbox"
|
||||
:aria-expanded="open" @if ($tooltip) :title="current" @endif>
|
||||
<span class="listbox-trigger-label" x-text="current"></span>
|
||||
@@ -66,23 +100,48 @@
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="m8 9 4-4 4 4m0 6-4 4-4-4" />
|
||||
</svg>
|
||||
</button>
|
||||
<div class="listbox-panel" x-show="open" x-cloak role="listbox">
|
||||
<div x-show="options.length === 0"
|
||||
class="px-3 py-2 text-[13px] text-neutral-500 dark:text-fg-dim">
|
||||
{{ $emptyText }}
|
||||
</div>
|
||||
<template x-for="option in options" :key="String(option.value)">
|
||||
<button type="button" class="listbox-option" role="option"
|
||||
:class="{ 'listbox-option-disabled': option.disabled }"
|
||||
:aria-selected="String(option.value) === String(value)" @click="choose(option)">
|
||||
<span class="truncate" x-text="option.label"></span>
|
||||
<svg x-show="String(option.value) === String(value)" xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none" viewBox="0 0 24 24" stroke-width="2.5" stroke="currentColor"
|
||||
class="size-3.5 shrink-0">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="m4.5 12.75 6 6 9-13.5" />
|
||||
</svg>
|
||||
</button>
|
||||
@if ($portal)
|
||||
<template x-teleport="body">
|
||||
<div id="{{ $panelId }}" class="listbox-panel" style="position: fixed; z-index: 9999" x-show="open"
|
||||
x-cloak :style="{ visibility: positioned ? 'visible' : 'hidden' }"
|
||||
x-effect="if (open) requestAnimationFrame(() => positionPanel($el))" role="listbox">
|
||||
<div x-show="options.length === 0"
|
||||
class="px-3 py-2 text-[13px] text-neutral-500 dark:text-fg-dim">
|
||||
{{ $emptyText }}
|
||||
</div>
|
||||
<template x-for="option in options" :key="String(option.value)">
|
||||
<button type="button" class="listbox-option" role="option"
|
||||
:class="{ 'listbox-option-disabled': option.disabled }"
|
||||
:aria-selected="String(option.value) === String(value)" @click="choose(option)">
|
||||
<span class="truncate" x-text="option.label"></span>
|
||||
<svg x-show="String(option.value) === String(value)" xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none" viewBox="0 0 24 24" stroke-width="2.5" stroke="currentColor"
|
||||
class="size-3.5 shrink-0">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="m4.5 12.75 6 6 9-13.5" />
|
||||
</svg>
|
||||
</button>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
@else
|
||||
<div x-ref="panel" class="listbox-panel" x-show="open" x-cloak role="listbox">
|
||||
<div x-show="options.length === 0"
|
||||
class="px-3 py-2 text-[13px] text-neutral-500 dark:text-fg-dim">
|
||||
{{ $emptyText }}
|
||||
</div>
|
||||
<template x-for="option in options" :key="String(option.value)">
|
||||
<button type="button" class="listbox-option" role="option"
|
||||
:class="{ 'listbox-option-disabled': option.disabled }"
|
||||
:aria-selected="String(option.value) === String(value)" @click="choose(option)">
|
||||
<span class="truncate" x-text="option.label"></span>
|
||||
<svg x-show="String(option.value) === String(value)" xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none" viewBox="0 0 24 24" stroke-width="2.5" stroke="currentColor"
|
||||
class="size-3.5 shrink-0">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="m4.5 12.75 6 6 9-13.5" />
|
||||
</svg>
|
||||
</button>
|
||||
</template>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,5 +1,6 @@
|
||||
<div x-data="{
|
||||
visible: false,
|
||||
positioned: false,
|
||||
text: '',
|
||||
x: 0,
|
||||
y: 0,
|
||||
@@ -7,7 +8,10 @@
|
||||
activeTarget: null,
|
||||
isIconAction(target) {
|
||||
if (target.matches('[data-icon-tooltip-ignore]')) return false;
|
||||
return target.matches('[data-tooltip], .icon-button') || target.querySelector('svg');
|
||||
if (target.matches('[data-tooltip], .icon-button')) return true;
|
||||
return target.hasAttribute('aria-label')
|
||||
&& target.childElementCount === 1
|
||||
&& target.firstElementChild?.matches('svg');
|
||||
},
|
||||
prepare(root) {
|
||||
root.querySelectorAll?.('button[title], a[title], [data-tooltip]').forEach((target) => {
|
||||
@@ -25,10 +29,12 @@
|
||||
show(event) {
|
||||
const target = this.findTarget(event);
|
||||
if (!target) return;
|
||||
if (target === this.activeTarget && this.visible) return;
|
||||
const text = target.dataset.tooltip || target.dataset.iconTooltip || target.getAttribute('aria-label');
|
||||
if (!text) return;
|
||||
this.activeTarget = target;
|
||||
this.text = text;
|
||||
this.positioned = false;
|
||||
this.visible = true;
|
||||
const rect = target.getBoundingClientRect();
|
||||
this.below = rect.top < 48;
|
||||
@@ -37,11 +43,13 @@
|
||||
this.$nextTick(() => {
|
||||
const width = this.$refs.tooltip?.offsetWidth || 0;
|
||||
this.x = Math.max(width / 2 + 8, Math.min(window.innerWidth - width / 2 - 8, this.x));
|
||||
this.$nextTick(() => this.positioned = true);
|
||||
});
|
||||
},
|
||||
hide(event) {
|
||||
if (event?.relatedTarget && this.activeTarget?.contains(event.relatedTarget)) return;
|
||||
this.visible = false;
|
||||
this.positioned = false;
|
||||
this.activeTarget = null;
|
||||
},
|
||||
init() {
|
||||
@@ -62,7 +70,7 @@
|
||||
}" class="contents">
|
||||
<div x-ref="tooltip" x-show="visible" x-cloak role="tooltip" x-text="text"
|
||||
:style="`left: ${x}px; top: ${y}px;`"
|
||||
:class="below ? '' : '-translate-y-full'"
|
||||
:class="[below ? '' : '-translate-y-full', positioned ? 'visible' : 'invisible']"
|
||||
class="pointer-events-none fixed z-[100] -translate-x-1/2 whitespace-nowrap rounded-lg border border-neutral-700 bg-neutral-900 px-2 py-1 text-xs font-medium text-white shadow-lg dark:border-white/10 dark:bg-raised">
|
||||
</div>
|
||||
</div>
|
||||
@@ -67,7 +67,7 @@
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<ul role="list" class="flex min-h-0 flex-1 flex-col gap-y-0.5 overflow-y-auto pb-2 scrollbar">
|
||||
<ul role="list" class="-mx-1 flex min-h-0 flex-1 flex-col gap-y-0.5 overflow-y-auto px-1 pb-2 scrollbar">
|
||||
@if (isSubscribed() || !isCloud())
|
||||
{{-- Workspace --}}
|
||||
<li class="nav-section" :class="collapsed && 'lg:hidden'">Workspace</li>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
['label' => 'Environment Variables', 'route' => 'project.service.environment-variables', 'icon' => 'variables', 'hasWarning' => ! $service->isDeployable],
|
||||
['label' => 'Persistent Storage', 'route' => 'project.service.storages', 'icon' => 'storages'],
|
||||
['label' => 'Backups', 'route' => 'project.service.volume-backups.index', 'icon' => 'database'],
|
||||
['label' => 'Runtime', 'route' => 'project.service.logs', 'icon' => 'unordered-list', 'navigate' => false],
|
||||
['label' => 'Runtime Logs', 'route' => 'project.service.logs', 'icon' => 'unordered-list', 'navigate' => false],
|
||||
['label' => 'Terminal', 'route' => 'project.service.command', 'icon' => 'browser-terminal', 'navigate' => false, 'visible' => auth()->user()?->can('canAccessTerminal')],
|
||||
['label' => 'Scheduled Tasks', 'route' => 'project.service.scheduled-tasks.show', 'icon' => 'calendar'],
|
||||
['label' => 'Webhooks', 'route' => 'project.service.webhooks', 'icon' => 'notifications'],
|
||||
@@ -31,14 +31,17 @@
|
||||
]);
|
||||
|
||||
$menuGroups = [
|
||||
'Settings' => ['General', 'Domains', 'Environment Variables', 'Persistent Storage', 'Backups'],
|
||||
'Automation' => ['Scheduled Tasks', 'Webhooks'],
|
||||
'Logs' => ['Runtime'],
|
||||
'Operations' => ['Terminal', 'Resource Operations', 'Tags', 'Danger Zone'],
|
||||
'Settings' => ['General', 'Domains', 'Environment Variables', 'Persistent Storage'],
|
||||
'Observe & troubleshoot' => ['Runtime Logs', 'Terminal'],
|
||||
'Automation' => ['Scheduled Tasks', 'Webhooks', 'Backups'],
|
||||
'Operations' => ['Resource Operations', 'Tags', 'Danger Zone'],
|
||||
];
|
||||
|
||||
$groupedItems = collect($menuGroups)
|
||||
->map(fn (array $labels) => $configurationItems->whereIn('label', $labels)->values())
|
||||
->map(fn (array $labels) => collect($labels)
|
||||
->map(fn (string $label) => $configurationItems->firstWhere('label', $label))
|
||||
->filter()
|
||||
->values())
|
||||
->filter(fn ($items) => $items->isNotEmpty());
|
||||
@endphp
|
||||
|
||||
|
||||
@@ -14,15 +14,15 @@
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="flex h-8 w-fit items-center rounded-lg border border-neutral-200 bg-white p-0.5 dark:border-white/[0.08] dark:bg-white/[0.035]">
|
||||
class="flex h-9 w-fit items-center rounded-lg border border-neutral-200 bg-white p-0.5 dark:border-white/[0.08] dark:bg-white/[0.035]">
|
||||
<button type="button" @click="viewMode = 'list'; localStorage.setItem('{{ $storageKey }}', 'list')"
|
||||
class="flex size-6.5 items-center justify-center rounded-md transition-colors"
|
||||
class="flex size-7.5 items-center justify-center rounded-md transition-colors"
|
||||
:class="viewMode === 'list' ? 'control-selected' : 'text-neutral-400 hover:bg-neutral-100 hover:text-black dark:text-fg-faint dark:hover:bg-white/[0.06] dark:hover:text-fg'"
|
||||
aria-label="List view" title="List view">
|
||||
<x-reicon name="unordered-list" class="size-3.5" />
|
||||
</button>
|
||||
<button type="button" @click="viewMode = 'grid'; localStorage.setItem('{{ $storageKey }}', 'grid')"
|
||||
class="flex size-6.5 items-center justify-center rounded-md transition-colors"
|
||||
class="flex size-7.5 items-center justify-center rounded-md transition-colors"
|
||||
:class="viewMode === 'grid' ? 'control-selected' : 'text-neutral-400 hover:bg-neutral-100 hover:text-black dark:text-fg-faint dark:hover:bg-white/[0.06] dark:hover:text-fg'"
|
||||
aria-label="Grid view" title="Grid view">
|
||||
<x-reicon name="grid" class="size-3.5" />
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
appearanceOpen: false,
|
||||
theme: localStorage.getItem('theme') === 'purple' ? 'custom' : (localStorage.getItem('theme') || 'dark'),
|
||||
themeColor: localStorage.getItem('themeColor') || '#6b16ed',
|
||||
themeColorFrame: null,
|
||||
avatarUrl: @js($user?->avatar_path ? route('profile.avatar', ['v' => $user->updated_at->timestamp]) : null),
|
||||
setTheme(type, closeMenu = true) {
|
||||
this.theme = type;
|
||||
@@ -31,9 +32,29 @@
|
||||
document.documentElement.style.setProperty('--theme-accent-foreground', window.themeAccentForeground(this.themeColor));
|
||||
document.querySelector('meta[name=theme-color]')?.setAttribute('content', isDark ? '#101010' : '#ffffff');
|
||||
},
|
||||
setThemeColor() {
|
||||
localStorage.setItem('themeColor', this.themeColor);
|
||||
this.setTheme('custom', false);
|
||||
previewThemeColor(color) {
|
||||
this.themeColor = color;
|
||||
|
||||
if (this.theme !== 'custom') {
|
||||
this.theme = 'custom';
|
||||
document.documentElement.classList.add('dark');
|
||||
document.documentElement.dataset.theme = 'custom';
|
||||
}
|
||||
|
||||
if (this.themeColorFrame) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.themeColorFrame = requestAnimationFrame(() => {
|
||||
document.documentElement.style.setProperty('--theme-base-color', this.themeColor);
|
||||
document.documentElement.style.setProperty('--theme-accent-foreground', window.themeAccentForeground(this.themeColor));
|
||||
this.themeColorFrame = null;
|
||||
});
|
||||
},
|
||||
saveThemeColor(color) {
|
||||
this.previewThemeColor(color);
|
||||
localStorage.setItem('themeColor', color);
|
||||
localStorage.setItem('theme', 'custom');
|
||||
},
|
||||
}" @avatar-updated.window="avatarUrl = $event.detail.url" @keydown.escape.window="open = false; appearanceOpen = false"
|
||||
@click.outside="open = false; appearanceOpen = false">
|
||||
@@ -62,9 +83,11 @@
|
||||
|
||||
<template x-if="open">
|
||||
<div @class([
|
||||
'listbox-panel z-[90]! max-h-none! w-52! min-w-0! overflow-visible!',
|
||||
'listbox-panel z-[90]! max-h-none! w-52! min-w-0! overflow-visible! animate-in fade-in zoom-in-95 duration-150',
|
||||
'right-0! left-auto!' => ! $sidebar,
|
||||
'bottom-full! left-0! right-auto! top-auto! mb-1!' => $sidebar,
|
||||
'origin-bottom-left' => $sidebar,
|
||||
'origin-top-right' => ! $sidebar,
|
||||
])>
|
||||
<div class="min-w-0 px-2 py-1.5">
|
||||
<div class="truncate text-[13px] font-semibold text-black dark:text-fg">{{ $userName }}</div>
|
||||
@@ -110,7 +133,8 @@
|
||||
<path d="m2.5 6.25 2.1 2.1 4.9-5" stroke="currentColor" stroke-width="1.4"
|
||||
stroke-linecap="round" stroke-linejoin="round" />
|
||||
</svg>
|
||||
<input type="color" x-model="themeColor" @input="setThemeColor()"
|
||||
<input type="color" :value="themeColor" @input="previewThemeColor($event.target.value)"
|
||||
@change="saveThemeColor($event.target.value)"
|
||||
aria-label="Custom theme color"
|
||||
class="absolute inset-0 z-10 h-full w-full cursor-pointer opacity-0" />
|
||||
</div>
|
||||
|
||||
@@ -56,18 +56,18 @@
|
||||
}
|
||||
"
|
||||
@if ($targets) wire:target="{{ $targets }}" @endif
|
||||
class="pointer-events-none fixed inset-x-3 bottom-[calc(var(--keyboard-inset,0px)+max(1.5rem,env(safe-area-inset-bottom,0px)+0.75rem))] z-[1000] flex max-w-full translate-y-6 flex-col items-stretch gap-2 rounded-2xl border border-white/10 bg-surface py-2.5 pr-2.5 pl-4 opacity-0 shadow-modal transition-[opacity,transform] duration-200 ease-out delay-0 [&.is-dirty]:pointer-events-auto [&.is-dirty]:translate-y-0 [&.is-dirty]:opacity-100 [&.is-dirty]:delay-300 sm:inset-x-auto sm:left-1/2 sm:bottom-6 sm:w-max sm:max-w-none sm:-translate-x-1/2 sm:flex-row sm:items-center sm:gap-8 sm:py-2 sm:pl-5 sm:pr-2">
|
||||
<span class="text-[13px] font-semibold leading-snug text-fg sm:whitespace-nowrap">{{ $label }}</span>
|
||||
class="pointer-events-none fixed inset-x-3 bottom-[calc(var(--keyboard-inset,0px)+max(1.5rem,env(safe-area-inset-bottom,0px)+0.75rem))] z-[1000] flex max-w-full translate-y-6 flex-col items-stretch gap-2 rounded-2xl border border-neutral-200 bg-white py-2.5 pr-2.5 pl-4 opacity-0 shadow-modal transition-[opacity,transform] duration-200 ease-out delay-0 dark:border-white/10 dark:bg-surface [&.is-dirty]:pointer-events-auto [&.is-dirty]:translate-y-0 [&.is-dirty]:opacity-100 [&.is-dirty]:delay-300 sm:inset-x-auto sm:left-1/2 sm:bottom-6 sm:w-max sm:max-w-none sm:-translate-x-1/2 sm:flex-row sm:items-center sm:gap-8 sm:py-2 sm:pl-5 sm:pr-2">
|
||||
<span class="text-[13px] font-semibold leading-snug text-neutral-800 dark:text-fg sm:whitespace-nowrap">{{ $label }}</span>
|
||||
<div class="flex shrink-0 items-center justify-end gap-2">
|
||||
<button type="button" onclick="window.location.reload()"
|
||||
class="h-8 rounded-lg bg-white/[0.07] px-3.5 text-[13px] font-medium text-fg transition-colors hover:bg-white/[0.12]">
|
||||
class="h-8 rounded-lg bg-neutral-100 px-3.5 text-[13px] font-medium text-neutral-700 transition-colors hover:bg-neutral-200 dark:bg-white/[0.07] dark:text-fg dark:hover:bg-white/[0.12]">
|
||||
Reset
|
||||
</button>
|
||||
<button type="button" wire:click="{{ $action }}" wire:loading.attr="disabled"
|
||||
class="button-highlighted flex h-8 items-center gap-2 rounded-lg px-4 text-[13px] font-semibold transition-[transform,background-color] active:scale-[0.98]">
|
||||
<span>Save changes</span>
|
||||
<kbd
|
||||
class="rounded border border-white/20 bg-white/10 px-1.5 py-0.5 text-[10px] leading-none font-medium text-white/75">Enter</kbd>
|
||||
class="rounded border border-coollabs/20 bg-coollabs/10 px-1.5 py-0.5 text-[10px] leading-none font-medium text-coollabs-200 dark:border-white/20 dark:bg-white/10 dark:text-white/75">Enter</kbd>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -95,7 +95,11 @@
|
||||
Select where to deploy your applications and databases. You can add more servers later.
|
||||
</x-slot:question>
|
||||
<x-slot:actions>
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-4 w-full">
|
||||
<div class="w-full space-y-6">
|
||||
<section>
|
||||
<h3 class="text-base font-semibold">Add a server</h3>
|
||||
<p class="mb-3 text-sm text-neutral-500 dark:text-neutral-400">Use this machine or connect a server you already manage.</p>
|
||||
<div class="grid w-full grid-cols-1 gap-4 lg:grid-cols-2">
|
||||
<button
|
||||
class="group relative cursor-pointer min-h-36 rounded-[10px] border border-neutral-200 bg-white p-4 text-left shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]"
|
||||
wire:target="setServerType('localhost')" wire:click="setServerType('localhost')">
|
||||
@@ -134,26 +138,29 @@
|
||||
d="M2.25 15a4.5 4.5 0 004.5 4.5H18a3.75 3.75 0 001.332-7.257 3 3 0 00-3.758-3.848 5.25 5.25 0 00-10.233 2.33A4.502 4.502 0 002.25 15z" />
|
||||
</svg>
|
||||
<div>
|
||||
<h3 class="mb-1 text-[14px] font-semibold">Remote server</h3>
|
||||
<h3 class="mb-1 text-[14px] font-semibold">IP address or domain</h3>
|
||||
<p class="text-sm dark:text-neutral-400">
|
||||
Connect via SSH to any server: cloud VPS, bare metal, or home infrastructure.
|
||||
Connect via SSH using a server IP address or domain.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@can('viewAny', App\Models\CloudProviderToken::class)
|
||||
<section>
|
||||
<h3 class="text-base font-semibold">Provision a server</h3>
|
||||
<p class="mb-3 text-sm text-neutral-500 dark:text-neutral-400">Create a server with a cloud provider.</p>
|
||||
<div class="grid w-full grid-cols-1 gap-4 lg:grid-cols-2">
|
||||
@if ($currentState === 'select-server-type')
|
||||
<x-modal-input title="Connect a Hetzner Server" isFullWidth>
|
||||
<x-slot:content>
|
||||
<div
|
||||
class="group relative cursor-pointer flex h-full min-h-36 flex-col rounded-[10px] border border-neutral-200 bg-white p-4 text-left shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]">
|
||||
<div class="flex h-full flex-col gap-4 text-left">
|
||||
<svg class="size-10 shrink-0" viewBox="0 0 200 200"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="200" height="200" fill="#D50C2D" rx="8" />
|
||||
<path d="M40 40 H60 V90 H140 V40 H160 V160 H140 V110 H60 V160 H40 Z"
|
||||
fill="white" />
|
||||
</svg>
|
||||
<img src="{{ asset('svgs/hetzner.svg') }}" alt="Hetzner"
|
||||
class="size-10 shrink-0">
|
||||
<div class="min-h-0 flex-1">
|
||||
<h3 class="mb-1 text-[14px] font-semibold">Hetzner Cloud</h3>
|
||||
<p class="text-sm dark:text-neutral-400">
|
||||
@@ -170,12 +177,8 @@
|
||||
<div
|
||||
class="group relative cursor-pointer flex h-full min-h-36 flex-col rounded-[10px] border border-neutral-200 bg-white p-4 text-left shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]">
|
||||
<div class="flex h-full flex-col gap-4 text-left">
|
||||
<svg class="size-10 shrink-0" viewBox="0 0 200 200"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="200" height="200" fill="#007BFC" rx="8" />
|
||||
<path d="M42 46 H73 L100 127 L127 46 H158 L114 154 H86 Z"
|
||||
fill="white" />
|
||||
</svg>
|
||||
<img src="https://www.vultr.com/media/logo_ondark.svg" alt="Vultr"
|
||||
class="h-10 w-28 shrink-0 object-contain object-left">
|
||||
<div class="min-h-0 flex-1">
|
||||
<h3 class="mb-1 text-[14px] font-semibold">Vultr Cloud</h3>
|
||||
<p class="text-sm dark:text-neutral-400">
|
||||
@@ -205,6 +208,8 @@
|
||||
<livewire:server.new.by-digital-ocean :limit_reached="false" :from_onboarding="true" />
|
||||
</x-modal-input>
|
||||
@endif
|
||||
</div>
|
||||
</section>
|
||||
@endcan
|
||||
</div>
|
||||
|
||||
@@ -421,19 +426,13 @@
|
||||
<x-forms.input placeholder="Optional: Note what this server hosts" label="Description"
|
||||
id="remoteServerDescription" wire:model="remoteServerDescription" />
|
||||
|
||||
<x-forms.collapsible title="Advanced Connection Settings"
|
||||
<x-forms.collapsible title="Advanced Settings"
|
||||
content-class="grid grid-cols-1 gap-4 lg:grid-cols-2">
|
||||
<x-forms.input placeholder="Default: 22" label="SSH Port" type="number"
|
||||
id="remoteServerPort" wire:model="remoteServerPort" />
|
||||
<div>
|
||||
<x-forms.input placeholder="Default: root" label="SSH User" id="remoteServerUser"
|
||||
wire:model="remoteServerUser" />
|
||||
<p class="mt-1 text-xs text-black dark:text-white">
|
||||
Non-root user support is experimental.
|
||||
<a class="font-bold underline hover:text-coollabs" target="_blank"
|
||||
href="https://coolify.io/docs/knowledge-base/server/non-root-user">Learn
|
||||
more</a>
|
||||
</p>
|
||||
</div>
|
||||
</x-forms.collapsible>
|
||||
<x-forms.button type="submit" class="w-full lg:w-auto">Validate Connection</x-forms.button>
|
||||
|
||||
@@ -178,15 +178,22 @@
|
||||
};
|
||||
@endphp
|
||||
|
||||
<article
|
||||
<a href="{{ route('server.show', ['server_uuid' => $server->uuid]) }}"
|
||||
{{ wireNavigate() }} aria-label="Open {{ $server->name }}"
|
||||
class="group relative flex min-h-28 min-w-0 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]">
|
||||
<a href="{{ route('server.show', ['server_uuid' => $server->uuid]) }}"
|
||||
{{ wireNavigate() }} class="absolute inset-0 rounded-xl"
|
||||
aria-label="Open {{ $server->name }}"></a>
|
||||
@if ($server->isMetricsEnabled())
|
||||
<livewire:dashboard.server-metrics-chart :server="$server"
|
||||
:key="'dashboard-server-metrics-'.$server->uuid" />
|
||||
@endif
|
||||
|
||||
<div class="flex min-w-0 items-start gap-3">
|
||||
<div
|
||||
class="flex size-8 shrink-0 items-center justify-center rounded-lg border border-neutral-200 bg-neutral-50 text-neutral-500 dark:border-white/[0.08] dark:bg-white/[0.04] dark:text-fg-dim">
|
||||
<div class="pointer-events-none relative z-10 flex min-w-0 items-start gap-3">
|
||||
<div title="{{ $serverStatus }}" aria-label="Server status: {{ $serverStatus }}"
|
||||
@class([
|
||||
'flex size-8 shrink-0 items-center justify-center rounded-lg border bg-neutral-50 text-neutral-500 dark:bg-white/[0.04] dark:text-fg-dim',
|
||||
'border-emerald-500/70' => $serverStatusType === 'success',
|
||||
'border-amber-500/70' => $serverStatusType === 'warning',
|
||||
'border-red-500/70' => $serverStatusType === 'error',
|
||||
])>
|
||||
<x-reicon name="servers" class="size-4" />
|
||||
</div>
|
||||
<div class="min-w-0 flex-1">
|
||||
@@ -199,11 +206,7 @@
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-auto flex items-center pt-4">
|
||||
<x-status-badge :status="$serverStatus" :type="$serverStatusType" />
|
||||
</div>
|
||||
</article>
|
||||
</a>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
|
||||
<a wire:key="dashboard-active-deployment-{{ $deployment->deployment_uuid }}"
|
||||
href="{{ $deployment->deployment_url }}" {{ wireNavigate() }}
|
||||
class="dashboard-deployment-table-grid group block border-b border-neutral-200 px-4 py-3 transition-colors last:border-b-0 hover:bg-neutral-50 md:grid md:items-center md:gap-4 dark:border-white/[0.08] dark:hover:bg-white/[0.025]">
|
||||
class="dashboard-deployment-table-grid group block border-b border-neutral-200 px-4 py-3 transition-colors last:border-b-0 hover:bg-neutral-50 focus-visible:z-10 focus-visible:bg-warning/10 focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-warning focus-visible:ring-offset-0 md:grid md:items-center md:gap-4 dark:border-white/[0.08] dark:hover:bg-white/[0.025] dark:focus-visible:bg-warning/10">
|
||||
<div class="min-w-0">
|
||||
<p class="truncate text-[13px] font-semibold text-black dark:text-fg">
|
||||
{{ $deployment->application_name }}
|
||||
@@ -139,7 +139,7 @@
|
||||
|
||||
<a wire:key="dashboard-recent-deployment-{{ $deployment->deployment_uuid }}"
|
||||
href="{{ $deployment->deployment_url }}" {{ wireNavigate() }}
|
||||
class="dashboard-deployment-table-grid group block border-b border-neutral-200 px-4 py-3 transition-colors last:border-b-0 hover:bg-neutral-50 md:grid md:items-center md:gap-4 dark:border-white/[0.08] dark:hover:bg-white/[0.025]">
|
||||
class="dashboard-deployment-table-grid group block border-b border-neutral-200 px-4 py-3 transition-colors last:border-b-0 hover:bg-neutral-50 focus-visible:z-10 focus-visible:bg-warning/10 focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-warning focus-visible:ring-offset-0 md:grid md:items-center md:gap-4 dark:border-white/[0.08] dark:hover:bg-white/[0.025] dark:focus-visible:bg-warning/10">
|
||||
<div class="min-w-0">
|
||||
<p class="truncate text-[13px] font-semibold text-black dark:text-fg">
|
||||
{{ $deployment->application_name }}
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
<div
|
||||
class="absolute right-0 bottom-0 h-2/3 w-full rounded-b-xl [&_.apexcharts-svg]:overflow-hidden [&_.apexcharts-svg]:rounded-b-xl [&_.apexcharts-tooltip]:z-30!"
|
||||
x-data="{
|
||||
hiddenAt: null,
|
||||
refreshInterval: null,
|
||||
visibilityHandler: null,
|
||||
init() {
|
||||
this.visibilityHandler = () => {
|
||||
if (document.hidden) {
|
||||
this.hiddenAt = Date.now();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.hiddenAt && Date.now() - this.hiddenAt >= 60000) {
|
||||
$wire.loadData();
|
||||
}
|
||||
|
||||
this.hiddenAt = null;
|
||||
};
|
||||
|
||||
document.addEventListener('visibilitychange', this.visibilityHandler);
|
||||
this.refreshInterval = window.setInterval(() => {
|
||||
if (!document.hidden) {
|
||||
$wire.loadData();
|
||||
}
|
||||
}, 60000);
|
||||
|
||||
$wire.loadData();
|
||||
},
|
||||
destroy() {
|
||||
window.clearInterval(this.refreshInterval);
|
||||
document.removeEventListener('visibilitychange', this.visibilityHandler);
|
||||
},
|
||||
}">
|
||||
<div wire:ignore id="dashboard-server-metrics-{{ $server->uuid }}" class="h-full w-full"></div>
|
||||
|
||||
@script
|
||||
<script>
|
||||
(() => {
|
||||
const chart = new ApexCharts(
|
||||
document.getElementById('dashboard-server-metrics-{{ $server->uuid }}'), {
|
||||
chart: {
|
||||
height: '100%',
|
||||
type: 'area',
|
||||
toolbar: { show: false },
|
||||
zoom: { enabled: false },
|
||||
animations: { enabled: true },
|
||||
sparkline: { enabled: true },
|
||||
background: 'transparent',
|
||||
},
|
||||
series: [
|
||||
{ name: 'CPU', data: [] },
|
||||
{ name: 'Memory', data: [] },
|
||||
],
|
||||
colors: [
|
||||
'rgba(30, 144, 255, 0.52)',
|
||||
'rgba(168, 85, 247, 0.42)',
|
||||
],
|
||||
stroke: {
|
||||
curve: 'smooth',
|
||||
width: 1.5,
|
||||
},
|
||||
fill: {
|
||||
type: 'gradient',
|
||||
gradient: {
|
||||
opacityFrom: 0.18,
|
||||
opacityTo: 0.02,
|
||||
stops: [0, 100],
|
||||
},
|
||||
},
|
||||
dataLabels: { enabled: false },
|
||||
grid: { show: false },
|
||||
legend: { show: false },
|
||||
markers: { size: 0 },
|
||||
xaxis: {
|
||||
type: 'datetime',
|
||||
labels: { show: false },
|
||||
axisBorder: { show: false },
|
||||
axisTicks: { show: false },
|
||||
},
|
||||
yaxis: {
|
||||
min: 0,
|
||||
max: 100,
|
||||
labels: { show: false },
|
||||
},
|
||||
tooltip: {
|
||||
shared: true,
|
||||
intersect: false,
|
||||
marker: { show: false },
|
||||
custom: ({ series, seriesIndex, dataPointIndex, w }) => {
|
||||
const cpu = series[0][dataPointIndex];
|
||||
const memory = series[1][dataPointIndex];
|
||||
const timestamp = w.globals.seriesX[seriesIndex][dataPointIndex];
|
||||
const formatPercent = value => Number.isFinite(value) ? `${Number(value.toFixed(1))}%` : '—';
|
||||
const formatTimestamp = timestamp => `${new Date(timestamp).toLocaleString(undefined, {
|
||||
timeZone: 'UTC',
|
||||
hour12: false,
|
||||
})} UTC`;
|
||||
|
||||
return `<div class="apexcharts-tooltip-custom">
|
||||
<div class="apexcharts-tooltip-custom-value">CPU: <span class="apexcharts-tooltip-value-bold">${formatPercent(cpu)}</span></div>
|
||||
<div class="apexcharts-tooltip-custom-value">Memory: <span class="apexcharts-tooltip-value-bold">${formatPercent(memory)}</span></div>
|
||||
<div class="apexcharts-tooltip-custom-title">${formatTimestamp(timestamp)}</div>
|
||||
</div>`;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
chart.render();
|
||||
|
||||
Livewire.on('dashboard-server-metrics-{{ $server->uuid }}', chartData => {
|
||||
chart.updateSeries([
|
||||
{
|
||||
name: 'CPU',
|
||||
data: chartData[0].cpu ?? [],
|
||||
},
|
||||
{
|
||||
name: 'Memory',
|
||||
data: chartData[0].memory ?? [],
|
||||
},
|
||||
]);
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
@endscript
|
||||
</div>
|
||||
@@ -120,12 +120,6 @@
|
||||
this.searchQuery = '';
|
||||
this.allSearchableItems = [];
|
||||
this.isPaletteTransitioning = false;
|
||||
// Ensure scroll is restored
|
||||
document.body.style.overflow = '';
|
||||
// Use $wire instead of @this for SPA navigation compatibility
|
||||
if ($wire) {
|
||||
$wire.closeSearchModal();
|
||||
}
|
||||
},
|
||||
runPaletteTransition(callback) {
|
||||
this.isPaletteTransitioning = true;
|
||||
@@ -299,16 +293,16 @@
|
||||
}">
|
||||
|
||||
<!-- Command palette -->
|
||||
<div x-show="modalOpen" x-cloak
|
||||
<div x-cloak :class="modalOpen ? 'pointer-events-auto' : 'pointer-events-none'"
|
||||
class="fixed inset-0 z-99 flex items-start justify-center px-4 pt-[12vh]">
|
||||
<div @click="closeModal()" class="absolute inset-0 w-full h-full bg-black/50 backdrop-blur-[2px]">
|
||||
<div x-show="modalOpen" @click="closeModal()"
|
||||
x-transition:enter="animate-in fade-in-0 duration-150"
|
||||
x-transition:leave="animate-out fade-out-0 duration-100"
|
||||
class="absolute inset-0 w-full h-full bg-black/50 backdrop-blur-[2px]">
|
||||
</div>
|
||||
<div x-show="modalOpen" x-trap.inert="modalOpen"
|
||||
x-init="$watch('modalOpen', value => { document.body.style.overflow = value ? 'hidden' : '' })"
|
||||
x-transition:enter="ease-out duration-150" x-transition:enter-start="opacity-0 -translate-y-2 scale-[0.98]"
|
||||
x-transition:enter-end="opacity-100 translate-y-0 scale-100" x-transition:leave="ease-in duration-100"
|
||||
x-transition:leave-start="opacity-100 translate-y-0 scale-100"
|
||||
x-transition:leave-end="opacity-0 -translate-y-2 scale-[0.98]"
|
||||
x-transition:enter="animate-in fade-in-0 zoom-in-95 slide-in-from-top-2 duration-150"
|
||||
x-transition:leave="animate-out fade-out-0 zoom-out-95 slide-out-to-top-2 duration-100"
|
||||
class="command-palette relative mx-auto"
|
||||
@click.stop>
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
<div x-data="{
|
||||
theme: localStorage.getItem('theme') === 'purple' ? 'custom' : (localStorage.getItem('theme') || 'dark'),
|
||||
themeColor: localStorage.getItem('themeColor') || '#6b16ed',
|
||||
themeColorFrame: null,
|
||||
init() {
|
||||
localStorage.setItem('theme', this.theme);
|
||||
this.applyTheme();
|
||||
@@ -12,9 +13,29 @@
|
||||
localStorage.setItem('theme', type);
|
||||
this.applyTheme();
|
||||
},
|
||||
setThemeColor() {
|
||||
localStorage.setItem('themeColor', this.themeColor);
|
||||
this.setTheme('custom');
|
||||
previewThemeColor(color) {
|
||||
this.themeColor = color;
|
||||
|
||||
if (this.theme !== 'custom') {
|
||||
this.theme = 'custom';
|
||||
document.documentElement.classList.add('dark');
|
||||
document.documentElement.dataset.theme = 'custom';
|
||||
}
|
||||
|
||||
if (this.themeColorFrame) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.themeColorFrame = requestAnimationFrame(() => {
|
||||
document.documentElement.style.setProperty('--theme-base-color', this.themeColor);
|
||||
document.documentElement.style.setProperty('--theme-accent-foreground', window.themeAccentForeground(this.themeColor));
|
||||
this.themeColorFrame = null;
|
||||
});
|
||||
},
|
||||
saveThemeColor(color) {
|
||||
this.previewThemeColor(color);
|
||||
localStorage.setItem('themeColor', color);
|
||||
localStorage.setItem('theme', 'custom');
|
||||
},
|
||||
applyTheme() {
|
||||
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||
@@ -76,7 +97,8 @@
|
||||
</p>
|
||||
</div>
|
||||
@if ($option['value'] === 'custom')
|
||||
<input type="color" x-model="themeColor" @input="setThemeColor()"
|
||||
<input type="color" :value="themeColor" @input="previewThemeColor($event.target.value)"
|
||||
@change="saveThemeColor($event.target.value)"
|
||||
aria-label="Custom theme color"
|
||||
class="absolute inset-0 z-10 h-full w-full cursor-pointer opacity-0" />
|
||||
@endif
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
class="absolute top-9 right-0 z-50 w-52 rounded-lg border border-neutral-200 bg-white p-1 shadow-modal dark:border-white/[0.1] dark:bg-raised">
|
||||
<template x-for="option in sortOptions" :key="option.value">
|
||||
<button type="button"
|
||||
class="flex h-8 w-full items-center rounded-md px-2 text-left text-[12px] text-neutral-600 transition-colors hover:bg-neutral-100 hover:text-black dark:text-fg-dim dark:hover:bg-white/[0.06] dark:hover:text-fg"
|
||||
class="flex h-9 w-full items-center rounded-md px-2 text-left text-[12px] text-neutral-600 transition-colors hover:bg-neutral-100 hover:text-black dark:text-fg-dim dark:hover:bg-white/[0.06] dark:hover:text-fg"
|
||||
x-on:click="sortBy = option.value; sortOpen = false; page = 1">
|
||||
<span class="flex-1" x-text="option.label"></span>
|
||||
<svg x-show="sortBy === option.value" class="size-3.5 text-warning"
|
||||
@@ -77,9 +77,9 @@
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="flex h-8 items-center rounded-lg border border-neutral-200 bg-white p-0.5 dark:border-white/[0.08] dark:bg-white/[0.035]">
|
||||
class="flex h-9 items-center rounded-lg border border-neutral-200 bg-white p-0.5 dark:border-white/[0.08] dark:bg-white/[0.035]">
|
||||
<button type="button" x-on:click="setViewMode('table')"
|
||||
class="flex size-6.5 items-center justify-center rounded-md transition-colors"
|
||||
class="flex size-7.5 items-center justify-center rounded-md transition-colors"
|
||||
:class="viewMode === 'table'
|
||||
?
|
||||
'control-selected' :
|
||||
@@ -88,7 +88,7 @@
|
||||
<x-reicon name="unordered-list" class="size-3.5" />
|
||||
</button>
|
||||
<button type="button" x-on:click="setViewMode('grid')"
|
||||
class="flex size-6.5 items-center justify-center rounded-md transition-colors"
|
||||
class="flex size-7.5 items-center justify-center rounded-md transition-colors"
|
||||
:class="viewMode === 'grid'
|
||||
?
|
||||
'control-selected' :
|
||||
@@ -133,12 +133,12 @@
|
||||
<div class="relative z-10 flex shrink-0 items-center gap-0.5">
|
||||
<a x-show="project.addResourceHref" :href="project.addResourceHref"
|
||||
{{ wireNavigate() }}
|
||||
class="flex size-6.5 items-center justify-center rounded-md text-neutral-400 transition-colors hover:bg-neutral-100 hover:text-black dark:text-fg-faint dark:hover:bg-white/[0.06] dark:hover:text-fg"
|
||||
class="flex size-7.5 items-center justify-center rounded-md text-neutral-400 transition-colors hover:bg-neutral-100 hover:text-black dark:text-fg-faint dark:hover:bg-white/[0.06] dark:hover:text-fg"
|
||||
title="Add resource" :aria-label="`Add resource to ${project.name}`">
|
||||
<x-reicon name="plus" class="size-3" />
|
||||
</a>
|
||||
<a x-show="project.settingsHref" :href="project.settingsHref" {{ wireNavigate() }}
|
||||
class="flex size-6.5 items-center justify-center rounded-md text-neutral-400 transition-colors hover:bg-neutral-100 hover:text-black dark:text-fg-faint dark:hover:bg-white/[0.06] dark:hover:text-fg"
|
||||
class="flex size-7.5 items-center justify-center rounded-md text-neutral-400 transition-colors hover:bg-neutral-100 hover:text-black dark:text-fg-faint dark:hover:bg-white/[0.06] dark:hover:text-fg"
|
||||
title="Project settings" :aria-label="`Open settings for ${project.name}`">
|
||||
<x-reicon name="settings" class="size-3" />
|
||||
</a>
|
||||
|
||||
@@ -129,7 +129,7 @@
|
||||
class="absolute top-9 right-0 z-50 w-48 rounded-lg border border-neutral-200 bg-white p-1 shadow-modal dark:border-white/[0.1] dark:bg-raised">
|
||||
<template x-for="option in sortOptions" :key="option.value">
|
||||
<button type="button"
|
||||
class="flex h-8 w-full items-center rounded-md px-2 text-left text-[12px] text-neutral-600 transition-colors hover:bg-neutral-100 hover:text-black dark:text-fg-dim dark:hover:bg-white/[0.06] dark:hover:text-fg"
|
||||
class="flex h-9 w-full items-center rounded-md px-2 text-left text-[12px] text-neutral-600 transition-colors hover:bg-neutral-100 hover:text-black dark:text-fg-dim dark:hover:bg-white/[0.06] dark:hover:text-fg"
|
||||
x-on:click="sortBy = option.value; sortOpen = false; page = 1">
|
||||
<span class="flex-1" x-text="option.label"></span>
|
||||
<svg x-show="sortBy === option.value" class="size-3.5 text-warning"
|
||||
@@ -143,9 +143,9 @@
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="flex h-8 items-center rounded-lg border border-neutral-200 bg-white p-0.5 dark:border-white/[0.08] dark:bg-white/[0.035]">
|
||||
class="flex h-9 items-center rounded-lg border border-neutral-200 bg-white p-0.5 dark:border-white/[0.08] dark:bg-white/[0.035]">
|
||||
<button type="button" x-on:click="setViewMode('table')"
|
||||
class="flex size-6.5 items-center justify-center rounded-md transition-colors"
|
||||
class="flex size-7.5 items-center justify-center rounded-md transition-colors"
|
||||
:class="viewMode === 'table'
|
||||
?
|
||||
'control-selected' :
|
||||
@@ -154,7 +154,7 @@
|
||||
<x-reicon name="unordered-list" class="size-3.5" />
|
||||
</button>
|
||||
<button type="button" x-on:click="setViewMode('grid')"
|
||||
class="flex size-6.5 items-center justify-center rounded-md transition-colors"
|
||||
class="flex size-7.5 items-center justify-center rounded-md transition-colors"
|
||||
:class="viewMode === 'grid'
|
||||
?
|
||||
'control-selected' :
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
['label' => 'Environment Variables', 'route' => 'project.service.environment-variables', 'icon' => 'variables', 'hasWarning' => ! $service->isDeployable],
|
||||
['label' => 'Persistent Storage', 'route' => 'project.service.storages', 'icon' => 'storages'],
|
||||
['label' => 'Backups', 'route' => 'project.service.volume-backups.index', 'icon' => 'database'],
|
||||
['label' => 'Runtime', 'route' => 'project.service.logs', 'icon' => 'unordered-list', 'navigate' => false],
|
||||
['label' => 'Runtime Logs', 'route' => 'project.service.logs', 'icon' => 'unordered-list', 'navigate' => false],
|
||||
['label' => 'Terminal', 'route' => 'project.service.command', 'icon' => 'browser-terminal', 'navigate' => false, 'visible' => auth()->user()?->can('canAccessTerminal')],
|
||||
['label' => 'Scheduled Tasks', 'route' => 'project.service.scheduled-tasks.show', 'icon' => 'calendar'],
|
||||
['label' => 'Webhooks', 'route' => 'project.service.webhooks', 'icon' => 'notifications'],
|
||||
@@ -33,14 +33,17 @@
|
||||
]);
|
||||
|
||||
$menuGroups = [
|
||||
'Settings' => ['General', 'Domains', 'Environment Variables', 'Persistent Storage', 'Backups'],
|
||||
'Automation' => ['Scheduled Tasks', 'Webhooks'],
|
||||
'Logs' => ['Runtime'],
|
||||
'Operations' => ['Terminal', 'Resource Operations', 'Tags', 'Danger Zone'],
|
||||
'Settings' => ['General', 'Domains', 'Environment Variables', 'Persistent Storage'],
|
||||
'Observe & troubleshoot' => ['Runtime Logs', 'Terminal'],
|
||||
'Automation' => ['Scheduled Tasks', 'Webhooks', 'Backups'],
|
||||
'Operations' => ['Resource Operations', 'Tags', 'Danger Zone'],
|
||||
];
|
||||
|
||||
$groupedItems = collect($menuGroups)
|
||||
->map(fn (array $labels) => $configurationItems->whereIn('label', $labels)->values())
|
||||
->map(fn (array $labels) => collect($labels)
|
||||
->map(fn (string $label) => $configurationItems->firstWhere('label', $label))
|
||||
->filter()
|
||||
->values())
|
||||
->filter(fn ($items) => $items->isNotEmpty());
|
||||
|
||||
$storageSections = $applications
|
||||
@@ -113,9 +116,9 @@
|
||||
</div>
|
||||
<div class="flex w-full items-center justify-between gap-2 sm:w-auto sm:justify-start">
|
||||
<div
|
||||
class="flex h-8 items-center rounded-lg border border-neutral-200 bg-white p-0.5 dark:border-white/[0.08] dark:bg-white/[0.035]">
|
||||
class="flex h-9 items-center rounded-lg border border-neutral-200 bg-white p-0.5 dark:border-white/[0.08] dark:bg-white/[0.035]">
|
||||
<button type="button" x-on:click="setViewMode('table')"
|
||||
class="flex size-6.5 items-center justify-center rounded-md transition-colors"
|
||||
class="flex size-7.5 items-center justify-center rounded-md transition-colors"
|
||||
:class="viewMode === 'table'
|
||||
? 'control-selected'
|
||||
: 'text-neutral-400 hover:bg-neutral-100 hover:text-black dark:text-fg-faint dark:hover:bg-white/[0.06] dark:hover:text-fg'"
|
||||
@@ -123,7 +126,7 @@
|
||||
<x-reicon name="unordered-list" class="size-3.5" />
|
||||
</button>
|
||||
<button type="button" x-on:click="setViewMode('grid')"
|
||||
class="flex size-6.5 items-center justify-center rounded-md transition-colors"
|
||||
class="flex size-7.5 items-center justify-center rounded-md transition-colors"
|
||||
:class="viewMode === 'grid'
|
||||
? 'control-selected'
|
||||
: 'text-neutral-400 hover:bg-neutral-100 hover:text-black dark:text-fg-faint dark:hover:bg-white/[0.06] dark:hover:text-fg'"
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
class="absolute top-9 right-0 z-50 w-48 rounded-lg border border-neutral-200 bg-white p-1 shadow-modal dark:border-white/[0.1] dark:bg-raised">
|
||||
<template x-for="option in sortOptions" :key="option.value">
|
||||
<button type="button"
|
||||
class="flex h-8 w-full items-center rounded-md px-2 text-left text-[12px] text-neutral-600 transition-colors hover:bg-neutral-100 hover:text-black dark:text-fg-dim dark:hover:bg-white/[0.06] dark:hover:text-fg"
|
||||
class="flex h-9 w-full items-center rounded-md px-2 text-left text-[12px] text-neutral-600 transition-colors hover:bg-neutral-100 hover:text-black dark:text-fg-dim dark:hover:bg-white/[0.06] dark:hover:text-fg"
|
||||
x-on:click="sortBy = option.value; sortOpen = false; page = 1">
|
||||
<span class="flex-1" x-text="option.label"></span>
|
||||
<svg x-show="sortBy === option.value" class="size-3.5 text-warning"
|
||||
@@ -99,9 +99,9 @@
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="flex h-8 items-center rounded-lg border border-neutral-200 bg-white p-0.5 dark:border-white/[0.08] dark:bg-white/[0.035]">
|
||||
class="flex h-9 items-center rounded-lg border border-neutral-200 bg-white p-0.5 dark:border-white/[0.08] dark:bg-white/[0.035]">
|
||||
<button type="button" x-on:click="setViewMode('table')"
|
||||
class="flex size-6.5 items-center justify-center rounded-md transition-colors"
|
||||
class="flex size-7.5 items-center justify-center rounded-md transition-colors"
|
||||
:class="viewMode === 'table'
|
||||
?
|
||||
'control-selected' :
|
||||
@@ -110,7 +110,7 @@
|
||||
<x-reicon name="unordered-list" class="size-3.5" />
|
||||
</button>
|
||||
<button type="button" x-on:click="setViewMode('grid')"
|
||||
class="flex size-6.5 items-center justify-center rounded-md transition-colors"
|
||||
class="flex size-7.5 items-center justify-center rounded-md transition-colors"
|
||||
:class="viewMode === 'grid'
|
||||
?
|
||||
'control-selected' :
|
||||
@@ -152,13 +152,13 @@
|
||||
<div class="relative z-10 flex shrink-0 items-center gap-0.5">
|
||||
<a x-show="environment.addResourceHref" :href="environment.addResourceHref"
|
||||
{{ wireNavigate() }}
|
||||
class="flex size-6.5 items-center justify-center rounded-md text-neutral-400 transition-colors hover:bg-neutral-100 hover:text-black dark:text-fg-faint dark:hover:bg-white/[0.06] dark:hover:text-fg"
|
||||
class="flex size-7.5 items-center justify-center rounded-md text-neutral-400 transition-colors hover:bg-neutral-100 hover:text-black dark:text-fg-faint dark:hover:bg-white/[0.06] dark:hover:text-fg"
|
||||
title="Add resource" :aria-label="`Add resource to ${environment.name}`">
|
||||
<x-reicon name="plus" class="size-3" />
|
||||
</a>
|
||||
<a x-show="environment.settingsHref" :href="environment.settingsHref"
|
||||
{{ wireNavigate() }}
|
||||
class="flex size-6.5 items-center justify-center rounded-md text-neutral-400 transition-colors hover:bg-neutral-100 hover:text-black dark:text-fg-faint dark:hover:bg-white/[0.06] dark:hover:text-fg"
|
||||
class="flex size-7.5 items-center justify-center rounded-md text-neutral-400 transition-colors hover:bg-neutral-100 hover:text-black dark:text-fg-faint dark:hover:bg-white/[0.06] dark:hover:text-fg"
|
||||
title="Environment settings"
|
||||
:aria-label="`Open settings for ${environment.name}`">
|
||||
<x-reicon name="settings" class="size-3" />
|
||||
|
||||
@@ -15,91 +15,89 @@
|
||||
</div>
|
||||
|
||||
@if (!$selectedType)
|
||||
<div class="application-settings-form">
|
||||
<div class="application-settings-form flex flex-col gap-6">
|
||||
<section class="application-settings-section">
|
||||
<div class="application-settings-section-body is-flush">
|
||||
<div class="grid grid-cols-1 gap-3 p-3 sm:grid-cols-2 lg:grid-cols-4">
|
||||
@can('viewAny', App\Models\CloudProviderToken::class)
|
||||
<a href="{{ route('server.create.type', ['type' => 'hetzner']) }}"
|
||||
class="group flex min-h-32 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:no-underline hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]"
|
||||
{{ wireNavigate() }}>
|
||||
<div class="flex items-start justify-between gap-3">
|
||||
<span
|
||||
class="flex size-8 items-center justify-center rounded-lg bg-[#D50C2D] text-[12px] font-bold text-white">H</span>
|
||||
<span
|
||||
class="rounded-full bg-neutral-100 px-2 py-0.5 text-[10px] font-medium text-neutral-600 dark:bg-white/[0.06] dark:text-fg-dim">
|
||||
Provider
|
||||
</span>
|
||||
</div>
|
||||
<div class="mt-auto pt-5">
|
||||
<h3 class="text-[13px]! font-semibold! text-black dark:text-fg">Hetzner</h3>
|
||||
<p class="mt-1 text-[11px] leading-4 text-neutral-500 dark:text-fg-faint">
|
||||
Provision from Hetzner Cloud.
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="{{ route('server.create.type', ['type' => 'vultr']) }}"
|
||||
class="group flex min-h-32 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:no-underline hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]"
|
||||
{{ wireNavigate() }}>
|
||||
<div class="flex items-start justify-between gap-3">
|
||||
<span
|
||||
class="flex size-8 items-center justify-center rounded-lg bg-[#007BFC] text-[12px] font-bold text-white">V</span>
|
||||
<span
|
||||
class="rounded-full bg-neutral-100 px-2 py-0.5 text-[10px] font-medium text-neutral-600 dark:bg-white/[0.06] dark:text-fg-dim">
|
||||
Provider
|
||||
</span>
|
||||
</div>
|
||||
<div class="mt-auto pt-5">
|
||||
<h3 class="text-[13px]! font-semibold! text-black dark:text-fg">Vultr</h3>
|
||||
<p class="mt-1 text-[11px] leading-4 text-neutral-500 dark:text-fg-faint">
|
||||
Provision from Vultr Cloud.
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="{{ route('server.create.type', ['type' => 'digital-ocean']) }}"
|
||||
class="group flex min-h-32 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:no-underline hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]"
|
||||
{{ wireNavigate() }}>
|
||||
<div class="flex items-start justify-between gap-3">
|
||||
<x-digital-ocean-icon class="size-8" />
|
||||
<span
|
||||
class="rounded-full bg-neutral-100 px-2 py-0.5 text-[10px] font-medium text-neutral-600 dark:bg-white/[0.06] dark:text-fg-dim">
|
||||
Provider
|
||||
</span>
|
||||
</div>
|
||||
<div class="mt-auto pt-5">
|
||||
<h3 class="text-[13px]! font-semibold! text-black dark:text-fg">DigitalOcean</h3>
|
||||
<p class="mt-1 text-[11px] leading-4 text-neutral-500 dark:text-fg-faint">
|
||||
Provision a new Droplet.
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
@endcan
|
||||
|
||||
<a href="{{ route('server.create.type', ['type' => 'manual']) }}"
|
||||
class="group flex min-h-32 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:no-underline hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]"
|
||||
{{ wireNavigate() }}>
|
||||
<div class="flex items-start justify-between gap-3">
|
||||
<span
|
||||
class="flex size-8 items-center justify-center rounded-lg border border-neutral-200 bg-neutral-50 text-neutral-500 dark:border-white/[0.08] dark:bg-white/[0.04] dark:text-fg-dim">
|
||||
<x-reicon name="servers" class="size-4" />
|
||||
</span>
|
||||
<span
|
||||
class="rounded-full bg-neutral-100 px-2 py-0.5 text-[10px] font-medium text-neutral-600 dark:bg-white/[0.06] dark:text-fg-dim">
|
||||
Manual
|
||||
</span>
|
||||
</div>
|
||||
<div class="mt-auto pt-5">
|
||||
<h3 class="text-[13px]! font-semibold! text-black dark:text-fg">IP address</h3>
|
||||
<p class="mt-1 text-[11px] leading-4 text-neutral-500 dark:text-fg-faint">
|
||||
Connect an existing server over SSH.
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
<div class="application-settings-section-header">
|
||||
<h2 class="application-settings-section-title">Add a server</h2>
|
||||
<p class="application-settings-section-description">Connect a server you already manage.</p>
|
||||
</div>
|
||||
<div class="application-settings-section-body is-flush">
|
||||
<div class="grid grid-cols-1 gap-3 p-3 sm:grid-cols-2 lg:grid-cols-4">
|
||||
<a href="{{ route('server.create.type', ['type' => 'manual']) }}"
|
||||
class="group flex min-h-32 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:no-underline hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]"
|
||||
{{ wireNavigate() }}>
|
||||
<div class="flex items-start">
|
||||
<span
|
||||
class="flex size-8 items-center justify-center rounded-lg border border-neutral-200 bg-neutral-50 text-neutral-500 dark:border-white/[0.08] dark:bg-white/[0.04] dark:text-fg-dim">
|
||||
<x-reicon name="servers" class="size-4" />
|
||||
</span>
|
||||
</div>
|
||||
<div class="mt-auto pt-5">
|
||||
<h3 class="text-[13px]! font-semibold! text-black dark:text-fg">IP address or domain</h3>
|
||||
<p class="mt-1 text-[11px] leading-4 text-neutral-500 dark:text-fg-faint">
|
||||
Connect an existing server over SSH.
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@can('viewAny', App\Models\CloudProviderToken::class)
|
||||
<section class="application-settings-section">
|
||||
<div class="application-settings-section-header">
|
||||
<h2 class="application-settings-section-title">Provision a server</h2>
|
||||
<p class="application-settings-section-description">Create a server with a cloud provider.</p>
|
||||
</div>
|
||||
<div class="application-settings-section-body is-flush">
|
||||
<div class="grid grid-cols-1 gap-3 p-3 sm:grid-cols-2 lg:grid-cols-3">
|
||||
<a href="{{ route('server.create.type', ['type' => 'hetzner']) }}"
|
||||
class="group flex min-h-32 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:no-underline hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]"
|
||||
{{ wireNavigate() }}>
|
||||
<div class="flex items-start">
|
||||
<img src="{{ asset('svgs/hetzner.svg') }}" alt="Hetzner" class="size-8">
|
||||
</div>
|
||||
<div class="mt-auto pt-5">
|
||||
<h3 class="text-[13px]! font-semibold! text-black dark:text-fg">Hetzner</h3>
|
||||
<p class="mt-1 text-[11px] leading-4 text-neutral-500 dark:text-fg-faint">
|
||||
Provision from Hetzner Cloud.
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="{{ route('server.create.type', ['type' => 'vultr']) }}"
|
||||
class="group flex min-h-32 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:no-underline hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]"
|
||||
{{ wireNavigate() }}>
|
||||
<div class="flex items-start">
|
||||
<img src="https://www.vultr.com/media/logo_ondark.svg" alt="Vultr"
|
||||
class="h-8 w-20 object-contain object-left">
|
||||
</div>
|
||||
<div class="mt-auto pt-5">
|
||||
<h3 class="text-[13px]! font-semibold! text-black dark:text-fg">Vultr</h3>
|
||||
<p class="mt-1 text-[11px] leading-4 text-neutral-500 dark:text-fg-faint">
|
||||
Provision from Vultr Cloud.
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="{{ route('server.create.type', ['type' => 'digital-ocean']) }}"
|
||||
class="group flex min-h-32 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:no-underline hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]"
|
||||
{{ wireNavigate() }}>
|
||||
<div class="flex items-start">
|
||||
<x-digital-ocean-icon class="size-8" />
|
||||
</div>
|
||||
<div class="mt-auto pt-5">
|
||||
<h3 class="text-[13px]! font-semibold! text-black dark:text-fg">DigitalOcean</h3>
|
||||
<p class="mt-1 text-[11px] leading-4 text-neutral-500 dark:text-fg-faint">
|
||||
Provision a new Droplet.
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@endcan
|
||||
</div>
|
||||
@else
|
||||
<div class="application-settings-form">
|
||||
|
||||
@@ -41,14 +41,19 @@
|
||||
default => 'Validation required',
|
||||
};
|
||||
|
||||
$statusType = match (true) {
|
||||
$isReady => 'success',
|
||||
$isTransferredAway || $server->settings->force_disabled => 'error',
|
||||
default => 'warning',
|
||||
};
|
||||
|
||||
return [
|
||||
'uuid' => $server->uuid,
|
||||
'name' => $server->name,
|
||||
'description' => $server->description ?: 'No description',
|
||||
'href' => route('server.show', ['server_uuid' => $server->uuid]),
|
||||
'status' => $status,
|
||||
'statusType' => $isReady ? 'success' : 'error',
|
||||
'ready' => $isReady,
|
||||
'statusType' => $statusType,
|
||||
];
|
||||
})->values();
|
||||
@endphp
|
||||
@@ -94,9 +99,9 @@
|
||||
<span x-text="filteredServers.length === 1 ? 'server' : 'servers'"></span>
|
||||
</span>
|
||||
<div
|
||||
class="flex h-8 items-center rounded-lg border border-neutral-200 bg-white p-0.5 dark:border-white/[0.08] dark:bg-white/[0.035]">
|
||||
class="flex h-9 items-center rounded-lg border border-neutral-200 bg-white p-0.5 dark:border-white/[0.08] dark:bg-white/[0.035]">
|
||||
<button type="button" x-on:click="setViewMode('table')"
|
||||
class="flex size-6.5 items-center justify-center rounded-md transition-colors"
|
||||
class="flex size-7.5 items-center justify-center rounded-md transition-colors"
|
||||
:class="viewMode === 'table'
|
||||
? 'control-selected'
|
||||
: 'text-neutral-400 hover:bg-neutral-100 hover:text-black dark:text-fg-faint dark:hover:bg-white/[0.06] dark:hover:text-fg'"
|
||||
@@ -104,7 +109,7 @@
|
||||
<x-reicon name="unordered-list" class="size-3.5" />
|
||||
</button>
|
||||
<button type="button" x-on:click="setViewMode('grid')"
|
||||
class="flex size-6.5 items-center justify-center rounded-md transition-colors"
|
||||
class="flex size-7.5 items-center justify-center rounded-md transition-colors"
|
||||
:class="viewMode === 'grid'
|
||||
? 'control-selected'
|
||||
: 'text-neutral-400 hover:bg-neutral-100 hover:text-black dark:text-fg-faint dark:hover:bg-white/[0.06] dark:hover:text-fg'"
|
||||
@@ -121,8 +126,9 @@
|
||||
<a :href="server.href" {{ wireNavigate() }}
|
||||
class="group relative flex min-h-28 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:no-underline hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]">
|
||||
<div class="flex items-start gap-3">
|
||||
<div
|
||||
class="flex size-8 shrink-0 items-center justify-center rounded-lg border border-neutral-200 bg-neutral-50 text-neutral-500 dark:border-white/[0.08] dark:bg-white/[0.04] dark:text-fg-dim">
|
||||
<div :title="server.status" :aria-label="`Server status: ${server.status}`"
|
||||
class="flex size-8 shrink-0 items-center justify-center rounded-lg border bg-neutral-50 text-neutral-500 dark:bg-white/[0.04] dark:text-fg-dim"
|
||||
:class="server.statusType === 'success' ? 'border-emerald-500/70' : server.statusType === 'warning' ? 'border-amber-500/70' : 'border-red-500/70'">
|
||||
<x-reicon name="servers" class="size-4" />
|
||||
</div>
|
||||
<div class="min-w-0 flex-1">
|
||||
@@ -132,13 +138,6 @@
|
||||
x-text="server.description"></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-auto flex items-center pt-4">
|
||||
<x-status-badge dynamic>
|
||||
<span class="size-1.5 rounded-full"
|
||||
:class="server.ready ? 'bg-emerald-500' : 'bg-red-500'"></span>
|
||||
<span x-text="server.status"></span>
|
||||
</x-status-badge>
|
||||
</div>
|
||||
</a>
|
||||
</template>
|
||||
</div>
|
||||
@@ -154,8 +153,9 @@
|
||||
<a :href="server.href" {{ wireNavigate() }}
|
||||
class="grid min-h-14 min-w-[480px] grid-cols-[minmax(0,1fr)_9.5rem] items-center border-b border-neutral-200 px-4 py-2.5 text-[12px] transition-colors last:border-b-0 hover:bg-neutral-50 hover:no-underline dark:border-white/[0.07] dark:hover:bg-white/[0.025]">
|
||||
<div class="flex min-w-0 items-center gap-3">
|
||||
<div
|
||||
class="flex size-8 shrink-0 items-center justify-center rounded-lg border border-neutral-200 bg-neutral-50 text-neutral-500 dark:border-white/[0.08] dark:bg-white/[0.035] dark:text-fg-dim">
|
||||
<div :title="server.status" :aria-label="`Server status: ${server.status}`"
|
||||
class="flex size-8 shrink-0 items-center justify-center rounded-lg border bg-neutral-50 text-neutral-500 dark:bg-white/[0.035] dark:text-fg-dim"
|
||||
:class="server.statusType === 'success' ? 'border-emerald-500/70' : server.statusType === 'warning' ? 'border-amber-500/70' : 'border-red-500/70'">
|
||||
<x-reicon name="servers" class="size-4" />
|
||||
</div>
|
||||
<div class="min-w-0">
|
||||
@@ -165,12 +165,8 @@
|
||||
x-text="server.description"></p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<x-status-badge dynamic>
|
||||
<span class="size-1.5 rounded-full"
|
||||
:class="server.ready ? 'bg-emerald-500' : 'bg-red-500'"></span>
|
||||
<span x-text="server.status"></span>
|
||||
</x-status-badge>
|
||||
<div class="text-[11px] font-medium text-neutral-600 dark:text-fg-dim">
|
||||
<span x-text="server.status"></span>
|
||||
</div>
|
||||
</a>
|
||||
</template>
|
||||
|
||||
@@ -83,9 +83,12 @@
|
||||
helper="Non-root SSH users are experimental." />
|
||||
<x-forms.input type="number" id="port" label="Port" required />
|
||||
</div>
|
||||
<x-forms.checkbox id="is_build_server"
|
||||
<x-forms.select id="is_build_server"
|
||||
helper="Build servers compile applications but do not host deployments. Enabling this makes the server build-only."
|
||||
label="Use as a dedicated build server" />
|
||||
label="Use as a dedicated build server">
|
||||
<option value="0">No</option>
|
||||
<option value="1">Yes</option>
|
||||
</x-forms.select>
|
||||
</x-forms.collapsible>
|
||||
</x-application.settings-section>
|
||||
</form>
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<span class="text-[11px] text-neutral-500 dark:text-fg-faint"><span x-text="filteredItems.length"></span> <span x-text="filteredItems.length === 1 ? '{{ $singular }}' : '{{ $plural }}'"></span></span>
|
||||
<div class="flex h-8 items-center rounded-lg border border-neutral-200 bg-white p-0.5 dark:border-white/[0.08] dark:bg-white/[0.035]">
|
||||
<button type="button" x-on:click="setViewMode('table')" class="flex size-6.5 items-center justify-center rounded-md transition-colors" :class="viewMode === 'table' ? 'control-selected' : 'text-neutral-400 hover:bg-neutral-100 hover:text-black dark:text-fg-faint dark:hover:bg-white/[0.06] dark:hover:text-fg'" aria-label="Table view"><x-reicon name="unordered-list" class="size-3.5" /></button>
|
||||
<button type="button" x-on:click="setViewMode('grid')" class="flex size-6.5 items-center justify-center rounded-md transition-colors" :class="viewMode === 'grid' ? 'control-selected' : 'text-neutral-400 hover:bg-neutral-100 hover:text-black dark:text-fg-faint dark:hover:bg-white/[0.06] dark:hover:text-fg'" aria-label="Grid view"><x-reicon name="grid" class="size-3.5" /></button>
|
||||
<div class="flex h-9 items-center rounded-lg border border-neutral-200 bg-white p-0.5 dark:border-white/[0.08] dark:bg-white/[0.035]">
|
||||
<button type="button" x-on:click="setViewMode('table')" class="flex size-7.5 items-center justify-center rounded-md transition-colors" :class="viewMode === 'table' ? 'control-selected' : 'text-neutral-400 hover:bg-neutral-100 hover:text-black dark:text-fg-faint dark:hover:bg-white/[0.06] dark:hover:text-fg'" aria-label="Table view"><x-reicon name="unordered-list" class="size-3.5" /></button>
|
||||
<button type="button" x-on:click="setViewMode('grid')" class="flex size-7.5 items-center justify-center rounded-md transition-colors" :class="viewMode === 'grid' ? 'control-selected' : 'text-neutral-400 hover:bg-neutral-100 hover:text-black dark:text-fg-faint dark:hover:bg-white/[0.06] dark:hover:text-fg'" aria-label="Grid view"><x-reicon name="grid" class="size-3.5" /></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,7 +1,7 @@
|
||||
<div x-data="{ search: '' }" class="application-settings-form">
|
||||
<x-application.settings-section title="Backup schedules"
|
||||
description="Schedules currently writing backup data to this storage." flush>
|
||||
@if ($groupedBackups->count() === 0)
|
||||
@if ($groupedBackups->count() === 0 && $volumeBackups->count() === 0)
|
||||
<x-empty title="No backup schedules use this storage"
|
||||
description="Select this storage from a database or volume backup schedule to see it here."
|
||||
icon-name="storages" size="sm" />
|
||||
@@ -18,7 +18,7 @@
|
||||
<div class="overflow-x-auto">
|
||||
<div
|
||||
class="grid min-w-[780px] grid-cols-[minmax(12rem,1fr)_9rem_7rem_minmax(15rem,1.2fr)] border-b border-neutral-200 bg-neutral-50 px-4 py-2.5 text-[11px] font-medium text-neutral-500 dark:border-white/[0.08] dark:bg-white/[0.025] dark:text-fg-faint">
|
||||
<div>Database</div>
|
||||
<div>Backup target</div>
|
||||
<div>Frequency</div>
|
||||
<div>Status</div>
|
||||
<div>Storage</div>
|
||||
@@ -93,10 +93,13 @@
|
||||
<span class="text-neutral-500 dark:text-fg-dim">{{ $backup->frequency }}</span>
|
||||
@endif
|
||||
</div>
|
||||
<x-status-badge :status="$backup->enabled ? 'Enabled' : 'Disabled'"
|
||||
:type="$backup->enabled ? 'success' : 'warning'" />
|
||||
<div class="flex items-center">
|
||||
<x-status-badge :status="$backup->enabled ? 'Enabled' : 'Disabled'"
|
||||
:type="$backup->enabled ? 'success' : 'warning'" />
|
||||
</div>
|
||||
<div class="flex items-end gap-2">
|
||||
<x-forms.listbox id="selectedStorages.{{ $backup->id }}" :options="$storageOptions" />
|
||||
<x-forms.listbox id="selectedStorages.{{ $backup->id }}" :options="$storageOptions"
|
||||
portal />
|
||||
<button type="button" class="button shrink-0"
|
||||
wire:click="moveBackup({{ $backup->id }})">Move</button>
|
||||
<button type="button" class="button shrink-0 text-error"
|
||||
@@ -108,6 +111,45 @@
|
||||
</div>
|
||||
@endforeach
|
||||
@endforeach
|
||||
@foreach ($volumeBackups as $backup)
|
||||
@php
|
||||
$targetName = $backup->targetName();
|
||||
$targetType = $backup->targetType();
|
||||
$resource = $backup->targetResource();
|
||||
$resourceName = $resource?->human_name ?? $resource?->name;
|
||||
$storageOptions = $allStorages->map(fn ($s3) => [
|
||||
'value' => $s3->id,
|
||||
'label' => $s3->name.($s3->is_usable ? '' : ' (unusable)'),
|
||||
'disabled' => ! $s3->is_usable,
|
||||
])->values()->all();
|
||||
@endphp
|
||||
<div
|
||||
class="grid min-h-14 min-w-[780px] grid-cols-[minmax(12rem,1fr)_9rem_7rem_minmax(15rem,1.2fr)] items-center border-b border-neutral-200 px-4 py-2.5 text-[12px] last:border-b-0 dark:border-white/[0.07]"
|
||||
x-show="search === '' || '{{ strtolower(addslashes($targetName)) }}'.includes(search.toLowerCase()) || '{{ strtolower(addslashes($targetType)) }}'.includes(search.toLowerCase()) || '{{ strtolower(addslashes($resourceName ?? '')) }}'.includes(search.toLowerCase()) || '{{ strtolower(addslashes($backup->frequency)) }}'.includes(search.toLowerCase())">
|
||||
<div class="min-w-0">
|
||||
<div class="truncate font-medium text-black dark:text-fg">{{ $targetName }}</div>
|
||||
<div class="truncate text-neutral-500 dark:text-fg-dim">
|
||||
{{ $targetType }}@if ($resourceName) · {{ $resourceName }} @endif
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-neutral-500 dark:text-fg-dim">{{ $backup->frequency }}</div>
|
||||
<div class="flex items-center">
|
||||
<x-status-badge :status="$backup->enabled ? 'Enabled' : 'Disabled'"
|
||||
:type="$backup->enabled ? 'success' : 'warning'" />
|
||||
</div>
|
||||
<div class="flex items-end gap-2">
|
||||
<x-forms.listbox id="selectedVolumeStorages.{{ $backup->id }}" :options="$storageOptions"
|
||||
portal />
|
||||
<button type="button" class="button shrink-0"
|
||||
wire:click="moveVolumeBackup({{ $backup->id }})">Move</button>
|
||||
<button type="button" class="button shrink-0 text-error"
|
||||
wire:click="disableVolumeS3({{ $backup->id }})"
|
||||
wire:confirm="Are you sure you want to disable S3 for this backup schedule?">
|
||||
Disable
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
</x-application.settings-section>
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
class="absolute top-9 right-0 z-50 w-52 rounded-lg border border-neutral-200 bg-white p-1 shadow-modal dark:border-white/[0.1] dark:bg-raised">
|
||||
<template x-for="option in sortOptions" :key="option.value">
|
||||
<button type="button"
|
||||
class="flex h-8 w-full items-center rounded-md px-2 text-left text-[12px] text-neutral-600 transition-colors hover:bg-neutral-100 hover:text-black dark:text-fg-dim dark:hover:bg-white/[0.06] dark:hover:text-fg"
|
||||
class="flex h-9 w-full items-center rounded-md px-2 text-left text-[12px] text-neutral-600 transition-colors hover:bg-neutral-100 hover:text-black dark:text-fg-dim dark:hover:bg-white/[0.06] dark:hover:text-fg"
|
||||
x-on:click="sortBy = option.value; sortOpen = false; page = 1">
|
||||
<span class="flex-1" x-text="option.label"></span>
|
||||
<svg x-show="sortBy === option.value" class="size-3.5 text-warning"
|
||||
@@ -70,9 +70,9 @@
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="flex h-8 items-center rounded-lg border border-neutral-200 bg-white p-0.5 dark:border-white/[0.08] dark:bg-white/[0.035]">
|
||||
class="flex h-9 items-center rounded-lg border border-neutral-200 bg-white p-0.5 dark:border-white/[0.08] dark:bg-white/[0.035]">
|
||||
<button type="button" x-on:click="setViewMode('table')"
|
||||
class="flex size-6.5 items-center justify-center rounded-md transition-colors"
|
||||
class="flex size-7.5 items-center justify-center rounded-md transition-colors"
|
||||
:class="viewMode === 'table'
|
||||
?
|
||||
'control-selected' :
|
||||
@@ -81,7 +81,7 @@
|
||||
<x-reicon name="unordered-list" class="size-3.5" />
|
||||
</button>
|
||||
<button type="button" x-on:click="setViewMode('grid')"
|
||||
class="flex size-6.5 items-center justify-center rounded-md transition-colors"
|
||||
class="flex size-7.5 items-center justify-center rounded-md transition-colors"
|
||||
:class="viewMode === 'grid'
|
||||
?
|
||||
'control-selected' :
|
||||
|
||||
@@ -70,11 +70,16 @@
|
||||
themeAccents: @js($consoleThemeAccents),
|
||||
consoleTheme: 'system',
|
||||
themeOpen: false,
|
||||
get filteredTargets() {
|
||||
get filteredTargetGroups() {
|
||||
const query = this.targetSearch.trim().toLowerCase();
|
||||
return query
|
||||
const targets = query
|
||||
? this.targets.filter((target) => target.label.toLowerCase().includes(query))
|
||||
: this.targets;
|
||||
|
||||
return [
|
||||
{ type: 'server', label: 'Servers', targets: targets.filter((target) => target.type === 'server') },
|
||||
{ type: 'container', label: 'Containers', targets: targets.filter((target) => target.type === 'container') },
|
||||
].filter((group) => group.targets.length > 0);
|
||||
},
|
||||
init() {
|
||||
const savedTheme = localStorage.getItem('coolify-console-theme');
|
||||
@@ -139,19 +144,27 @@
|
||||
<div class="mt-1 text-xs text-white/45">Connect a reachable server and enable terminal access.</div>
|
||||
</div>
|
||||
@else
|
||||
<template x-for="target in filteredTargets" :key="target.value">
|
||||
<button type="button"
|
||||
class="flex min-h-11 w-full items-center gap-3 rounded-md px-3 text-left text-sm text-white/70 transition-colors hover:bg-white/[0.07] hover:text-white"
|
||||
x-on:click="selectTarget(target)">
|
||||
<x-reicon name="servers" x-show="target.type === 'server'"
|
||||
class="size-4 shrink-0 text-white/40" />
|
||||
<x-reicon name="layers" x-show="target.type === 'container'"
|
||||
class="size-4 shrink-0 text-white/40" />
|
||||
<span class="min-w-0 flex-1 truncate" x-text="target.label"></span>
|
||||
<x-reicon name="arrow-right" class="size-3.5 shrink-0 text-white/35" />
|
||||
</button>
|
||||
<template x-for="group in filteredTargetGroups" :key="group.type">
|
||||
<section class="not-last:mb-2">
|
||||
<div class="px-3 py-2 text-[10px] font-semibold tracking-wider text-white/40 uppercase"
|
||||
x-text="group.label"></div>
|
||||
<template x-for="target in group.targets" :key="target.value">
|
||||
<button type="button"
|
||||
class="flex min-h-11 w-full items-center gap-3 rounded-md px-3 text-left text-sm text-white/70 transition-colors hover:bg-white/[0.07] hover:text-white"
|
||||
x-on:click="selectTarget(target)">
|
||||
<x-reicon name="servers" x-show="target.type === 'server'"
|
||||
class="size-4 shrink-0 text-white/40" />
|
||||
<x-reicon name="layers" x-show="target.type === 'container'"
|
||||
class="size-4 shrink-0 text-white/40" />
|
||||
<span class="min-w-0 flex-1 truncate" x-text="target.label"></span>
|
||||
<span class="rounded-full border border-white/10 px-2 py-0.5 text-[10px] text-white/40"
|
||||
x-text="target.type"></span>
|
||||
<x-reicon name="arrow-right" class="size-3.5 shrink-0 text-white/35" />
|
||||
</button>
|
||||
</template>
|
||||
</section>
|
||||
</template>
|
||||
<div x-show="filteredTargets.length === 0"
|
||||
<div x-show="filteredTargetGroups.length === 0"
|
||||
class="px-3 py-8 text-center text-sm text-white/50">
|
||||
No matching targets
|
||||
</div>
|
||||
@@ -211,25 +224,33 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="terminal-target-list max-h-72 overflow-y-auto p-1">
|
||||
<template x-for="target in filteredTargets" :key="target.value">
|
||||
<button type="button"
|
||||
class="flex min-h-8 w-full cursor-pointer items-center gap-2 rounded-md px-2 text-left text-[11px] text-white/65 transition-colors hover:bg-white/[0.07] hover:text-white"
|
||||
x-on:click="selectTarget(target)">
|
||||
<x-reicon name="servers" x-cloak x-show="target.type === 'server'"
|
||||
class="size-3.5 shrink-0 text-white/35" />
|
||||
<x-reicon name="layers" x-cloak x-show="target.type === 'container'"
|
||||
class="size-3.5 shrink-0 text-white/35" />
|
||||
<span class="min-w-0 flex-1 truncate" x-text="target.label"></span>
|
||||
<svg x-show="$wire.selected_uuid === target.value"
|
||||
class="size-3 text-[#fcd452]" viewBox="0 0 12 12" fill="none"
|
||||
aria-hidden="true">
|
||||
<path d="m2.5 6.25 2.1 2.1 4.9-5" stroke="currentColor"
|
||||
stroke-width="1.4" stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
</svg>
|
||||
</button>
|
||||
<template x-for="group in filteredTargetGroups" :key="group.type">
|
||||
<section class="not-last:mb-1">
|
||||
<div class="px-2 py-1.5 text-[9px] font-semibold tracking-wider text-white/35 uppercase"
|
||||
x-text="group.label"></div>
|
||||
<template x-for="target in group.targets" :key="target.value">
|
||||
<button type="button"
|
||||
class="flex min-h-8 w-full cursor-pointer items-center gap-2 rounded-md px-2 text-left text-[11px] text-white/65 transition-colors hover:bg-white/[0.07] hover:text-white"
|
||||
x-on:click="selectTarget(target)">
|
||||
<x-reicon name="servers" x-cloak x-show="target.type === 'server'"
|
||||
class="size-3.5 shrink-0 text-white/35" />
|
||||
<x-reicon name="layers" x-cloak x-show="target.type === 'container'"
|
||||
class="size-3.5 shrink-0 text-white/35" />
|
||||
<span class="min-w-0 flex-1 truncate" x-text="target.label"></span>
|
||||
<span class="rounded-full border border-white/10 px-1.5 py-0.5 text-[9px] text-white/35"
|
||||
x-text="target.type"></span>
|
||||
<svg x-show="$wire.selected_uuid === target.value"
|
||||
class="size-3 text-[#fcd452]" viewBox="0 0 12 12" fill="none"
|
||||
aria-hidden="true">
|
||||
<path d="m2.5 6.25 2.1 2.1 4.9-5" stroke="currentColor"
|
||||
stroke-width="1.4" stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
</svg>
|
||||
</button>
|
||||
</template>
|
||||
</section>
|
||||
</template>
|
||||
<div x-show="filteredTargets.length === 0"
|
||||
<div x-show="filteredTargetGroups.length === 0"
|
||||
class="px-2 py-5 text-center text-[11px] text-white/35">
|
||||
No matching targets
|
||||
</div>
|
||||
@@ -281,18 +302,26 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="max-h-72 overflow-y-auto p-1">
|
||||
<template x-for="target in filteredTargets" :key="target.value">
|
||||
<button type="button"
|
||||
class="flex min-h-9 w-full items-center gap-2 rounded-md px-2 text-left text-[11px] text-white/65 transition-colors hover:bg-white/[0.07] hover:text-white"
|
||||
x-on:click="selectTarget(target)">
|
||||
<x-reicon name="servers" x-show="target.type === 'server'"
|
||||
class="size-3.5 shrink-0 text-white/35" />
|
||||
<x-reicon name="layers" x-show="target.type === 'container'"
|
||||
class="size-3.5 shrink-0 text-white/35" />
|
||||
<span class="min-w-0 flex-1 truncate" x-text="target.label"></span>
|
||||
</button>
|
||||
<template x-for="group in filteredTargetGroups" :key="group.type">
|
||||
<section class="not-last:mb-1">
|
||||
<div class="px-2 py-1.5 text-[9px] font-semibold tracking-wider text-white/35 uppercase"
|
||||
x-text="group.label"></div>
|
||||
<template x-for="target in group.targets" :key="target.value">
|
||||
<button type="button"
|
||||
class="flex min-h-9 w-full items-center gap-2 rounded-md px-2 text-left text-[11px] text-white/65 transition-colors hover:bg-white/[0.07] hover:text-white"
|
||||
x-on:click="selectTarget(target)">
|
||||
<x-reicon name="servers" x-show="target.type === 'server'"
|
||||
class="size-3.5 shrink-0 text-white/35" />
|
||||
<x-reicon name="layers" x-show="target.type === 'container'"
|
||||
class="size-3.5 shrink-0 text-white/35" />
|
||||
<span class="min-w-0 flex-1 truncate" x-text="target.label"></span>
|
||||
<span class="rounded-full border border-white/10 px-1.5 py-0.5 text-[9px] text-white/35"
|
||||
x-text="target.type"></span>
|
||||
</button>
|
||||
</template>
|
||||
</section>
|
||||
</template>
|
||||
<div x-show="filteredTargets.length === 0"
|
||||
<div x-show="filteredTargetGroups.length === 0"
|
||||
class="px-2 py-5 text-center text-[11px] text-white/35">
|
||||
No matching targets
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg fill="#000000" width="800px" height="800px" viewBox="0 0 24 24" role="img" xmlns="http://www.w3.org/2000/svg"><title>InfluxDB icon</title><path d="M23.775 14.443L21.482 4.5c-.128-.536-.621-1.093-1.178-1.243L9.868.043C9.739 0 9.589 0 9.418 0c-.45 0-.9.171-1.222.45L.718 7.414C.31 7.78.096 8.507.225 9.021l2.443 10.65c.128.536.621 1.093 1.178 1.243l9.772 3.043c.128.043.278.043.45.043.45 0 .9-.171 1.221-.45l7.993-7.436c.407-.428.622-1.114.493-1.671zM10.961 2.4l7.178 2.207c.279.086.279.214 0 .279l-3.771.857c-.279.086-.686-.043-.879-.257l-2.614-2.829c-.236-.236-.193-.343.086-.257zm4.478 12.857c.086.279-.107.45-.385.364l-7.736-2.4c-.279-.085-.343-.321-.129-.514L13.104 7.2c.214-.214.45-.129.514.15zM2.69 8.25L8.968 2.4c.214-.214.536-.171.75.021l3.15 3.408c.214.214.171.535-.022.75l-6.278 5.85c-.214.214-.536.171-.75-.022L2.668 9c-.214-.236-.193-.579.021-.75zm1.522 9.257l-1.65-7.286c-.086-.278.043-.342.235-.128l2.615 2.828c.214.215.278.622.214.9l-1.136 3.686c-.085.3-.214.3-.278 0zm9.193 4.286l-8.208-2.55a.555.555 0 01-.364-.686l1.372-4.414a.555.555 0 01.685-.364l8.207 2.528c.279.086.45.386.365.686l-1.372 4.414a.598.598 0 01-.685.386zm7.285-5.979l-5.485 5.1c-.215.215-.322.129-.236-.15l1.136-3.685c.085-.279.385-.579.685-.622l3.772-.857c.278-.107.321.021.128.214zm.6-1.114l-4.521 1.029c-.279.085-.579-.108-.643-.386l-1.929-8.357c-.085-.279.108-.579.386-.643l4.522-1.029c.278-.085.578.107.642.386l1.929 8.357c.064.322-.107.6-.386.643z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2" viewBox="0 19 326 286"><use xlink:href="#a" width="326" height="286" y="19"/><defs><image xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAUYAAAEeCAYAAAD2CrxqAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAgAElEQVR4nO3deWBU1dk/8O9zZzJJWERZ3KlAZgJ0loDRVn1bjdrSaitCZi4i1l1Rq1jXWpe+RnH9ue+KS1UqojMBX7BqtRa0VatCgZmMJJkJqFiqImhMiMkkc5/fH8m01IKSZCbPnTnn8yck936V5Jl7zj3nOYCmaZr2H0g6gKaGtROmjxhUZAzrzzU2uVIfH7ByaVu2MmnajujCqOXU+qpTSro2t1wN0HkAhvTzcpsIdK07Fr43G9k0bUd0YdRypslvzrJg3QTQ6Gxel4Eogc72xMJvZfO6mpahC6OWdQ3+4AQDtADA5JzeiGhpV6rr1In1izfn9D6acnRh1LJmw8FmaXsLngHx0QAcA3TbVhAecg/3/YaW13QN0D21AqcLo9ZvDFDSF/pfEH4NYJBQjE0Enu2O1T4ndH+tgOjCqPVL0hc6hAnPARglnaUbb/gK7RWB2B8+l06i5S9dGLU+2TR+6tAvXK4EgD2ks+zAW55Y5BDpEFp+0oVR67VGX+hpIpgYuHnEvkqD8VtPXeRG6SBaftGFUdsp3fOIwVNBNA/2L4hf106gH7hj4ZXSQbT8oAuj9o0YoLUTj/MWOdOvARgunac/GIgalP6xO7r4U+ksmr3pwqjtUNxrDnc5sATM/yOdJasYjww1Si/YMzp/q3QUzZ50YdT+y8eBEwe3cNtVAP1GOksOpSzi2V1p42lvPJySDqPZiy6M2r+sqJxdtGtq888Y9AwAl3SegcEbQM4Z7ugzbxPA0mk0e9CFUQMD1OQ392dYCwAql84j5CXDorPK4uEPpYNo8nRhVNx6r7lnJ/EdRJgpncUOLMY1XUy3euPhVuksmhxdGBW1rKrKue+W4eeBjTuks9hQOxFOLYv6niXUWNJhtIGnC6OCEgEzBOZHAPSrcawCVgF0rm5vph5dGBWS9JuVTLir4Jbf5BpTbZvR9csKvf5RGbowKiDx/RN2QVvHHQBOk86Sx9JgzPXURa6RDqLlni6MBS7hC10t3A6s0HzCoIvKY+EF0kG03NGFsUAl/aGjmPAAGPtJZylM9De2cE55PLxaOomWfbowFpi1E6aNcRYVPQHw/yD/mj3kmxQzFnUynamX9xQWXRgLBFfOLkp2bn4UTMdBmV0rttECxm16/rFw6MJYAJL+4JkMugV6+Y20jRbhpPHRyKvSQbT+0YUxjzX5Tb8FfgnA3tJZtH9jIModHUeOb1z6mXQWrW90YcxDGyuPGdSaKllO4AOls2g7lCbg2b/H6MQZCKelw2i9owtjHmGAmnzBm5noIugXK/kibbFljq9btFg6iLbzdGHME+t85o/TxC9L59D6jii9h+4enh90YbS5pnHmMGswr0OeHyug/cuqNir9YYXuHm5rujDa1PpJ03ZNp4ueYvDR0lm07CNgbvEQunH0W+GvpLNo/00XRptZP+aUkq5dvjwbbNwKPY9Y6NoIfMKGEZufP3z58i7pMNq/6cJoE4waoykQr2LmRdDrERXDjQ4ypo6Lhhukk2jddGG0gXUBc3wXY75efqM2ZiwsKXJe/J1VCzdKZ1GdLoyCkoHpuzOMGjCdI53FFgi3gTEHam9pTBHhyuLBdJ+ef5SjC6OA7nnE1tPAuBnAEOk8duGJRWj9pGm7dnUVPQniY6TzCNtEwMllMd8f9fEKA08XxgGW9IeOYuBuAG7pLHbjiUX+9fPY5AseYBE9DsArl8gO6HXL6jp/fHzxGukkKtGFcYAkvaYbBu7Sy292bNvCCPS8kPLHz2DwdQBGCcWyBQbPK0bxb/aLLfhcOosKdGHMMa6qcjZtHnk7A3Oks9jd1wtjRv34qUMdxa6r9fwjWi1GTXmd7w49vM4tXRhzqMEXutgg1EDPI+6UHRXGjKTXdLMDt4OVn39MgvgiT7R2qXSQQqULYw4k/ObBDH6QgIB0lnzybYUxIxkwj2DwY8of20C0rKuk1Jz4zpObpaMUGl0YsyjuNYe7DH4awBTpLPloZwsjAMS9pstF1i9A9ADUHl6nGTy/PFZ7qnSQQqILY5Yk/KF7AZwOoEQ6S77qTWHMaCg/ZqRRXFwD4NzsJ8orzSBc4YlG7pcOUgh0YeynpM88jonvgeJvTbOhL4UxY+2kaWOcaeeLACZkMVI+ShJopjsWXikdJJ/pwthHTZOCHitNL0CvR8ya/hTGjJ7jHlZB7QYcaRC9bhRhetnKcLN0mHxkSAfIN+w1XUm/+QcrTWuhi6LtlMXCMfeIz0oA4yLpLIIcYD7cSvGnSX/obukw+Ug/MfZCwhe6HIS5UPtpJGey8cS4rYT7qGIqHfwHBo7M5nXzUIrBPyuP1f5JOki+0IVxJ/RsT3tXOkehy3ZhzOhZLbAOup3bJjjJ61kV3iQdxO50YfwG63xT9+gi18t6PeLAyFVhzGjwzzjagBUGMCiX97E7BhZ3WnSSNx5ulc5iV7owbkfcaw5xEd8BwhnSWVSS68KYkfCH7gDwS6i9/hEEOusL126/O2DlvE7pLHajC+M2njVNx/5rEWLihdJZhKUAdAAYOpA3HajCCPQMrx2IgPlQKD5nTIz/cddF3pTOYSe6MPZY551ekTYcr0H1eSiiN0oIx31lWdcR6JSBvPVAFsaMxkDw+8R4EqDygb63nTDo3WJYM/eL1a6TzmIHyhfGD/zBcSkYvwP4UOksoggfEFmnutcsWgYAjf7g71QojBmJQOiXYMyF6sfUEj9QkjauGh0Pb5GOIknZdYxNleawpD90bQrUqHhRbCGiqzzRyJhMUVSRJxq539ny2T4MfhzdUwlqYjqn3eB/JP3BM5dVVTml40hRrjAuq6pyJgOhk6wUf8DAb6Hu/FKagKedI4bs7o6Gr5cOYwdj31/eXh6rPdXpcI4H8LJ0HkElDJq37+aRDU2BkJJrQJUaSid9oUMswgN6+Q3egkVneOLh93b0BaoNpben+xgKfgig0dJZhL1kOPj8stW1CekgA8VWP4i5kghU7ws2bgdgSmeRxRsMpgvK6iKLvu0rdWH8t2QgdAkzrofay3vSxHw7tRnXl60r/P3XBT2UfnNfszTpD10LNhJQvSgyrvhoxOZxO1MUtf/kjkZuTadSIxk8TzqLIAcTXWoN5kTSHzyTTbOgp6AKtjA2+s1Zo3bjZM88oro9Eonnpyzay1MXufHw5cu7pOPkqwkNS1rKY7VnwWAfiN6QziNoFIPmJer5701e8wfSYXKl4ApjU8Vx5Y1+8x0CPwVgb+k8UhiIOokP8kRrT/LGwx9L5ykUnjW18VXjcRiIpwLYKJ1HCgEBy+C/JALmksT3T9hFOk+2FUxh5KoqZ8JnLrGsdAOBD5TOI6jVYAQ9E2j/sdHat6XDFKIZ4XDaE61d2uzq8BDhUuk8opiPQVvHJwl/6A5GTcHUk4L4D0kEQtcnN4/8HKT46XGMGgwq3qesLrKIwuG0dJxCd8DKpW3uaOTWlEV7EfC0dB5BJQAuSPrrNiR8wRnSYbLBlm8Bd1aiIjQFFn4HhYfMPV5yWnTq2CwOmfVb6d5LTDa/iy7+PyjfwJgbU5ZxWD5P4eTlE+PHgSmDE/7QWlj4I9Quip+wRZPdscjR2SyKWt94VoXfWzWBJjiYpgBol84jh8pdBn+UCJh/lk7SV3lXGBM+M9LCuzRD7UOP0kw866MRn+1bHg+vJoClA2ndZoTD6XF14VecLUN2I+ZbpPMIcoD58IQ/1JHwha6WDtNbeTN0SQZCJzHjMai7ha8b8fyPhm8+LddLb/RQOjviXtNVZPC7ercVmi2Dfj5+Tfiv0kF2hu03iTdVHFduWekVzAPbG9CGPvHEIntKh9B6xxsPpwBUJH0zRzN1JaHu7plhhsV/SfiDjcMso3J3m3cPt+1QOu41hycC5l8tK92AAW6YajOtDFeZLor5zV23cIMnFikmwslQfP6x2eCWhD/0aMJ9VLF0mh2xXWHccLBZmvAHb3QZvBnM/yOdR1AbGDWeWGRoeWyBbh5aINzRyJPumG8wgKcAqLyk6jSUDm5P+szjVlTOLpIO83W2KYzLqqqcSX9wWnsrbwHoN9J5BKUZWPxRy5ARnrrINdJhtOwj1FieWOQXKYt2ZyAqnUcSEy8cltrycaIiOJlt9M7DFnOMDd7pFcZm41lWvL08gFWGkZ5ZtmZxo3QQLfe83V2yKxoqzB8YlrVA4fZmw2HR35MBc2lTGueVxcMfSgcSrdDvT6zeK+U07iNgumQOG9hITBe568LPSAfJ0G+lB17CF7oahAuh+LlDBMwdQqU37xmdv1Uqg8hQmitnFyX95nmdTmOj4kWxHYQbml3Dx9ipKGoyPHWRa0o702U92wuVPV6Bgd+28FefSm4vHPBP6J5DzxdC7TfNaQDPE6Vnu6OLP5UOsz36iVFW4yRzEqXxAMAHSWcRFncSnz7QDVEG7AexwTu9wjCcD6r+D81AlMg6yxNd9DfpLN9EF0Z7aAwEjyemW6H21leAqbYdHef665Z8MhC3y/lQOhmYvnvCF3rYMBwrFS+KW8B8enksUmH3oqjZR3m09umURWPBqIHCw2sQB0vI9WEyYF7JA7C8J2eFsXseMfRrZkcShDOg7la+NIA7u7to1z4mHUbLP954OOWpi1zjtGg/ZiyUzLine truncated
|
||||
|
After Width: | Height: | Size: 20 KiB |
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="1024" height="1024">
|
||||
<path d="M0 0 C1.24605143 -0.00320648 2.49210286 -0.00641296 3.77591342 -0.0097166 C7.20551324 -0.01654213 10.63489336 -0.01454336 14.06448046 -0.00866088 C17.80678204 -0.00446316 21.54906441 -0.01190796 25.29136121 -0.01781338 C31.84084796 -0.02655123 38.39030342 -0.02789611 44.93979454 -0.02431011 C54.67961151 -0.01899148 64.41939833 -0.02511011 74.15921202 -0.03339304 C92.56926142 -0.04861937 110.97929706 -0.05033948 129.38935144 -0.04787002 C143.60890976 -0.04603597 157.82846357 -0.0477993 172.04802132 -0.05209446 C174.09235779 -0.05269687 176.13669427 -0.05329806 178.18103074 -0.05389806 C181.26182901 -0.05480534 184.34262728 -0.05571401 187.42342555 -0.05663041 C216.06152484 -0.06505806 244.69962243 -0.06939698 273.33772278 -0.06522369 C274.95656045 -0.06498913 274.95656045 -0.06498913 276.60810192 -0.06474983 C282.07778518 -0.06394407 287.54746842 -0.0630983 293.01715167 -0.06223653 C294.64653437 -0.06197989 294.64653437 -0.06197989 296.30883388 -0.06171808 C298.50550538 -0.06137142 300.70217687 -0.06102289 302.89884837 -0.06067249 C337.07170733 -0.05531644 371.24454049 -0.06324318 405.41739464 -0.08170605 C443.83052411 -0.10243565 482.24363759 -0.11314686 520.65677297 -0.10913056 C524.75506425 -0.10873523 528.85335552 -0.10837368 532.9516468 -0.10803318 C533.96071349 -0.10794245 534.96978018 -0.10785172 536.00942464 -0.10775824 C551.22334929 -0.10659366 566.43725776 -0.11323001 581.65117836 -0.1238451 C598.96103916 -0.13591042 616.2708644 -0.13744077 633.58072574 -0.12505493 C643.25916158 -0.11843905 652.93751231 -0.12002798 662.6159413 -0.13364345 C669.09234848 -0.1419165 675.56869223 -0.13915349 682.04509432 -0.12766818 C685.72751758 -0.12143989 689.40977538 -0.11973724 693.09218879 -0.13153151 C742.29620511 -0.27803261 783.72404367 14.44275388 819.33878136 49.25447559 C838.15454949 68.05987805 851.6807596 92.15656693 859.15128136 117.62947559 C859.50259117 118.81223072 859.50259117 118.81223072 859.86099815 120.01887989 C864.84716349 137.93439184 865.34131204 155.41560974 865.28668402 173.91294083 C865.27899556 177.65690687 865.28888432 181.40083665 865.29641402 185.14479738 C865.3071966 191.69097825 865.30695291 198.23708474 865.29927254 204.78326893 C865.2878824 214.51804038 865.2937484 224.25274959 865.30289746 233.98752068 C865.31866453 251.37833898 865.3173375 268.76912415 865.30866072 286.15994558 C865.30110466 301.37985494 865.29914832 316.59975219 865.30272865 331.81966305 C865.30295781 332.83047421 865.30318696 333.84128537 865.30342306 334.88272717 C865.30435713 338.98627537 865.30531233 343.08982357 865.30630235 347.19337176 C865.3154731 385.66415573 865.30716901 424.13491865 865.29101166 462.60569937 C865.27677663 496.7590625 865.27804855 530.91239206 865.29239464 565.06575489 C865.30847087 603.46608751 865.31482155 641.86640153 865.30555785 680.26673704 C865.30459574 684.36298215 865.30365722 688.45922726 865.30272865 692.55547237 C865.3023728 694.06829454 865.3023728 694.06829454 865.30200977 695.61167876 C865.29860234 710.81857886 865.3025789 726.02546547 865.31016731 741.2323637 C865.31875621 758.53008151 865.31657695 775.82776109 865.30032508 793.12547415 C865.29153676 802.79747308 865.2909114 812.46938917 865.3022636 822.1413859 C865.30901854 828.61208821 865.30475417 835.08272447 865.2917493 841.55341703 C865.28465281 845.23332826 865.2820887 848.9130756 865.29296724 852.59298133 C865.3442355 871.30113003 864.89727324 889.46647244 859.15128136 907.44197559 C858.89524132 908.2652837 858.63920128 909.0885918 858.37540245 909.93684864 C855.79685812 917.9856683 852.58102984 925.65348896 848.90128136 933.25447559 C848.61591515 933.86033497 848.33054893 934.46619434 848.03653526 935.09041309 C830.37472338 972.22703729 796.06237029 1001.64914703 757.52628136 1015.44197559 C741.01943895 1021.1452558 724.41526408 1024.57505987 706.89996243 1024.5117445 C705.65228729 1024.51525057 704.40461215 1024.51875665 703.11912867 1024.52236897 C699.68034267 1024.53174518 696.24166373 1024.52885318 692.80287276 1024.52381342 C689.05227316 1024.52052693 685.3016955 1024.52884577 681.55110306 1024.53563178 C674.98544107 1024.54591004 668.41980856 1024.54877936 661.85413933 1024.54671955 C652.09014292 1024.54366388 642.32617902 1024.55200613 632.56218895 1024.5624688 C614.10585117 1024.58179372 595.64952453 1024.58743648 577.19317783 1024.58858292 C562.93642719 1024.5895027 548.6796809 1024.59362298 534.42293167 1024.59998417 C530.31618419 1024.60177932 526.2094367 1024.60355895 522.10268921 1024.60533392 C521.08167553 1024.60577602 520.06066186 1024.60621812 519.00870837 1024.60667361 C490.29523693 1024.61897939 461.581767 1024.62687502 432.86829281 1024.62598705 C431.78608639 1024.6259559 430.70387998 1024.62592474 429.58887942 1024.62589264 C424.10406817 1024.62572643 418.61925692 1024.62552835 413.13444567 1024.62532322 C412.04518472 1024.62528333 410.95592376 1024.62524344 409.8336549 1024.62520234 C407.63090343 1024.62512147 405.42815196 1024.62503787 403.22540049 1024.62495156 C368.96540695 10Line truncated
|
||||
<path d="M0 0 C2.3607826 -0.00533069 4.7215618 -0.01239937 7.08233458 -0.02104706 C12.86781777 -0.03768809 18.65308544 -0.03586118 24.43857937 -0.02603391 C31.37506207 -0.01528955 38.31145513 -0.02784201 45.24792682 -0.04094901 C58.83711965 -0.06583655 72.42624267 -0.0677834 86.01545164 -0.0596749 C97.90842776 -0.05259347 109.80137684 -0.05255306 121.6943531 -0.05953789 C123.29160454 -0.06044923 124.88885599 -0.06135999 126.48610743 -0.06227018 C128.89321227 -0.06365335 131.3003171 -0.06504445 133.70742193 -0.06645631 C156.07605562 -0.07943052 178.44468029 -0.0845595 200.81331539 -0.07292271 C202.07720574 -0.07226575 202.07720574 -0.07226575 203.36662924 -0.07159552 C210.20845318 -0.06798894 217.05027701 -0.06415405 223.89210082 -0.06030459 C250.57968088 -0.04545695 277.26715859 -0.05423912 303.95472717 -0.08226013 C333.96091556 -0.11370558 363.96704337 -0.12865264 393.97324854 -0.11846012 C397.17413714 -0.11742339 400.37502576 -0.11643616 403.57591438 -0.11547661 C404.75806397 -0.11510328 404.75806397 -0.11510328 405.96409537 -0.11472241 C417.84673069 -0.11128624 429.72931241 -0.12057354 441.61193657 -0.13624763 C455.12861173 -0.15403651 468.64515667 -0.15411882 482.16182631 -0.13089598 C489.05584211 -0.11951551 495.94963463 -0.11592963 502.84363937 -0.13519669 C509.15952167 -0.15202846 515.47494573 -0.1456129 521.79079849 -0.1209799 C524.07057599 -0.11610521 526.35039063 -0.11958862 528.63013696 -0.13246734 C545.55919757 -0.22117063 559.49258132 1.40958132 573.70204163 11.5146637 C574.65143616 12.18948792 574.65143616 12.18948792 575.62001038 12.87794495 C584.56469704 19.88757798 591.37473569 31.41173592 593.70204163 42.5146637 C593.95009484 46.21967671 593.9332442 49.92717174 593.95204163 53.6396637 C593.98297913 55.13239807 593.98297913 55.13239807 594.01454163 56.6552887 C594.09018739 71.14145219 588.46971331 82.75864333 578.63954163 93.3271637 C572.7611904 98.9075711 566.35707715 102.79152692 558.70204163 105.5146637 C557.98319668 105.77360066 557.26435173 106.03253763 556.5237236 106.29932117 C545.67592079 109.56985516 534.52679546 108.91143924 523.30848694 108.85523987 C520.90407196 108.85431984 518.49965616 108.85472308 516.09524155 108.85633564 C509.68138016 108.85701034 503.26768815 108.83967715 496.85386658 108.81850433 C490.82587678 108.80136501 484.79792729 108.80061201 478.76991272 108.79847717 C461.16393343 108.7827621 443.55798536 108.74087841 425.95204163 108.7021637 C386.59954163 108.6402887 347.24704163 108.5784137 306.70204163 108.5146637 C306.70204163 227.6446637 306.70204163 346.7746637 306.70204163 469.5146637 C286.90204163 469.5146637 267.10204163 469.5146637 246.70204163 469.5146637 C246.70204163 513.4046637 246.70204163 557.2946637 246.70204163 602.5146637 C266.50204163 602.5146637 286.30204163 602.5146637 306.70204163 602.5146637 C306.79485413 611.0843512 306.79485413 611.0843512 306.88954163 619.8271637 C306.91685364 621.60647278 306.94416565 623.38578186 306.9723053 625.2190094 C307.11177013 640.67747815 304.32285969 652.54241746 293.63954163 664.2646637 C283.35164203 674.1494599 271.29383334 675.99381057 257.74501038 675.7881012 C245.19699202 675.32053069 236.72499202 668.99701836 228.38954163 660.0771637 C220.57277107 650.9239274 218.39160693 641.68285062 218.46153259 629.87820435 C218.45896932 628.28889812 218.45896932 628.28889812 218.45635426 626.6674847 C218.45306486 623.123718 218.46405419 619.58014142 218.47499084 616.03639221 C218.47555508 613.49352015 218.47523817 610.95064775 218.47410583 608.40777588 C218.47365067 602.93649447 218.47931674 597.46527407 218.49058151 591.9940052 C218.50685769 584.08354929 218.51204668 576.17311643 218.5145575 568.26264559 C218.51893128 555.42744908 218.53223178 542.59227803 218.55116272 529.75709534 C218.56952972 517.29127632 218.58368221 504.82546422 218.59217834 492.3596344 C218.59270379 491.5908286 218.59322924 490.82202281 218.59377061 490.02991987 C218.59638074 486.17292397 218.59890815 482.31592802 218.60139441 478.45893204 C218.62211705 446.47749075 218.65733395 414.49608076 218.70204163 382.5146637 C224.61760486 380.08952596 230.53376566 377.66585017 236.45030212 375.24308777 C238.45381022 374.42248424 240.45719208 373.60157242 242.46043396 372.78031921 C294.33562193 351.5146637 294.33562193 351.5146637 297.70204163 351.5146637 C297.70204163 313.8946637 297.70204163 276.2746637 297.70204163 237.5146637 C293.24704163 236.0296637 293.24704163 236.0296637 288.70204163 234.5146637 C286.21106492 233.56633242 283.72835319 232.59599737 281.25453186 231.60377502 C280.55959405 231.32587222 279.86465624 231.04796942 279.14865971 230.76164532 C276.93500856 229.87574275 274.72279495 228.98631453 272.51063538 228.09669495 C271.12991114 227.54352131 269.74909265 226.9905829 268.36817932 226.43788147 C263.29082801 224.40381573 258.21529078 222.36522413 253.13954163 220.3271637 C241.77516663 215.7690387 230.41079163 211.2109137 218.70204163 206.5146637 C218.70204163 174.1746637 218.70204163 141.8346637 218.70204163 108.5146637 C211.4392218 1Line truncated
|
||||
<path d="M0 0 C5.86817508 1.95605836 11.59073119 3.95365747 17.30737305 6.27001953 C18.09306325 6.58584142 18.87875345 6.9016633 19.68825245 7.22705555 C22.29709699 8.27645462 24.90439611 9.32963844 27.51171875 10.3828125 C29.39488199 11.14115547 31.2781448 11.89925122 33.16149902 12.65711975 C37.21264727 14.28789145 41.26312379 15.92031644 45.31307983 17.55404663 C51.7542863 20.15236465 58.19696081 22.74702807 64.63989258 25.34106445 C71.41130904 28.06755974 78.18261714 30.79432275 84.95341492 33.52235413 C108.15087431 42.86883922 131.35537268 52.19778488 154.5609436 61.52410889 C159.994401 63.70786608 165.42764165 65.89216193 170.86079502 68.07667542 C193.23239581 77.07158187 215.60890835 86.05370489 238 95 C238 116.12 238 137.24 238 159 C232.01359375 161.39185547 232.01359375 161.39185547 225.90625 163.83203125 C206.57998543 171.55973546 187.26934996 179.32631616 167.95794678 187.09106445 C161.36560101 189.74165676 154.77289802 192.39135988 148.18017578 195.04101562 C126.79552102 203.63604381 105.41240644 212.23486217 84.03399658 220.84541321 C75.73587703 224.18760199 67.43708216 227.52811242 59.13812637 230.86822414 C52.33470621 233.60660835 45.53222385 236.34730609 38.73039818 239.08964825 C34.51543173 240.78839672 30.29959748 242.48498283 26.08351517 244.1809597 C24.12464123 244.96946815 22.16613491 245.75889055 20.20801926 246.54928017 C17.53921709 247.62640467 14.86914587 248.70032007 12.19873047 249.7734375 C11.02965778 250.24663689 11.02965778 250.24663689 9.83696747 250.72939587 C6.56202144 252.04197447 3.43106937 253.14223266 0 254 C0 231.56 0 209.12 0 186 C21.85641702 177.6267728 43.73124762 169.30784563 65.63814926 161.06789398 C71.62769516 158.81489337 77.61678737 156.56068672 83.60580635 154.30628586 C85.09797285 153.74460399 86.5901539 153.18296077 88.08234978 152.62135696 C97.85972778 148.94125789 107.63197621 145.24805417 117.3984375 141.5390625 C119.52367608 140.73273275 121.64892001 139.92641707 123.77416992 139.12011719 C127.62723328 137.65810939 131.4786996 136.19199339 135.3293457 134.72363281 C137.01507528 134.08382248 138.70086226 133.44416335 140.38671875 132.8046875 C141.51894363 132.37079208 141.51894363 132.37079208 142.67404175 131.9281311 C147.77255889 130 147.77255889 130 150 130 C149.67 128.02 149.34 126.04 149 124 C147.88878784 123.58995728 147.88878784 123.58995728 146.75512695 123.17163086 C117.43275623 112.3398187 88.19328622 101.28796181 58.94955444 90.24617195 C50.58387921 87.08758433 42.21738212 83.93117504 33.85093689 80.77462769 C22.56697288 76.5172614 11.28352836 72.25852172 0 68 C0 45.56 0 23.12 0 0 Z " fill="#F39044" transform="translate(272,342)"/>
|
||||
<path d="M0 0 C81.84 0 163.68 0 248 0 C248 19.47 248 38.94 248 59 C166.16 59 84.32 59 0 59 C0 39.53 0 20.06 0 0 Z " fill="#F39044" transform="translate(533,681)"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 17 KiB |
@@ -22,7 +22,7 @@ services:
|
||||
volumes:
|
||||
- firefly-upload:/var/www/html/storage/upload
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://127.0.0.1:8080"]
|
||||
test: ["CMD", "curl", "-f", "http://127.0.0.1:8080/health"]
|
||||
interval: 5s
|
||||
timeout: 20s
|
||||
retries: 10
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
services:
|
||||
forgejo:
|
||||
image: codeberg.org/forgejo/forgejo:8
|
||||
image: codeberg.org/forgejo/forgejo:15
|
||||
environment:
|
||||
- SERVICE_URL_FORGEJO_3000
|
||||
- FORGEJO__server__ROOT_URL=${SERVICE_URL_FORGEJO}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
services:
|
||||
forgejo:
|
||||
image: codeberg.org/forgejo/forgejo:8
|
||||
image: codeberg.org/forgejo/forgejo:15
|
||||
environment:
|
||||
- SERVICE_URL_FORGEJO_3000
|
||||
- FORGEJO__server__ROOT_URL=${SERVICE_URL_FORGEJO}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
services:
|
||||
forgejo:
|
||||
image: codeberg.org/forgejo/forgejo:8
|
||||
image: codeberg.org/forgejo/forgejo:15
|
||||
environment:
|
||||
- SERVICE_URL_FORGEJO_3000
|
||||
- FORGEJO__server__ROOT_URL=${SERVICE_URL_FORGEJO}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
services:
|
||||
forgejo:
|
||||
image: codeberg.org/forgejo/forgejo:8
|
||||
image: codeberg.org/forgejo/forgejo:15
|
||||
environment:
|
||||
- SERVICE_URL_FORGEJO_3000
|
||||
- FORGEJO__server__ROOT_URL=${SERVICE_URL_FORGEJO}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
services:
|
||||
forgejo:
|
||||
image: codeberg.org/forgejo/forgejo:8
|
||||
image: codeberg.org/forgejo/forgejo:15
|
||||
environment:
|
||||
- SERVICE_URL_FORGEJO_3000
|
||||
- FORGEJO__server__ROOT_URL=${SERVICE_URL_FORGEJO}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
services:
|
||||
forgejo:
|
||||
image: codeberg.org/forgejo/forgejo:8
|
||||
image: codeberg.org/forgejo/forgejo:15
|
||||
environment:
|
||||
- SERVICE_URL_FORGEJO_3000
|
||||
- FORGEJO__server__ROOT_URL=${SERVICE_URL_FORGEJO}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
services:
|
||||
forgejo:
|
||||
image: codeberg.org/forgejo/forgejo:8
|
||||
image: codeberg.org/forgejo/forgejo:15
|
||||
environment:
|
||||
- SERVICE_URL_FORGEJO_3000
|
||||
- FORGEJO__server__ROOT_URL=${SERVICE_URL_FORGEJO}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
services:
|
||||
forgejo:
|
||||
image: codeberg.org/forgejo/forgejo:8
|
||||
image: codeberg.org/forgejo/forgejo:15
|
||||
environment:
|
||||
- SERVICE_URL_FORGEJO_3000
|
||||
- FORGEJO__server__ROOT_URL=${SERVICE_URL_FORGEJO}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
# documentation: https://docs.influxdata.com/influxdb/
|
||||
# slogan: Open source time series database for metrics, events, and analytics.
|
||||
# category: databases
|
||||
# tags: influxdb,time series,metrics,iot,monitoring,telegraf
|
||||
# logo: svgs/influxdb.svg
|
||||
# port: 8086
|
||||
|
||||
services:
|
||||
influxdb:
|
||||
image: influxdb:2.7-alpine
|
||||
environment:
|
||||
- SERVICE_URL_INFLUXDB_8086
|
||||
- INFLUXDB_HTTP_BIND_ADDRESS=:8086
|
||||
- INFLUXDB_INIT_MODE=setup
|
||||
- INFLUXDB_INIT_USERNAME=$SERVICE_USER_INFLUXDB
|
||||
- INFLUXDB_INIT_PASSWORD=$SERVICE_PASSWORD_INFLUXDB
|
||||
- INFLUXDB_INIT_ORG=$SERVICE_ORG_INFLUXDB
|
||||
- INFLUXDB_INIT_BUCKET=$SERVICE_BUCKET_INFLUXDB
|
||||
- INFLUXDB_INIT_RETENTION=0
|
||||
- INFLUXDB_INIT_ADMIN_TOKEN=$SERVICE_PASSWORD_INFLUXDB_TOKEN
|
||||
volumes:
|
||||
- influxdb-data:/var/lib/influxdb2
|
||||
- influxdb-config:/etc/influxdb2
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD
|
||||
- influx
|
||||
- ping
|
||||
- --host
|
||||
- http://127.0.0.1:8086
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 20s
|
||||
@@ -40,6 +40,7 @@ services:
|
||||
content: |
|
||||
general_settings:
|
||||
proxy_batch_write_at: 60
|
||||
store_prompts_in_spend_logs: false
|
||||
|
||||
router_settings:
|
||||
redis_host: os.environ/REDIS_HOST
|
||||
@@ -50,15 +51,15 @@ services:
|
||||
litellm_settings:
|
||||
set_verbose: false
|
||||
json_logs: true
|
||||
log_raw_request_response: true
|
||||
log_raw_request_response: false
|
||||
# turn_off_message_logging: false
|
||||
# redact_user_api_key_info: false
|
||||
service_callback: ["prometheus_system"]
|
||||
drop_params: true
|
||||
# max_budget: 100
|
||||
# budget_duration: 30d
|
||||
num_retries: 3
|
||||
request_timeout: 600
|
||||
num_retries: 1
|
||||
request_timeout: 120
|
||||
telemetry: false
|
||||
cache: true
|
||||
cache_params:
|
||||
@@ -131,17 +132,21 @@ services:
|
||||
- CMD
|
||||
- python
|
||||
- "-c"
|
||||
- "import requests as r;r.get('http://127.0.0.1:4000/health/liveliness').raise_for_status()"
|
||||
interval: 5s
|
||||
- "import urllib.request;urllib.request.urlopen('http://127.0.0.1:4000/health/liveliness',timeout=5)"
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
command:
|
||||
- "--config"
|
||||
- /app/config.yaml
|
||||
- "--port"
|
||||
- "4000"
|
||||
- "--num_workers"
|
||||
- "8"
|
||||
- "2"
|
||||
- "--run_gunicorn"
|
||||
- "--max_requests_before_restart"
|
||||
- "1000"
|
||||
postgres:
|
||||
image: "postgres:16-alpine"
|
||||
environment:
|
||||
|
||||
@@ -47,10 +47,15 @@ x-shared-env: &shared-api-env
|
||||
PHP_MAX_EXECUTION_TIME: "600"
|
||||
PHP_UPLOAD_MAX_FILESIZE: "64M"
|
||||
PHP_POST_MAX_SIZE: "64M"
|
||||
# Frontend settings
|
||||
FRONT_URL: ${SERVICE_URL_NGINX}
|
||||
FRONT_API_SECRET: ${SERVICE_PASSWORD_FRONTAPISECRET}
|
||||
PUBLIC_UPLOADS_RATE_LIMIT_PER_MINUTE: ${PUBLIC_UPLOADS_RATE_LIMIT_PER_MINUTE:-30}
|
||||
PUBLIC_UPLOADS_RATE_LIMIT_PER_HOUR: ${PUBLIC_UPLOADS_RATE_LIMIT_PER_HOUR:-300}
|
||||
|
||||
services:
|
||||
opnform-api:
|
||||
image: jhumanj/opnform-api:1.12.1
|
||||
image: jhumanj/opnform-api:2.2.4
|
||||
volumes:
|
||||
- api-storage:/usr/share/nginx/html/storage
|
||||
environment:
|
||||
@@ -58,7 +63,7 @@ services:
|
||||
<<: *shared-api-env
|
||||
JWT_TTL: ${JWT_TTL:-1440}
|
||||
JWT_SECRET: ${SERVICE_PASSWORD_JWTSECRET}
|
||||
JWT_SKIP_IP_UA_VALIDATION: ${JWT_SKIP_IP_UA_VALIDATION:-true}
|
||||
JWT_SKIP_IP_UA_VALIDATION: ${JWT_SKIP_IP_UA_VALIDATION:-false}
|
||||
H_CAPTCHA_SITE_KEY: ${H_CAPTCHA_SITE_KEY}
|
||||
H_CAPTCHA_SECRET_KEY: ${H_CAPTCHA_SECRET_KEY}
|
||||
RE_CAPTCHA_SITE_KEY: ${RE_CAPTCHA_SITE_KEY}
|
||||
@@ -77,7 +82,7 @@ services:
|
||||
start_period: 60s
|
||||
|
||||
api-worker:
|
||||
image: jhumanj/opnform-api:1.12.1
|
||||
image: jhumanj/opnform-api:2.2.4
|
||||
volumes:
|
||||
- api-storage:/usr/share/nginx/html/storage
|
||||
environment:
|
||||
@@ -98,7 +103,7 @@ services:
|
||||
start_period: 30s
|
||||
|
||||
api-scheduler:
|
||||
image: jhumanj/opnform-api:1.12.1
|
||||
image: jhumanj/opnform-api:2.2.4
|
||||
volumes:
|
||||
- api-storage:/usr/share/nginx/html/storage
|
||||
environment:
|
||||
@@ -122,7 +127,7 @@ services:
|
||||
start_period: 70s # Allow time for first scheduled run and cache write
|
||||
|
||||
opnform-ui:
|
||||
image: jhumanj/opnform-client:1.12.1
|
||||
image: jhumanj/opnform-client:2.2.4
|
||||
environment:
|
||||
- NUXT_PUBLIC_APP_URL=/
|
||||
- NUXT_PUBLIC_API_BASE=/api
|
||||
@@ -130,6 +135,8 @@ services:
|
||||
- NUXT_PUBLIC_ENV=production
|
||||
- NUXT_PUBLIC_H_CAPTCHA_SITE_KEY=${H_CAPTCHA_SITE_KEY}
|
||||
- NUXT_PUBLIC_RE_CAPTCHA_SITE_KEY=${RE_CAPTCHA_SITE_KEY}
|
||||
- NUXT_API_SECRET=${SERVICE_PASSWORD_FRONTAPISECRET}
|
||||
- NUXT_PUBLIC_LICENSE_API_ENDPOINT=${NUXT_PUBLIC_LICENSE_API_ENDPOINT:-https://api.opnform.com}
|
||||
healthcheck:
|
||||
test:
|
||||
["CMD-SHELL", "wget --spider -q http://opnform-ui:3000/login || exit 1"]
|
||||
@@ -142,9 +149,9 @@ services:
|
||||
condition: service_healthy
|
||||
|
||||
postgresql:
|
||||
image: postgres:16
|
||||
image: postgres:18
|
||||
volumes:
|
||||
- opnform-postgresql-data:/var/lib/postgresql/data
|
||||
- opnform-postgresql-data:/var/lib/postgresql
|
||||
environment:
|
||||
- POSTGRES_USER=${SERVICE_USER_POSTGRESQL}
|
||||
- POSTGRES_PASSWORD=${SERVICE_PASSWORD_POSTGRESQL}
|
||||
@@ -171,7 +178,7 @@ services:
|
||||
# The nginx reverse proxy.
|
||||
# used for reverse proxying the API service and Web service.
|
||||
nginx:
|
||||
image: nginx:1.29.2
|
||||
image: nginx:1.31.3
|
||||
environment:
|
||||
- SERVICE_URL_NGINX
|
||||
volumes:
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
services:
|
||||
seaweedfs-master:
|
||||
image: chrislusf/seaweedfs:4.13
|
||||
image: chrislusf/seaweedfs:4.41
|
||||
environment:
|
||||
- SERVICE_URL_S3_8333
|
||||
- AWS_ACCESS_KEY_ID=${SERVICE_USER_S3}
|
||||
@@ -61,7 +61,7 @@ services:
|
||||
retries: 10
|
||||
|
||||
seaweedfs-admin:
|
||||
image: chrislusf/seaweedfs:4.13
|
||||
image: chrislusf/seaweedfs:4.41
|
||||
environment:
|
||||
- SERVICE_URL_ADMIN_23646
|
||||
- SEAWEED_USER_ADMIN=${SERVICE_USER_ADMIN}
|
||||
|
||||
@@ -7,26 +7,42 @@
|
||||
|
||||
services:
|
||||
sparkyfitness-frontend:
|
||||
image: 'codewithcj/sparkyfitness:v0.15.7.3' # Released on Oct 18, 2025
|
||||
image: 'codewithcj/sparkyfitness:v1.6.1'
|
||||
environment:
|
||||
- SERVICE_URL_SPARKYFITNESS_80
|
||||
- 'SPARKY_FITNESS_FRONTEND_URL=${SERVICE_URL_SPARKYFITNESS_80}'
|
||||
- SPARKY_FITNESS_SERVER_HOST=sparkyfitness-server
|
||||
- SPARKY_FITNESS_SERVER_PORT=3010
|
||||
depends_on:
|
||||
- sparkyfitness-server
|
||||
|
||||
sparkyfitness-server:
|
||||
image: 'codewithcj/sparkyfitness_server:v0.15.7.3' # Released on Oct 18, 2025
|
||||
image: 'codewithcj/sparkyfitness_server:v1.6.1'
|
||||
environment:
|
||||
- 'SPARKY_FITNESS_LOG_LEVEL=${SPARKY_FITNESS_LOG_LEVEL:-info}'
|
||||
- 'NODE_ENV=${NODE_ENV:-production}'
|
||||
- 'TZ=${TZ:-Etc/UTC}'
|
||||
# Database — superuser (used for migrations only)
|
||||
- 'SPARKY_FITNESS_DB_USER=${SERVICE_USER_POSTGRES}'
|
||||
- SPARKY_FITNESS_DB_HOST=sparkyfitness-db
|
||||
- 'SPARKY_FITNESS_DB_NAME=${SPARKY_FITNESS_DB_NAME:-sparkyfitness}'
|
||||
- 'SPARKY_FITNESS_DB_PASSWORD=${SERVICE_PASSWORD_POSTGRES}'
|
||||
- 'SPARKY_FITNESS_DB_PORT=${SPARKY_FITNESS_DB_PORT:-5432}'
|
||||
# Database — application user (unprivileged, used at runtime)
|
||||
- 'SPARKY_FITNESS_APP_DB_USER=${SPARKY_FITNESS_APP_DB_USER:-sparkyapp}'
|
||||
- 'SPARKY_FITNESS_APP_DB_PASSWORD=${SERVICE_PASSWORD_64_APPDBPASSWORD}'
|
||||
# Secrets
|
||||
- 'SPARKY_FITNESS_API_ENCRYPTION_KEY=${SERVICE_PASSWORD_64_SERVERAPIENCRYPTIONKEY}'
|
||||
- 'JWT_SECRET=${SERVICE_PASSWORD_64_SERVERJWTSECRET}'
|
||||
- 'BETTER_AUTH_SECRET=${SERVICE_PASSWORD_64_BETTERAUTHSECRET}'
|
||||
# CORS / trusted origins
|
||||
- 'SPARKY_FITNESS_FRONTEND_URL=${SERVICE_URL_SPARKYFITNESS_80}'
|
||||
- 'ALLOW_PRIVATE_NETWORK_CORS=${ALLOW_PRIVATE_NETWORK_CORS:-false}'
|
||||
- 'SPARKY_FITNESS_EXTRA_TRUSTED_ORIGINS=${SPARKY_FITNESS_EXTRA_TRUSTED_ORIGINS:-}'
|
||||
# Auth / signup
|
||||
- 'SPARKY_FITNESS_DISABLE_SIGNUP=${SPARKY_FITNESS_DISABLE_SIGNUP:-false}'
|
||||
- 'SPARKY_FITNESS_FORCE_EMAIL_LOGIN=${SPARKY_FITNESS_FORCE_EMAIL_LOGIN:-true}'
|
||||
- 'SPARKY_FITNESS_ADMIN_EMAIL=${SPARKY_FITNESS_ADMIN_EMAIL:-admin@example.com}'
|
||||
# Email (optional)
|
||||
- 'SPARKY_FITNESS_EMAIL_HOST=${SPARKY_FITNESS_EMAIL_HOST:-smtp.gmail.com}'
|
||||
- 'SPARKY_FITNESS_EMAIL_PORT=${SPARKY_FITNESS_EMAIL_PORT:-587}'
|
||||
- 'SPARKY_FITNESS_EMAIL_SECURE=${SPARKY_FITNESS_EMAIL_SECURE:-false}'
|
||||
@@ -40,7 +56,7 @@ services:
|
||||
- 'sparkyfitness-server-uploads:/app/SparkyFitnessServer/uploads'
|
||||
|
||||
sparkyfitness-db:
|
||||
image: 'postgres:15-alpine'
|
||||
image: 'postgres:18-alpine'
|
||||
environment:
|
||||
- 'POSTGRES_DB=${SPARKY_FITNESS_DB_NAME:-sparkyfitness}'
|
||||
- 'POSTGRES_USER=${SERVICE_USER_POSTGRES}'
|
||||
@@ -52,5 +68,5 @@ services:
|
||||
timeout: 20s
|
||||
retries: 10
|
||||
volumes:
|
||||
- 'sparkyfitness-db-postgresql:/var/lib/postgresql/data'
|
||||
- 'sparkyfitness-db-postgresql:/var/lib/postgresql'
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
# documentation: https://stalw.art/docs/
|
||||
# slogan: Modern mail server platform
|
||||
# category: Mail
|
||||
# tags: mail,smtp,imap,pop3,jmap,email,sieve,messaging
|
||||
# logo: svgs/stalwart.svg
|
||||
# port: 8080
|
||||
|
||||
services:
|
||||
stalwart:
|
||||
image: 'stalwartlabs/stalwart:v0.16.13'
|
||||
environment:
|
||||
- SERVICE_URL_STALWART_8080
|
||||
expose:
|
||||
- '8080'
|
||||
ports:
|
||||
- '25:25'
|
||||
- '465:465'
|
||||
- '587:587'
|
||||
- '993:993'
|
||||
- '995:995'
|
||||
- '143:143'
|
||||
- '110:110'
|
||||
- '4190:4190'
|
||||
volumes:
|
||||
- 'stalwart-mail:/etc/stalwart'
|
||||
- 'stalwart-data:/var/lib/stalwart'
|
||||
- '/etc/localtime:/etc/localtime:ro'
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8080/"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
@@ -0,0 +1,23 @@
|
||||
# documentation: https://docs.termix.site/install/server/docker
|
||||
# slogan: All-in-One SSH & Remote Desktop management app.
|
||||
# category: developer-tools
|
||||
# tags: ssh,terminal,remote-desktop,rdp,vnc,server-management,remote-access
|
||||
# logo: svgs/termix.svg
|
||||
# port: 8080
|
||||
|
||||
services:
|
||||
termix:
|
||||
image: ghcr.io/lukegus/termix:2.6.1
|
||||
environment:
|
||||
- SERVICE_URL_TERMIX_8080
|
||||
- PORT=8080
|
||||
- LOG_LEVEL=${LOG_LEVEL:-info}
|
||||
- GUACD_HOST=guacd
|
||||
- GUACD_RECORDING_PATH=/termix-data/session_recordings/guacamole
|
||||
depends_on:
|
||||
- guacd
|
||||
volumes:
|
||||
- termix-data:/app/data
|
||||
|
||||
guacd:
|
||||
image: guacamole/guacd:1.6.0
|
||||
@@ -1465,7 +1465,7 @@
|
||||
"firefly": {
|
||||
"documentation": "https://firefly-iii.org?utm_source=coolify.io",
|
||||
"slogan": "A personal finances manager that can help you save money.",
|
||||
"compose": "c2VydmljZXM6CiAgZmlyZWZseToKICAgIGltYWdlOiAnZmlyZWZseWlpaS9jb3JlOmxhdGVzdCcKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfVVJMX0ZJUkVGTFlfODA4MAogICAgICAtIEFQUF9LRVk9JFNFUlZJQ0VfQkFTRTY0X0FQUEtFWQogICAgICAtIERCX0hPU1Q9bXlzcWwKICAgICAgLSBEQl9QT1JUPTMzMDYKICAgICAgLSBEQl9DT05ORUNUSU9OPW15c3FsCiAgICAgIC0gJ0RCX0RBVEFCQVNFPSR7TVlTUUxfREFUQUJBU0U6LWZpcmVmbHl9JwogICAgICAtIERCX1VTRVJOQU1FPSRTRVJWSUNFX1VTRVJfTVlTUUwKICAgICAgLSBEQl9QQVNTV09SRD0kU0VSVklDRV9QQVNTV09SRF9NWVNRTAogICAgICAtIFNUQVRJQ19DUk9OX1RPS0VOPSRTRVJWSUNFX0JBU0U2NF9DUk9OVE9LRU4KICAgICAgLSAnVFJVU1RFRF9QUk9YSUVTPSonCiAgICB2b2x1bWVzOgogICAgICAtICdmaXJlZmx5LXVwbG9hZDovdmFyL3d3dy9odG1sL3N0b3JhZ2UvdXBsb2FkJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIGN1cmwKICAgICAgICAtICctZicKICAgICAgICAtICdodHRwOi8vMTI3LjAuMC4xOjgwODAnCiAgICAgIGludGVydmFsOiA1cwogICAgICB0aW1lb3V0OiAyMHMKICAgICAgcmV0cmllczogMTAKICAgIGRlcGVuZHNfb246CiAgICAgIG15c3FsOgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9oZWFsdGh5CiAgbXlzcWw6CiAgICBpbWFnZTogJ21hcmlhZGI6MTEnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSAnTVlTUUxfVVNFUj0ke1NFUlZJQ0VfVVNFUl9NWVNRTH0nCiAgICAgIC0gJ01ZU1FMX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9NWVNRTH0nCiAgICAgIC0gJ01ZU1FMX0RBVEFCQVNFPSR7TVlTUUxfREFUQUJBU0U6LWZpcmVmbHl9JwogICAgICAtICdNWVNRTF9ST09UX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9NWVNRTFJPT1R9JwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIG1hcmlhZGItYWRtaW4KICAgICAgICAtIHBpbmcKICAgICAgICAtICctaCcKICAgICAgICAtIDEyNy4wLjAuMQogICAgICAgIC0gJy11cm9vdCcKICAgICAgICAtICctcCR7U0VSVklDRV9QQVNTV09SRF9NWVNRTFJPT1R9JwogICAgICBpbnRlcnZhbDogNXMKICAgICAgdGltZW91dDogMjBzCiAgICAgIHJldHJpZXM6IDEwCiAgICB2b2x1bWVzOgogICAgICAtICdmaXJlZmx5LW15c3FsLWRhdGE6L3Zhci9saWIvbXlzcWwnCiAgY3JvbjoKICAgIGltYWdlOiBhbHBpbmUKICAgIGVudHJ5cG9pbnQ6CiAgICAgIC0gL2VudHJ5cG9pbnQuc2gKICAgIHZvbHVtZXM6CiAgICAgIC0KICAgICAgICB0eXBlOiBiaW5kCiAgICAgICAgc291cmNlOiAuL2VudHJ5cG9pbnQuc2gKICAgICAgICB0YXJnZXQ6IC9lbnRyeXBvaW50LnNoCiAgICAgICAgY29udGVudDogIiMhL2Jpbi9zaFxuIyBTdWJzdGl0dXRlIHRoZSBlbnZpcm9ubWVudCB2YXJpYWJsZSBpbnRvIHRoZSBjcm9uIGNvbW1hbmRcbkNST05fQ09NTUFORD1cIjAgMyAqICogKiB3Z2V0IC1xTy0gaHR0cDovL2ZpcmVmbHk6ODA4MC9hcGkvdjEvY3Jvbi8ke1NUQVRJQ19DUk9OX1RPS0VOfVwiXG4jIEFkZCB0aGUgY3JvbiBjb21tYW5kIHRvIHRoZSBjcm9udGFiXG5lY2hvIFwiJENST05fQ09NTUFORFwiIHwgY3JvbnRhYiAtXG4jIFN0YXJ0IHRoZSBjcm9uIGRhZW1vbiBpbiB0aGUgZm9yZWdyb3VuZCB3aXRoIGxvZ2dpbmcgdG8gc3Rkb3V0XG5jcm9uZCAtZiAtTCAvZGV2L3N0ZG91dCIKICAgIGVudmlyb25tZW50OgogICAgICAtIFNUQVRJQ19DUk9OX1RPS0VOPSRTRVJWSUNFX0JBU0U2NF9DUk9OVE9LRU4KICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ELVNIRUxMCiAgICAgICAgLSAnbHMgL2VudHJ5cG9pbnQuc2ggfHwgZXhpdCAxJwogICAgICBpbnRlcnZhbDogMzBzCiAgICAgIHRpbWVvdXQ6IDEwcwogICAgICByZXRyaWVzOiAzCiAgICAgIHN0YXJ0X3BlcmlvZDogNDBzCg==",
|
||||
"compose": "c2VydmljZXM6CiAgZmlyZWZseToKICAgIGltYWdlOiAnZmlyZWZseWlpaS9jb3JlOmxhdGVzdCcKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfVVJMX0ZJUkVGTFlfODA4MAogICAgICAtIEFQUF9LRVk9JFNFUlZJQ0VfQkFTRTY0X0FQUEtFWQogICAgICAtIERCX0hPU1Q9bXlzcWwKICAgICAgLSBEQl9QT1JUPTMzMDYKICAgICAgLSBEQl9DT05ORUNUSU9OPW15c3FsCiAgICAgIC0gJ0RCX0RBVEFCQVNFPSR7TVlTUUxfREFUQUJBU0U6LWZpcmVmbHl9JwogICAgICAtIERCX1VTRVJOQU1FPSRTRVJWSUNFX1VTRVJfTVlTUUwKICAgICAgLSBEQl9QQVNTV09SRD0kU0VSVklDRV9QQVNTV09SRF9NWVNRTAogICAgICAtIFNUQVRJQ19DUk9OX1RPS0VOPSRTRVJWSUNFX0JBU0U2NF9DUk9OVE9LRU4KICAgICAgLSAnVFJVU1RFRF9QUk9YSUVTPSonCiAgICB2b2x1bWVzOgogICAgICAtICdmaXJlZmx5LXVwbG9hZDovdmFyL3d3dy9odG1sL3N0b3JhZ2UvdXBsb2FkJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIGN1cmwKICAgICAgICAtICctZicKICAgICAgICAtICdodHRwOi8vMTI3LjAuMC4xOjgwODAvaGVhbHRoJwogICAgICBpbnRlcnZhbDogNXMKICAgICAgdGltZW91dDogMjBzCiAgICAgIHJldHJpZXM6IDEwCiAgICBkZXBlbmRzX29uOgogICAgICBteXNxbDoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogIG15c3FsOgogICAgaW1hZ2U6ICdtYXJpYWRiOjExJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ01ZU1FMX1VTRVI9JHtTRVJWSUNFX1VTRVJfTVlTUUx9JwogICAgICAtICdNWVNRTF9QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfTVlTUUx9JwogICAgICAtICdNWVNRTF9EQVRBQkFTRT0ke01ZU1FMX0RBVEFCQVNFOi1maXJlZmx5fScKICAgICAgLSAnTVlTUUxfUk9PVF9QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfTVlTUUxST09UfScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSBtYXJpYWRiLWFkbWluCiAgICAgICAgLSBwaW5nCiAgICAgICAgLSAnLWgnCiAgICAgICAgLSAxMjcuMC4wLjEKICAgICAgICAtICctdXJvb3QnCiAgICAgICAgLSAnLXAke1NFUlZJQ0VfUEFTU1dPUkRfTVlTUUxST09UfScKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHRpbWVvdXQ6IDIwcwogICAgICByZXRyaWVzOiAxMAogICAgdm9sdW1lczoKICAgICAgLSAnZmlyZWZseS1teXNxbC1kYXRhOi92YXIvbGliL215c3FsJwogIGNyb246CiAgICBpbWFnZTogYWxwaW5lCiAgICBlbnRyeXBvaW50OgogICAgICAtIC9lbnRyeXBvaW50LnNoCiAgICB2b2x1bWVzOgogICAgICAtCiAgICAgICAgdHlwZTogYmluZAogICAgICAgIHNvdXJjZTogLi9lbnRyeXBvaW50LnNoCiAgICAgICAgdGFyZ2V0OiAvZW50cnlwb2ludC5zaAogICAgICAgIGNvbnRlbnQ6ICIjIS9iaW4vc2hcbiMgU3Vic3RpdHV0ZSB0aGUgZW52aXJvbm1lbnQgdmFyaWFibGUgaW50byB0aGUgY3JvbiBjb21tYW5kXG5DUk9OX0NPTU1BTkQ9XCIwIDMgKiAqICogd2dldCAtcU8tIGh0dHA6Ly9maXJlZmx5OjgwODAvYXBpL3YxL2Nyb24vJHtTVEFUSUNfQ1JPTl9UT0tFTn1cIlxuIyBBZGQgdGhlIGNyb24gY29tbWFuZCB0byB0aGUgY3JvbnRhYlxuZWNobyBcIiRDUk9OX0NPTU1BTkRcIiB8IGNyb250YWIgLVxuIyBTdGFydCB0aGUgY3JvbiBkYWVtb24gaW4gdGhlIGZvcmVncm91bmQgd2l0aCBsb2dnaW5nIHRvIHN0ZG91dFxuY3JvbmQgLWYgLUwgL2Rldi9zdGRvdXQiCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTVEFUSUNfQ1JPTl9UT0tFTj0kU0VSVklDRV9CQVNFNjRfQ1JPTlRPS0VOCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gJ2xzIC9lbnRyeXBvaW50LnNoIHx8IGV4aXQgMScKICAgICAgaW50ZXJ2YWw6IDMwcwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgcmV0cmllczogMwogICAgICBzdGFydF9wZXJpb2Q6IDQwcwo=",
|
||||
"tags": [
|
||||
"finance",
|
||||
"money",
|
||||
@@ -1475,7 +1475,7 @@
|
||||
"category": "finance",
|
||||
"logo": "svgs/firefly.svg",
|
||||
"minversion": "0.0.0",
|
||||
"template_last_updated_at": "2026-04-06T11:35:16-05:00",
|
||||
"template_last_updated_at": "2026-08-10T10:43:04+02:00",
|
||||
"port": "8080"
|
||||
},
|
||||
"firefox": {
|
||||
@@ -1583,7 +1583,7 @@
|
||||
"forgejo-with-mariadb": {
|
||||
"documentation": "https://forgejo.org/docs?utm_source=coolify.io",
|
||||
"slogan": "Forgejo is a self-hosted lightweight software forge. Easy to install and low maintenance, it just does the job.",
|
||||
"compose": "c2VydmljZXM6CiAgZm9yZ2VqbzoKICAgIGltYWdlOiAnY29kZWJlcmcub3JnL2Zvcmdlam8vZm9yZ2Vqbzo4JwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9VUkxfRk9SR0VKT18zMDAwCiAgICAgIC0gJ0ZPUkdFSk9fX3NlcnZlcl9fUk9PVF9VUkw9JHtTRVJWSUNFX1VSTF9GT1JHRUpPfScKICAgICAgLSAnRk9SR0VKT19fbWlncmF0aW9uc19fQUxMT1dFRF9ET01BSU5TPSR7Rk9SR0VKT19fbWlncmF0aW9uc19fQUxMT1dFRF9ET01BSU5TfScKICAgICAgLSAnRk9SR0VKT19fbWlncmF0aW9uc19fQUxMT1dfTE9DQUxORVRXT1JLUz0ke0ZPUkdFSk9fX21pZ3JhdGlvbnNfX0FMTE9XX0xPQ0FMTkVUV09SS1MtZmFsc2V9JwogICAgICAtIFVTRVJfVUlEPTEwMDAKICAgICAgLSBVU0VSX0dJRD0xMDAwCiAgICAgIC0gRk9SR0VKT19fZGF0YWJhc2VfX0RCX1RZUEU9bXlzcWwKICAgICAgLSBGT1JHRUpPX19kYXRhYmFzZV9fSE9TVD1tYXJpYWRiCiAgICAgIC0gJ0ZPUkdFSk9fX2RhdGFiYXNlX19OQU1FPSR7TVlTUUxfREFUQUJBU0UtZm9yZ2Vqb30nCiAgICAgIC0gRk9SR0VKT19fZGF0YWJhc2VfX1VTRVI9JFNFUlZJQ0VfVVNFUl9NWVNRTAogICAgICAtIEZPUkdFSk9fX2RhdGFiYXNlX19QQVNTV0Q9JFNFUlZJQ0VfUEFTU1dPUkRfTVlTUUwKICAgIHZvbHVtZXM6CiAgICAgIC0gJ2Zvcmdlam8tZGF0YTovZGF0YScKICAgICAgLSAnZm9yZ2Vqby10aW1lem9uZTovZXRjL3RpbWV6b25lOnJvJwogICAgICAtICdmb3JnZWpvLWxvY2FsdGltZTovZXRjL2xvY2FsdGltZTpybycKICAgIHBvcnRzOgogICAgICAtICcyMjIyMjoyMicKICAgIGRlcGVuZHNfb246CiAgICAgIG1hcmlhZGI6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSBjdXJsCiAgICAgICAgLSAnLWYnCiAgICAgICAgLSAnaHR0cDovLzEyNy4wLjAuMTozMDAwJwogICAgICBpbnRlcnZhbDogMnMKICAgICAgdGltZW91dDogMTBzCiAgICAgIHJldHJpZXM6IDE1CiAgbWFyaWFkYjoKICAgIGltYWdlOiAnbWFyaWFkYjoxMScKICAgIHZvbHVtZXM6CiAgICAgIC0gJ2Zvcmdlam8tbWFyaWFkYi1kYXRhOi92YXIvbGliL215c3FsJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ01ZU1FMX1VTRVI9JHtTRVJWSUNFX1VTRVJfTVlTUUx9JwogICAgICAtICdNWVNRTF9QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfTVlTUUx9JwogICAgICAtICdNWVNRTF9EQVRBQkFTRT0ke01ZU1FMX0RBVEFCQVNFfScKICAgICAgLSAnTVlTUUxfUk9PVF9QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfTVlTUUxST09UfScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSBoZWFsdGhjaGVjay5zaAogICAgICAgIC0gJy0tY29ubmVjdCcKICAgICAgICAtICctLWlubm9kYl9pbml0aWFsaXplZCcKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHRpbWVvdXQ6IDIwcwogICAgICByZXRyaWVzOiAxMAo=",
|
||||
"compose": "c2VydmljZXM6CiAgZm9yZ2VqbzoKICAgIGltYWdlOiAnY29kZWJlcmcub3JnL2Zvcmdlam8vZm9yZ2VqbzoxNScKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfVVJMX0ZPUkdFSk9fMzAwMAogICAgICAtICdGT1JHRUpPX19zZXJ2ZXJfX1JPT1RfVVJMPSR7U0VSVklDRV9VUkxfRk9SR0VKT30nCiAgICAgIC0gJ0ZPUkdFSk9fX21pZ3JhdGlvbnNfX0FMTE9XRURfRE9NQUlOUz0ke0ZPUkdFSk9fX21pZ3JhdGlvbnNfX0FMTE9XRURfRE9NQUlOU30nCiAgICAgIC0gJ0ZPUkdFSk9fX21pZ3JhdGlvbnNfX0FMTE9XX0xPQ0FMTkVUV09SS1M9JHtGT1JHRUpPX19taWdyYXRpb25zX19BTExPV19MT0NBTE5FVFdPUktTLWZhbHNlfScKICAgICAgLSBVU0VSX1VJRD0xMDAwCiAgICAgIC0gVVNFUl9HSUQ9MTAwMAogICAgICAtIEZPUkdFSk9fX2RhdGFiYXNlX19EQl9UWVBFPW15c3FsCiAgICAgIC0gRk9SR0VKT19fZGF0YWJhc2VfX0hPU1Q9bWFyaWFkYgogICAgICAtICdGT1JHRUpPX19kYXRhYmFzZV9fTkFNRT0ke01ZU1FMX0RBVEFCQVNFLWZvcmdlam99JwogICAgICAtIEZPUkdFSk9fX2RhdGFiYXNlX19VU0VSPSRTRVJWSUNFX1VTRVJfTVlTUUwKICAgICAgLSBGT1JHRUpPX19kYXRhYmFzZV9fUEFTU1dEPSRTRVJWSUNFX1BBU1NXT1JEX01ZU1FMCiAgICB2b2x1bWVzOgogICAgICAtICdmb3JnZWpvLWRhdGE6L2RhdGEnCiAgICAgIC0gJ2Zvcmdlam8tdGltZXpvbmU6L2V0Yy90aW1lem9uZTpybycKICAgICAgLSAnZm9yZ2Vqby1sb2NhbHRpbWU6L2V0Yy9sb2NhbHRpbWU6cm8nCiAgICBwb3J0czoKICAgICAgLSAnMjIyMjI6MjInCiAgICBkZXBlbmRzX29uOgogICAgICBtYXJpYWRiOgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9oZWFsdGh5CiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRAogICAgICAgIC0gY3VybAogICAgICAgIC0gJy1mJwogICAgICAgIC0gJ2h0dHA6Ly8xMjcuMC4wLjE6MzAwMCcKICAgICAgaW50ZXJ2YWw6IDJzCiAgICAgIHRpbWVvdXQ6IDEwcwogICAgICByZXRyaWVzOiAxNQogIG1hcmlhZGI6CiAgICBpbWFnZTogJ21hcmlhZGI6MTEnCiAgICB2b2x1bWVzOgogICAgICAtICdmb3JnZWpvLW1hcmlhZGItZGF0YTovdmFyL2xpYi9teXNxbCcKICAgIGVudmlyb25tZW50OgogICAgICAtICdNWVNRTF9VU0VSPSR7U0VSVklDRV9VU0VSX01ZU1FMfScKICAgICAgLSAnTVlTUUxfUEFTU1dPUkQ9JHtTRVJWSUNFX1BBU1NXT1JEX01ZU1FMfScKICAgICAgLSAnTVlTUUxfREFUQUJBU0U9JHtNWVNRTF9EQVRBQkFTRX0nCiAgICAgIC0gJ01ZU1FMX1JPT1RfUEFTU1dPUkQ9JHtTRVJWSUNFX1BBU1NXT1JEX01ZU1FMUk9PVH0nCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRAogICAgICAgIC0gaGVhbHRoY2hlY2suc2gKICAgICAgICAtICctLWNvbm5lY3QnCiAgICAgICAgLSAnLS1pbm5vZGJfaW5pdGlhbGl6ZWQnCiAgICAgIGludGVydmFsOiA1cwogICAgICB0aW1lb3V0OiAyMHMKICAgICAgcmV0cmllczogMTAK",
|
||||
"tags": [
|
||||
"version control",
|
||||
"collaboration",
|
||||
@@ -1595,13 +1595,13 @@
|
||||
"category": "git",
|
||||
"logo": "svgs/forgejo.svg",
|
||||
"minversion": "0.0.0",
|
||||
"template_last_updated_at": "2026-02-04T17:34:52+01:00",
|
||||
"template_last_updated_at": "2026-08-10T11:35:20+02:00",
|
||||
"port": "3000"
|
||||
},
|
||||
"forgejo-with-mysql": {
|
||||
"documentation": "https://forgejo.org/docs?utm_source=coolify.io",
|
||||
"slogan": "Forgejo is a self-hosted lightweight software forge. Easy to install and low maintenance, it just does the job.",
|
||||
"compose": "c2VydmljZXM6CiAgZm9yZ2VqbzoKICAgIGltYWdlOiAnY29kZWJlcmcub3JnL2Zvcmdlam8vZm9yZ2Vqbzo4JwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9VUkxfRk9SR0VKT18zMDAwCiAgICAgIC0gJ0ZPUkdFSk9fX3NlcnZlcl9fUk9PVF9VUkw9JHtTRVJWSUNFX1VSTF9GT1JHRUpPfScKICAgICAgLSAnRk9SR0VKT19fbWlncmF0aW9uc19fQUxMT1dFRF9ET01BSU5TPSR7Rk9SR0VKT19fbWlncmF0aW9uc19fQUxMT1dFRF9ET01BSU5TfScKICAgICAgLSAnRk9SR0VKT19fbWlncmF0aW9uc19fQUxMT1dfTE9DQUxORVRXT1JLUz0ke0ZPUkdFSk9fX21pZ3JhdGlvbnNfX0FMTE9XX0xPQ0FMTkVUV09SS1MtZmFsc2V9JwogICAgICAtIFVTRVJfVUlEPTEwMDAKICAgICAgLSBVU0VSX0dJRD0xMDAwCiAgICAgIC0gRk9SR0VKT19fZGF0YWJhc2VfX0RCX1RZUEU9bXlzcWwKICAgICAgLSBGT1JHRUpPX19kYXRhYmFzZV9fSE9TVD1teXNxbAogICAgICAtICdGT1JHRUpPX19kYXRhYmFzZV9fTkFNRT0ke01ZU1FMX0RBVEFCQVNFLWZvcmdlam99JwogICAgICAtIEZPUkdFSk9fX2RhdGFiYXNlX19VU0VSPSRTRVJWSUNFX1VTRVJfTVlTUUwKICAgICAgLSBGT1JHRUpPX19kYXRhYmFzZV9fUEFTU1dEPSRTRVJWSUNFX1BBU1NXT1JEX01ZU1FMCiAgICB2b2x1bWVzOgogICAgICAtICdmb3JnZWpvLWRhdGE6L2RhdGEnCiAgICAgIC0gJ2Zvcmdlam8tdGltZXpvbmU6L2V0Yy90aW1lem9uZTpybycKICAgICAgLSAnZm9yZ2Vqby1sb2NhbHRpbWU6L2V0Yy9sb2NhbHRpbWU6cm8nCiAgICBwb3J0czoKICAgICAgLSAnMjIyMjI6MjInCiAgICBkZXBlbmRzX29uOgogICAgICBteXNxbDoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIGN1cmwKICAgICAgICAtICctZicKICAgICAgICAtICdodHRwOi8vMTI3LjAuMC4xOjMwMDAnCiAgICAgIGludGVydmFsOiAycwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgcmV0cmllczogMTUKICBteXNxbDoKICAgIGltYWdlOiAnbXlzcWw6OCcKICAgIHZvbHVtZXM6CiAgICAgIC0gJ2Zvcmdlam8tbXlzcWwtZGF0YTovdmFyL2xpYi9teXNxbCcKICAgIGVudmlyb25tZW50OgogICAgICAtICdNWVNRTF9VU0VSPSR7U0VSVklDRV9VU0VSX01ZU1FMfScKICAgICAgLSAnTVlTUUxfUEFTU1dPUkQ9JHtTRVJWSUNFX1BBU1NXT1JEX01ZU1FMfScKICAgICAgLSAnTVlTUUxfREFUQUJBU0U9JHtNWVNRTF9EQVRBQkFTRX0nCiAgICAgIC0gJ01ZU1FMX1JPT1RfUEFTU1dPUkQ9JHtTRVJWSUNFX1BBU1NXT1JEX01ZU1FMUk9PVH0nCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRAogICAgICAgIC0gbXlzcWxhZG1pbgogICAgICAgIC0gcGluZwogICAgICAgIC0gJy1oJwogICAgICAgIC0gMTI3LjAuMC4xCiAgICAgIGludGVydmFsOiA1cwogICAgICB0aW1lb3V0OiAyMHMKICAgICAgcmV0cmllczogMTAK",
|
||||
"compose": "c2VydmljZXM6CiAgZm9yZ2VqbzoKICAgIGltYWdlOiAnY29kZWJlcmcub3JnL2Zvcmdlam8vZm9yZ2VqbzoxNScKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfVVJMX0ZPUkdFSk9fMzAwMAogICAgICAtICdGT1JHRUpPX19zZXJ2ZXJfX1JPT1RfVVJMPSR7U0VSVklDRV9VUkxfRk9SR0VKT30nCiAgICAgIC0gJ0ZPUkdFSk9fX21pZ3JhdGlvbnNfX0FMTE9XRURfRE9NQUlOUz0ke0ZPUkdFSk9fX21pZ3JhdGlvbnNfX0FMTE9XRURfRE9NQUlOU30nCiAgICAgIC0gJ0ZPUkdFSk9fX21pZ3JhdGlvbnNfX0FMTE9XX0xPQ0FMTkVUV09SS1M9JHtGT1JHRUpPX19taWdyYXRpb25zX19BTExPV19MT0NBTE5FVFdPUktTLWZhbHNlfScKICAgICAgLSBVU0VSX1VJRD0xMDAwCiAgICAgIC0gVVNFUl9HSUQ9MTAwMAogICAgICAtIEZPUkdFSk9fX2RhdGFiYXNlX19EQl9UWVBFPW15c3FsCiAgICAgIC0gRk9SR0VKT19fZGF0YWJhc2VfX0hPU1Q9bXlzcWwKICAgICAgLSAnRk9SR0VKT19fZGF0YWJhc2VfX05BTUU9JHtNWVNRTF9EQVRBQkFTRS1mb3JnZWpvfScKICAgICAgLSBGT1JHRUpPX19kYXRhYmFzZV9fVVNFUj0kU0VSVklDRV9VU0VSX01ZU1FMCiAgICAgIC0gRk9SR0VKT19fZGF0YWJhc2VfX1BBU1NXRD0kU0VSVklDRV9QQVNTV09SRF9NWVNRTAogICAgdm9sdW1lczoKICAgICAgLSAnZm9yZ2Vqby1kYXRhOi9kYXRhJwogICAgICAtICdmb3JnZWpvLXRpbWV6b25lOi9ldGMvdGltZXpvbmU6cm8nCiAgICAgIC0gJ2Zvcmdlam8tbG9jYWx0aW1lOi9ldGMvbG9jYWx0aW1lOnJvJwogICAgcG9ydHM6CiAgICAgIC0gJzIyMjIyOjIyJwogICAgZGVwZW5kc19vbjoKICAgICAgbXlzcWw6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSBjdXJsCiAgICAgICAgLSAnLWYnCiAgICAgICAgLSAnaHR0cDovLzEyNy4wLjAuMTozMDAwJwogICAgICBpbnRlcnZhbDogMnMKICAgICAgdGltZW91dDogMTBzCiAgICAgIHJldHJpZXM6IDE1CiAgbXlzcWw6CiAgICBpbWFnZTogJ215c3FsOjgnCiAgICB2b2x1bWVzOgogICAgICAtICdmb3JnZWpvLW15c3FsLWRhdGE6L3Zhci9saWIvbXlzcWwnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSAnTVlTUUxfVVNFUj0ke1NFUlZJQ0VfVVNFUl9NWVNRTH0nCiAgICAgIC0gJ01ZU1FMX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9NWVNRTH0nCiAgICAgIC0gJ01ZU1FMX0RBVEFCQVNFPSR7TVlTUUxfREFUQUJBU0V9JwogICAgICAtICdNWVNRTF9ST09UX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9NWVNRTFJPT1R9JwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIG15c3FsYWRtaW4KICAgICAgICAtIHBpbmcKICAgICAgICAtICctaCcKICAgICAgICAtIDEyNy4wLjAuMQogICAgICBpbnRlcnZhbDogNXMKICAgICAgdGltZW91dDogMjBzCiAgICAgIHJldHJpZXM6IDEwCg==",
|
||||
"tags": [
|
||||
"version control",
|
||||
"collaboration",
|
||||
@@ -1613,13 +1613,13 @@
|
||||
"category": "git",
|
||||
"logo": "svgs/forgejo.svg",
|
||||
"minversion": "0.0.0",
|
||||
"template_last_updated_at": "2026-02-04T17:34:52+01:00",
|
||||
"template_last_updated_at": "2026-08-10T11:35:20+02:00",
|
||||
"port": "3000"
|
||||
},
|
||||
"forgejo-with-postgresql": {
|
||||
"documentation": "https://forgejo.org/docs?utm_source=coolify.io",
|
||||
"slogan": "Forgejo is a self-hosted lightweight software forge. Easy to install and low maintenance, it just does the job.",
|
||||
"compose": "c2VydmljZXM6CiAgZm9yZ2VqbzoKICAgIGltYWdlOiAnY29kZWJlcmcub3JnL2Zvcmdlam8vZm9yZ2Vqbzo4JwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9VUkxfRk9SR0VKT18zMDAwCiAgICAgIC0gJ0ZPUkdFSk9fX3NlcnZlcl9fUk9PVF9VUkw9JHtTRVJWSUNFX1VSTF9GT1JHRUpPfScKICAgICAgLSAnRk9SR0VKT19fbWlncmF0aW9uc19fQUxMT1dFRF9ET01BSU5TPSR7Rk9SR0VKT19fbWlncmF0aW9uc19fQUxMT1dFRF9ET01BSU5TfScKICAgICAgLSAnRk9SR0VKT19fbWlncmF0aW9uc19fQUxMT1dfTE9DQUxORVRXT1JLUz0ke0ZPUkdFSk9fX21pZ3JhdGlvbnNfX0FMTE9XX0xPQ0FMTkVUV09SS1MtZmFsc2V9JwogICAgICAtIFVTRVJfVUlEPTEwMDAKICAgICAgLSBVU0VSX0dJRD0xMDAwCiAgICAgIC0gRk9SR0VKT19fZGF0YWJhc2VfX0RCX1RZUEU9cG9zdGdyZXMKICAgICAgLSBGT1JHRUpPX19kYXRhYmFzZV9fSE9TVD1wb3N0Z3Jlc3FsCiAgICAgIC0gJ0ZPUkdFSk9fX2RhdGFiYXNlX19OQU1FPSR7UE9TVEdSRVNRTF9EQVRBQkFTRS1mb3JnZWpvfScKICAgICAgLSBGT1JHRUpPX19kYXRhYmFzZV9fVVNFUj0kU0VSVklDRV9VU0VSX1BPU1RHUkVTUUwKICAgICAgLSBGT1JHRUpPX19kYXRhYmFzZV9fUEFTU1dEPSRTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTUUwKICAgIHZvbHVtZXM6CiAgICAgIC0gJ2Zvcmdlam8tZGF0YTovZGF0YScKICAgICAgLSAnZm9yZ2Vqby10aW1lem9uZTovZXRjL3RpbWV6b25lOnJvJwogICAgICAtICdmb3JnZWpvLWxvY2FsdGltZTovZXRjL2xvY2FsdGltZTpybycKICAgIHBvcnRzOgogICAgICAtICcyMjIyMjoyMicKICAgIGRlcGVuZHNfb246CiAgICAgIHBvc3RncmVzcWw6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSBjdXJsCiAgICAgICAgLSAnLWYnCiAgICAgICAgLSAnaHR0cDovLzEyNy4wLjAuMTozMDAwJwogICAgICBpbnRlcnZhbDogMnMKICAgICAgdGltZW91dDogMTBzCiAgICAgIHJldHJpZXM6IDE1CiAgcG9zdGdyZXNxbDoKICAgIGltYWdlOiAncG9zdGdyZXM6MTYtYWxwaW5lJwogICAgdm9sdW1lczoKICAgICAgLSAnZm9yZ2Vqby1wb3N0Z3Jlc3FsLWRhdGE6L3Zhci9saWIvcG9zdGdyZXNxbC9kYXRhJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ1BPU1RHUkVTX1VTRVI9JHtTRVJWSUNFX1VTRVJfUE9TVEdSRVNRTH0nCiAgICAgIC0gJ1BPU1RHUkVTX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU1FMfScKICAgICAgLSAnUE9TVEdSRVNfREI9JHtQT1NUR1JFU1FMX0RBVEFCQVNFfScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ELVNIRUxMCiAgICAgICAgLSAncGdfaXNyZWFkeSAtVSAkJHtQT1NUR1JFU19VU0VSfSAtZCAkJHtQT1NUR1JFU19EQn0nCiAgICAgIGludGVydmFsOiA1cwogICAgICB0aW1lb3V0OiAyMHMKICAgICAgcmV0cmllczogMTAK",
|
||||
"compose": "c2VydmljZXM6CiAgZm9yZ2VqbzoKICAgIGltYWdlOiAnY29kZWJlcmcub3JnL2Zvcmdlam8vZm9yZ2VqbzoxNScKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfVVJMX0ZPUkdFSk9fMzAwMAogICAgICAtICdGT1JHRUpPX19zZXJ2ZXJfX1JPT1RfVVJMPSR7U0VSVklDRV9VUkxfRk9SR0VKT30nCiAgICAgIC0gJ0ZPUkdFSk9fX21pZ3JhdGlvbnNfX0FMTE9XRURfRE9NQUlOUz0ke0ZPUkdFSk9fX21pZ3JhdGlvbnNfX0FMTE9XRURfRE9NQUlOU30nCiAgICAgIC0gJ0ZPUkdFSk9fX21pZ3JhdGlvbnNfX0FMTE9XX0xPQ0FMTkVUV09SS1M9JHtGT1JHRUpPX19taWdyYXRpb25zX19BTExPV19MT0NBTE5FVFdPUktTLWZhbHNlfScKICAgICAgLSBVU0VSX1VJRD0xMDAwCiAgICAgIC0gVVNFUl9HSUQ9MTAwMAogICAgICAtIEZPUkdFSk9fX2RhdGFiYXNlX19EQl9UWVBFPXBvc3RncmVzCiAgICAgIC0gRk9SR0VKT19fZGF0YWJhc2VfX0hPU1Q9cG9zdGdyZXNxbAogICAgICAtICdGT1JHRUpPX19kYXRhYmFzZV9fTkFNRT0ke1BPU1RHUkVTUUxfREFUQUJBU0UtZm9yZ2Vqb30nCiAgICAgIC0gRk9SR0VKT19fZGF0YWJhc2VfX1VTRVI9JFNFUlZJQ0VfVVNFUl9QT1NUR1JFU1FMCiAgICAgIC0gRk9SR0VKT19fZGF0YWJhc2VfX1BBU1NXRD0kU0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU1FMCiAgICB2b2x1bWVzOgogICAgICAtICdmb3JnZWpvLWRhdGE6L2RhdGEnCiAgICAgIC0gJ2Zvcmdlam8tdGltZXpvbmU6L2V0Yy90aW1lem9uZTpybycKICAgICAgLSAnZm9yZ2Vqby1sb2NhbHRpbWU6L2V0Yy9sb2NhbHRpbWU6cm8nCiAgICBwb3J0czoKICAgICAgLSAnMjIyMjI6MjInCiAgICBkZXBlbmRzX29uOgogICAgICBwb3N0Z3Jlc3FsOgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9oZWFsdGh5CiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRAogICAgICAgIC0gY3VybAogICAgICAgIC0gJy1mJwogICAgICAgIC0gJ2h0dHA6Ly8xMjcuMC4wLjE6MzAwMCcKICAgICAgaW50ZXJ2YWw6IDJzCiAgICAgIHRpbWVvdXQ6IDEwcwogICAgICByZXRyaWVzOiAxNQogIHBvc3RncmVzcWw6CiAgICBpbWFnZTogJ3Bvc3RncmVzOjE2LWFscGluZScKICAgIHZvbHVtZXM6CiAgICAgIC0gJ2Zvcmdlam8tcG9zdGdyZXNxbC1kYXRhOi92YXIvbGliL3Bvc3RncmVzcWwvZGF0YScKICAgIGVudmlyb25tZW50OgogICAgICAtICdQT1NUR1JFU19VU0VSPSR7U0VSVklDRV9VU0VSX1BPU1RHUkVTUUx9JwogICAgICAtICdQT1NUR1JFU19QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVNRTH0nCiAgICAgIC0gJ1BPU1RHUkVTX0RCPSR7UE9TVEdSRVNRTF9EQVRBQkFTRX0nCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gJ3BnX2lzcmVhZHkgLVUgJCR7UE9TVEdSRVNfVVNFUn0gLWQgJCR7UE9TVEdSRVNfREJ9JwogICAgICBpbnRlcnZhbDogNXMKICAgICAgdGltZW91dDogMjBzCiAgICAgIHJldHJpZXM6IDEwCg==",
|
||||
"tags": [
|
||||
"version control",
|
||||
"collaboration",
|
||||
@@ -1631,13 +1631,13 @@
|
||||
"category": "git",
|
||||
"logo": "svgs/forgejo.svg",
|
||||
"minversion": "0.0.0",
|
||||
"template_last_updated_at": "2026-02-04T17:34:52+01:00",
|
||||
"template_last_updated_at": "2026-08-10T11:35:20+02:00",
|
||||
"port": "3000"
|
||||
},
|
||||
"forgejo": {
|
||||
"documentation": "https://forgejo.org/docs?utm_source=coolify.io",
|
||||
"slogan": "Forgejo is a self-hosted lightweight software forge. Easy to install and low maintenance, it just does the job.",
|
||||
"compose": "c2VydmljZXM6CiAgZm9yZ2VqbzoKICAgIGltYWdlOiAnY29kZWJlcmcub3JnL2Zvcmdlam8vZm9yZ2Vqbzo4JwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9VUkxfRk9SR0VKT18zMDAwCiAgICAgIC0gJ0ZPUkdFSk9fX3NlcnZlcl9fUk9PVF9VUkw9JHtTRVJWSUNFX1VSTF9GT1JHRUpPfScKICAgICAgLSAnRk9SR0VKT19fbWlncmF0aW9uc19fQUxMT1dFRF9ET01BSU5TPSR7Rk9SR0VKT19fbWlncmF0aW9uc19fQUxMT1dFRF9ET01BSU5TfScKICAgICAgLSAnRk9SR0VKT19fbWlncmF0aW9uc19fQUxMT1dfTE9DQUxORVRXT1JLUz0ke0ZPUkdFSk9fX21pZ3JhdGlvbnNfX0FMTE9XX0xPQ0FMTkVUV09SS1MtZmFsc2V9JwogICAgICAtIFVTRVJfVUlEPTEwMDAKICAgICAgLSBVU0VSX0dJRD0xMDAwCiAgICBwb3J0czoKICAgICAgLSAnMjIyMjI6MjInCiAgICB2b2x1bWVzOgogICAgICAtICdmb3JnZWpvLWRhdGE6L2RhdGEnCiAgICAgIC0gJ2Zvcmdlam8tdGltZXpvbmU6L2V0Yy90aW1lem9uZTpybycKICAgICAgLSAnZm9yZ2Vqby1sb2NhbHRpbWU6L2V0Yy9sb2NhbHRpbWU6cm8nCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRAogICAgICAgIC0gY3VybAogICAgICAgIC0gJy1mJwogICAgICAgIC0gJ2h0dHA6Ly8xMjcuMC4wLjE6MzAwMCcKICAgICAgaW50ZXJ2YWw6IDJzCiAgICAgIHRpbWVvdXQ6IDEwcwogICAgICByZXRyaWVzOiAxNQo=",
|
||||
"compose": "c2VydmljZXM6CiAgZm9yZ2VqbzoKICAgIGltYWdlOiAnY29kZWJlcmcub3JnL2Zvcmdlam8vZm9yZ2VqbzoxNScKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfVVJMX0ZPUkdFSk9fMzAwMAogICAgICAtICdGT1JHRUpPX19zZXJ2ZXJfX1JPT1RfVVJMPSR7U0VSVklDRV9VUkxfRk9SR0VKT30nCiAgICAgIC0gJ0ZPUkdFSk9fX21pZ3JhdGlvbnNfX0FMTE9XRURfRE9NQUlOUz0ke0ZPUkdFSk9fX21pZ3JhdGlvbnNfX0FMTE9XRURfRE9NQUlOU30nCiAgICAgIC0gJ0ZPUkdFSk9fX21pZ3JhdGlvbnNfX0FMTE9XX0xPQ0FMTkVUV09SS1M9JHtGT1JHRUpPX19taWdyYXRpb25zX19BTExPV19MT0NBTE5FVFdPUktTLWZhbHNlfScKICAgICAgLSBVU0VSX1VJRD0xMDAwCiAgICAgIC0gVVNFUl9HSUQ9MTAwMAogICAgcG9ydHM6CiAgICAgIC0gJzIyMjIyOjIyJwogICAgdm9sdW1lczoKICAgICAgLSAnZm9yZ2Vqby1kYXRhOi9kYXRhJwogICAgICAtICdmb3JnZWpvLXRpbWV6b25lOi9ldGMvdGltZXpvbmU6cm8nCiAgICAgIC0gJ2Zvcmdlam8tbG9jYWx0aW1lOi9ldGMvbG9jYWx0aW1lOnJvJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIGN1cmwKICAgICAgICAtICctZicKICAgICAgICAtICdodHRwOi8vMTI3LjAuMC4xOjMwMDAnCiAgICAgIGludGVydmFsOiAycwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgcmV0cmllczogMTUK",
|
||||
"tags": [
|
||||
"version control",
|
||||
"collaboration",
|
||||
@@ -1648,7 +1648,7 @@
|
||||
"category": "git",
|
||||
"logo": "svgs/forgejo.svg",
|
||||
"minversion": "0.0.0",
|
||||
"template_last_updated_at": "2026-02-04T17:34:52+01:00",
|
||||
"template_last_updated_at": "2026-08-10T11:35:20+02:00",
|
||||
"port": "3000"
|
||||
},
|
||||
"formbricks": {
|
||||
@@ -2385,6 +2385,24 @@
|
||||
"template_last_updated_at": "2025-12-15T17:56:33+01:00",
|
||||
"port": "8080"
|
||||
},
|
||||
"influxdb": {
|
||||
"documentation": "https://docs.influxdata.com/influxdb/?utm_source=coolify.io",
|
||||
"slogan": "Open source time series database for metrics, events, and analytics.",
|
||||
"compose": "c2VydmljZXM6CiAgaW5mbHV4ZGI6CiAgICBpbWFnZTogJ2luZmx1eGRiOjIuNy1hbHBpbmUnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTRVJWSUNFX1VSTF9JTkZMVVhEQl84MDg2CiAgICAgIC0gJ0lORkxVWERCX0hUVFBfQklORF9BRERSRVNTPTo4MDg2JwogICAgICAtIElORkxVWERCX0lOSVRfTU9ERT1zZXR1cAogICAgICAtIElORkxVWERCX0lOSVRfVVNFUk5BTUU9JFNFUlZJQ0VfVVNFUl9JTkZMVVhEQgogICAgICAtIElORkxVWERCX0lOSVRfUEFTU1dPUkQ9JFNFUlZJQ0VfUEFTU1dPUkRfSU5GTFVYREIKICAgICAgLSBJTkZMVVhEQl9JTklUX09SRz0kU0VSVklDRV9PUkdfSU5GTFVYREIKICAgICAgLSBJTkZMVVhEQl9JTklUX0JVQ0tFVD0kU0VSVklDRV9CVUNLRVRfSU5GTFVYREIKICAgICAgLSBJTkZMVVhEQl9JTklUX1JFVEVOVElPTj0wCiAgICAgIC0gSU5GTFVYREJfSU5JVF9BRE1JTl9UT0tFTj0kU0VSVklDRV9QQVNTV09SRF9JTkZMVVhEQl9UT0tFTgogICAgdm9sdW1lczoKICAgICAgLSAnaW5mbHV4ZGItZGF0YTovdmFyL2xpYi9pbmZsdXhkYjInCiAgICAgIC0gJ2luZmx1eGRiLWNvbmZpZzovZXRjL2luZmx1eGRiMicKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSBpbmZsdXgKICAgICAgICAtIHBpbmcKICAgICAgICAtICctLWhvc3QnCiAgICAgICAgLSAnaHR0cDovLzEyNy4wLjAuMTo4MDg2JwogICAgICBpbnRlcnZhbDogMTBzCiAgICAgIHRpbWVvdXQ6IDVzCiAgICAgIHJldHJpZXM6IDUKICAgICAgc3RhcnRfcGVyaW9kOiAyMHMK",
|
||||
"tags": [
|
||||
"influxdb",
|
||||
"time series",
|
||||
"metrics",
|
||||
"iot",
|
||||
"monitoring",
|
||||
"telegraf"
|
||||
],
|
||||
"category": "databases",
|
||||
"logo": "svgs/influxdb.svg",
|
||||
"minversion": "0.0.0",
|
||||
"template_last_updated_at": "2026-08-10T12:53:16+02:00",
|
||||
"port": "8086"
|
||||
},
|
||||
"inngest": {
|
||||
"documentation": "https://www.inngest.com/docs/self-hosting?utm_source=coolify.io",
|
||||
"slogan": "Durable workflow engine for background jobs, queues and scheduled tasks.",
|
||||
@@ -2863,7 +2881,7 @@
|
||||
"litellm": {
|
||||
"documentation": "https://docs.litellm.ai?utm_source=coolify.io",
|
||||
"slogan": "Call all LLM APIs using the OpenAI format. Use Bedrock, Azure, OpenAI, Cohere, Anthropic, Ollama, Sagemaker, HuggingFace, Replicate, Groq (100+ LLMs)",
|
||||
"compose": "c2VydmljZXM6CiAgbGl0ZWxsbToKICAgIGltYWdlOiAnZ2hjci5pby9iZXJyaWFpL2xpdGVsbG0tZGF0YWJhc2U6bWFpbi1zdGFibGUnCiAgICBkZXBlbmRzX29uOgogICAgICBwb3N0Z3JlczoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgICByZWRpczoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9VUkxfTElURUxMTV80MDAwCiAgICAgIC0gJ0xJVEVMTE1fTE9HPSR7TElURUxMTV9MT0c6LUVSUk9SfScKICAgICAgLSAnTElURUxMTV9NT0RFPSR7TElURUxMTV9NT0RFOi1QUk9EVUNUSU9OfScKICAgICAgLSAnTElURUxMTV9NQVNURVJfS0VZPSR7U0VSVklDRV9QQVNTV09SRF9NQVNURVJLRVl9JwogICAgICAtICdVSV9VU0VSTkFNRT0ke1NFUlZJQ0VfVVNFUl9VSX0nCiAgICAgIC0gJ1VJX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9VSX0nCiAgICAgIC0gJ0RBVEFCQVNFX1VSTD1wb3N0Z3Jlc3FsOi8vJHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9OiR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU31AcG9zdGdyZXM6NTQzMi8ke1BPU1RHUkVTX0RCOi1saXRlbGxtfScKICAgICAgLSAnUkVESVNfSE9TVD0ke1JFRElTX0hPU1Q6LXJlZGlzfScKICAgICAgLSAnUkVESVNfUE9SVD0ke1JFRElTX1BPUlQ6LTYzNzl9JwogICAgICAtICdQT1NUR1JFU19VU0VSPSR7U0VSVklDRV9VU0VSX1BPU1RHUkVTfScKICAgICAgLSAnUE9TVEdSRVNfUEFTU1dPUkQ9JHtTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTfScKICAgICAgLSAnUE9TVEdSRVNfREI9JHtQT1NUR1JFU19EQjotbGl0ZWxsbX0nCiAgICAgIC0gJ09QRU5BSV9BUElfS0VZPSR7T1BFTkFJX0FQSV9LRVl9JwogICAgICAtICdPUEVOQUlfQVBJX0JBU0U9JHtPUEVOQUlfQVBJX0JBU0V9JwogICAgICAtICdBTlRIUk9QSUNfQVBJX0tFWT0ke0FOVEhST1BJQ19BUElfS0VZfScKICAgICAgLSAnQU5USFJPUElDX0FQSV9CQVNFPSR7QU5USFJPUElDX0FQSV9CQVNFfScKICAgICAgLSAnVk9ZQUdFX0FQSV9LRVk9JHtWT1lBR0VfQVBJX0tFWX0nCiAgICAgIC0gJ1ZPWUFHRV9BUElfQkFTRT0ke1ZPWUFHRV9BUElfQkFTRX0nCiAgICAgIC0gJ1NUT1JFX01PREVMX0lOX0RCPSR7U1RPUkVfTU9ERUxfSU5fREJ9JwogICAgdm9sdW1lczoKICAgICAgLQogICAgICAgIHR5cGU6IGJpbmQKICAgICAgICBzb3VyY2U6IC4vbGl0ZWxsbS1jb25maWcueWFtbAogICAgICAgIHRhcmdldDogL2FwcC9jb25maWcueWFtbAogICAgICAgIGNvbnRlbnQ6ICJnZW5lcmFsX3NldHRpbmdzOlxuICBwcm94eV9iYXRjaF93cml0ZV9hdDogNjBcblxucm91dGVyX3NldHRpbmdzOlxuICByZWRpc19ob3N0OiBvcy5lbnZpcm9uL1JFRElTX0hPU1RcbiAgcmVkaXNfcG9ydDogb3MuZW52aXJvbi9SRURJU19QT1JUXG4gIHJlZGlzX3Bhc3N3b3JkOiBvcy5lbnZpcm9uL1JFRElTX1BBU1NXT1JEXG4gIGVuYWJsZV9wcmVfY2FsbF9jaGVjazogdHJ1ZVxuXG5saXRlbGxtX3NldHRpbmdzOlxuICBzZXRfdmVyYm9zZTogZmFsc2VcbiAganNvbl9sb2dzOiB0cnVlXG4gIGxvZ19yYXdfcmVxdWVzdF9yZXNwb25zZTogdHJ1ZVxuICAjIHR1cm5fb2ZmX21lc3NhZ2VfbG9nZ2luZzogZmFsc2VcbiAgIyByZWRhY3RfdXNlcl9hcGlfa2V5X2luZm86IGZhbHNlXG4gIHNlcnZpY2VfY2FsbGJhY2s6IFtcInByb21ldGhldXNfc3lzdGVtXCJdXG4gIGRyb3BfcGFyYW1zOiB0cnVlXG4gICMgbWF4X2J1ZGdldDogMTAwXG4gICMgYnVkZ2V0X2R1cmF0aW9uOiAzMGRcbiAgbnVtX3JldHJpZXM6IDNcbiAgcmVxdWVzdF90aW1lb3V0OiA2MDBcbiAgdGVsZW1ldHJ5OiBmYWxzZVxuICBjYWNoZTogdHJ1ZVxuICBjYWNoZV9wYXJhbXM6XG4gICAgdHlwZTogcmVkaXNcbiAgICBob3N0OiBvcy5lbnZpcm9uL1JFRElTX0hPU1RcbiAgICBwb3J0OiBvcy5lbnZpcm9uL1JFRElTX1BPUlRcbiAgICBwYXNzd29yZDogb3MuZW52aXJvbi9SRURJU19QQVNTV09SRFxuICAgIG5hbWVzcGFjZTogXCJsaXRlbGxtX2NhY2hlXCJcbiAgICB0dGw6IDYwMFxuICBzdWNjZXNzX2NhbGxiYWNrOlxuICAgICMgLSBcImxhbmdmdXNlXCJcbiAgICAtIFwicHJvbWV0aGV1c1wiXG4gIGZhaWx1cmVfY2FsbGJhY2s6XG4gICAgIyAtIFwibGFuZ2Z1c2VcIlxuICAgIC0gXCJwcm9tZXRoZXVzXCJcbm1vZGVsX2xpc3Q6XG4gICMgT3BlbkFJXG4gIC0gbW9kZWxfbmFtZTogZ3B0LTRcbiAgICBsaXRlbGxtX3BhcmFtczpcbiAgICAgIG1vZGVsOiBvcGVuYWkvZ3B0LTRcbiAgICAgIGFwaV9rZXk6IG9zLmVudmlyb24vT1BFTkFJX0FQSV9LRVlcbiAgICAgIGFwaV9iYXNlOiBvcy5lbnZpcm9uL09QRU5BSV9BUElfQkFTRVxuICAtIG1vZGVsX25hbWU6IGdwdC00b1xuICAgIGxpdGVsbG1fcGFyYW1zOlxuICAgICAgbW9kZWw6IG9wZW5haS9ncHQtNG9cbiAgICAgIGFwaV9rZXk6IG9zLmVudmlyb24vT1BFTkFJX0FQSV9LRVlcbiAgICAgIGFwaV9iYXNlOiBvcy5lbnZpcm9uL09QRU5BSV9BUElfQkFTRVxuICAtIG1vZGVsX25hbWU6IGdwdC00by1taW5pXG4gICAgbGl0ZWxsbV9wYXJhbXM6XG4gICAgICBtb2RlbDogb3BlbmFpL2dwdC00by1taW5pXG4gICAgICBhcGlfa2V5OiBvcy5lbnZpcm9uL09QRU5BSV9BUElfS0VZXG4gICAgICBhcGlfYmFzZTogb3MuZW52aXJvbi9PUEVOQUlfQVBJX0JBU0VcbiAgIyBBbnRocm9waWNcbiAgLSBtb2RlbF9uYW1lOiBjbGF1ZGUtMy1oYWlrdVxuICAgIGxpdGVsbG1fcGFyYW1zOlxuICAgICAgbW9kZWw6IGNsYXVkZS0zLWhhaWt1LTIwMjQwMzA3XG4gICAgICBhcGlfa2V5OiBcIm9zLmVudmlyb24vQU5USFJPUElDX0FQSV9LRVlcIlxuICAgICAgYXBpX2Jhc2U6IFwib3MuZW52aXJvbi9BTlRIUk9QSUNfQVBJX0JBU0VcIlxuICAtIG1vZGVsX25hbWU6IGNsYXVkZS0zLjUtc29ubmV0XG4gICAgbGl0ZWxsbV9wYXJhbXM6XG4gICAgICBtb2RlbDogY2xhdWRlLTMtNS1zb25uZXQtMjAyNDA2MjBcbiAgICAgIGFwaV9rZXk6IFwib3MuZW52aXJvbi9BTlRIUk9QSUNfQVBJX0tFWVwiXG4gICAgICBhcGlfYmFzZTogXCJvcy5lbnZpcm9uL0FOVEhST1BJQ19BUElfQkFTRVwiXG4gICMgVm95YWdlQUlcbiAgLSBtb2RlbF9uYW1lOiB2b3lhZ2UtbGF3LTJcbiAgICBtb2RlbF9pbmZvOlxuICAgICAgb3V0cHV0X3ZlY3Rvcl9zaXplOiAxMDI0XG4gICAgbGl0ZWxsbV9wYXJhbXM6XG4gICAgICBtb2RlbDogdm95YWdlL3ZveWFnZS1sYXctMlxuICAgICAgYXBpX2tleTogXCJvcy5lbnZpcm9uL1ZPWUFHRV9BUElfS0VZXCJcbiAgICAgIGFwaV9iYXNlOiBcIm9zLmVudmlyb24vVk9ZQUdFX0FQSV9CQVNFXCJcbiAgICAgICMgcnBtOiAzMDBcbiAgICAgICMgdHBtOiAxMDAwMDAwXG4gIC0gbW9kZWxfbmFtZTogdm95YWdlLW11bHRpbGluZ3VhbC0yXG4gICAgbW9kZWxfaW5mbzpcbiAgICAgIG1vZGU6IGVtYmVkZGluZ1xuICAgICAgbWF4X3Rva2VuczogMzIwMDBcbiAgICAgIG1heF9pbnB1dF90b2tlbnM6IDMyMDAwXG4gICAgICBvdXRwdXRfdmVjdG9yX3NpemU6IDEwMjRcbiAgICBsaXRlbGxtX3BhcmFtczpcbiAgICAgIG1vZGVsOiB2b3lhZ2Uvdm95YWdlLW11bHRpbGluZ3VhbC0yXG4gICAgICBhcGlfa2V5OiBcIm9zLmVudmlyb24vVk9ZQUdFX0FQSV9LRVlcIlxuICAgICAgYXBpX2Jhc2U6IFwib3MuZW52aXJvbi9WT1lBR0VfQVBJX0JBU0VcIlxuICAgICAgaW5wdXRfY29zdF9Line truncated
|
||||
"compose": "c2VydmljZXM6CiAgbGl0ZWxsbToKICAgIGltYWdlOiAnZ2hjci5pby9iZXJyaWFpL2xpdGVsbG0tZGF0YWJhc2U6bWFpbi1zdGFibGUnCiAgICBkZXBlbmRzX29uOgogICAgICBwb3N0Z3JlczoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgICByZWRpczoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9VUkxfTElURUxMTV80MDAwCiAgICAgIC0gJ0xJVEVMTE1fTE9HPSR7TElURUxMTV9MT0c6LUVSUk9SfScKICAgICAgLSAnTElURUxMTV9NT0RFPSR7TElURUxMTV9NT0RFOi1QUk9EVUNUSU9OfScKICAgICAgLSAnTElURUxMTV9NQVNURVJfS0VZPSR7U0VSVklDRV9QQVNTV09SRF9NQVNURVJLRVl9JwogICAgICAtICdVSV9VU0VSTkFNRT0ke1NFUlZJQ0VfVVNFUl9VSX0nCiAgICAgIC0gJ1VJX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9VSX0nCiAgICAgIC0gJ0RBVEFCQVNFX1VSTD1wb3N0Z3Jlc3FsOi8vJHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9OiR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU31AcG9zdGdyZXM6NTQzMi8ke1BPU1RHUkVTX0RCOi1saXRlbGxtfScKICAgICAgLSAnUkVESVNfSE9TVD0ke1JFRElTX0hPU1Q6LXJlZGlzfScKICAgICAgLSAnUkVESVNfUE9SVD0ke1JFRElTX1BPUlQ6LTYzNzl9JwogICAgICAtICdQT1NUR1JFU19VU0VSPSR7U0VSVklDRV9VU0VSX1BPU1RHUkVTfScKICAgICAgLSAnUE9TVEdSRVNfUEFTU1dPUkQ9JHtTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTfScKICAgICAgLSAnUE9TVEdSRVNfREI9JHtQT1NUR1JFU19EQjotbGl0ZWxsbX0nCiAgICAgIC0gJ09QRU5BSV9BUElfS0VZPSR7T1BFTkFJX0FQSV9LRVl9JwogICAgICAtICdPUEVOQUlfQVBJX0JBU0U9JHtPUEVOQUlfQVBJX0JBU0V9JwogICAgICAtICdBTlRIUk9QSUNfQVBJX0tFWT0ke0FOVEhST1BJQ19BUElfS0VZfScKICAgICAgLSAnQU5USFJPUElDX0FQSV9CQVNFPSR7QU5USFJPUElDX0FQSV9CQVNFfScKICAgICAgLSAnVk9ZQUdFX0FQSV9LRVk9JHtWT1lBR0VfQVBJX0tFWX0nCiAgICAgIC0gJ1ZPWUFHRV9BUElfQkFTRT0ke1ZPWUFHRV9BUElfQkFTRX0nCiAgICAgIC0gJ1NUT1JFX01PREVMX0lOX0RCPSR7U1RPUkVfTU9ERUxfSU5fREJ9JwogICAgdm9sdW1lczoKICAgICAgLQogICAgICAgIHR5cGU6IGJpbmQKICAgICAgICBzb3VyY2U6IC4vbGl0ZWxsbS1jb25maWcueWFtbAogICAgICAgIHRhcmdldDogL2FwcC9jb25maWcueWFtbAogICAgICAgIGNvbnRlbnQ6ICJnZW5lcmFsX3NldHRpbmdzOlxuICBwcm94eV9iYXRjaF93cml0ZV9hdDogNjBcbiAgc3RvcmVfcHJvbXB0c19pbl9zcGVuZF9sb2dzOiBmYWxzZVxuXG5yb3V0ZXJfc2V0dGluZ3M6XG4gIHJlZGlzX2hvc3Q6IG9zLmVudmlyb24vUkVESVNfSE9TVFxuICByZWRpc19wb3J0OiBvcy5lbnZpcm9uL1JFRElTX1BPUlRcbiAgcmVkaXNfcGFzc3dvcmQ6IG9zLmVudmlyb24vUkVESVNfUEFTU1dPUkRcbiAgZW5hYmxlX3ByZV9jYWxsX2NoZWNrOiB0cnVlXG5cbmxpdGVsbG1fc2V0dGluZ3M6XG4gIHNldF92ZXJib3NlOiBmYWxzZVxuICBqc29uX2xvZ3M6IHRydWVcbiAgbG9nX3Jhd19yZXF1ZXN0X3Jlc3BvbnNlOiBmYWxzZVxuICAjIHR1cm5fb2ZmX21lc3NhZ2VfbG9nZ2luZzogZmFsc2VcbiAgIyByZWRhY3RfdXNlcl9hcGlfa2V5X2luZm86IGZhbHNlXG4gIHNlcnZpY2VfY2FsbGJhY2s6IFtcInByb21ldGhldXNfc3lzdGVtXCJdXG4gIGRyb3BfcGFyYW1zOiB0cnVlXG4gICMgbWF4X2J1ZGdldDogMTAwXG4gICMgYnVkZ2V0X2R1cmF0aW9uOiAzMGRcbiAgbnVtX3JldHJpZXM6IDFcbiAgcmVxdWVzdF90aW1lb3V0OiAxMjBcbiAgdGVsZW1ldHJ5OiBmYWxzZVxuICBjYWNoZTogdHJ1ZVxuICBjYWNoZV9wYXJhbXM6XG4gICAgdHlwZTogcmVkaXNcbiAgICBob3N0OiBvcy5lbnZpcm9uL1JFRElTX0hPU1RcbiAgICBwb3J0OiBvcy5lbnZpcm9uL1JFRElTX1BPUlRcbiAgICBwYXNzd29yZDogb3MuZW52aXJvbi9SRURJU19QQVNTV09SRFxuICAgIG5hbWVzcGFjZTogXCJsaXRlbGxtX2NhY2hlXCJcbiAgICB0dGw6IDYwMFxuICBzdWNjZXNzX2NhbGxiYWNrOlxuICAgICMgLSBcImxhbmdmdXNlXCJcbiAgICAtIFwicHJvbWV0aGV1c1wiXG4gIGZhaWx1cmVfY2FsbGJhY2s6XG4gICAgIyAtIFwibGFuZ2Z1c2VcIlxuICAgIC0gXCJwcm9tZXRoZXVzXCJcbm1vZGVsX2xpc3Q6XG4gICMgT3BlbkFJXG4gIC0gbW9kZWxfbmFtZTogZ3B0LTRcbiAgICBsaXRlbGxtX3BhcmFtczpcbiAgICAgIG1vZGVsOiBvcGVuYWkvZ3B0LTRcbiAgICAgIGFwaV9rZXk6IG9zLmVudmlyb24vT1BFTkFJX0FQSV9LRVlcbiAgICAgIGFwaV9iYXNlOiBvcy5lbnZpcm9uL09QRU5BSV9BUElfQkFTRVxuICAtIG1vZGVsX25hbWU6IGdwdC00b1xuICAgIGxpdGVsbG1fcGFyYW1zOlxuICAgICAgbW9kZWw6IG9wZW5haS9ncHQtNG9cbiAgICAgIGFwaV9rZXk6IG9zLmVudmlyb24vT1BFTkFJX0FQSV9LRVlcbiAgICAgIGFwaV9iYXNlOiBvcy5lbnZpcm9uL09QRU5BSV9BUElfQkFTRVxuICAtIG1vZGVsX25hbWU6IGdwdC00by1taW5pXG4gICAgbGl0ZWxsbV9wYXJhbXM6XG4gICAgICBtb2RlbDogb3BlbmFpL2dwdC00by1taW5pXG4gICAgICBhcGlfa2V5OiBvcy5lbnZpcm9uL09QRU5BSV9BUElfS0VZXG4gICAgICBhcGlfYmFzZTogb3MuZW52aXJvbi9PUEVOQUlfQVBJX0JBU0VcbiAgIyBBbnRocm9waWNcbiAgLSBtb2RlbF9uYW1lOiBjbGF1ZGUtMy1oYWlrdVxuICAgIGxpdGVsbG1fcGFyYW1zOlxuICAgICAgbW9kZWw6IGNsYXVkZS0zLWhhaWt1LTIwMjQwMzA3XG4gICAgICBhcGlfa2V5OiBcIm9zLmVudmlyb24vQU5USFJPUElDX0FQSV9LRVlcIlxuICAgICAgYXBpX2Jhc2U6IFwib3MuZW52aXJvbi9BTlRIUk9QSUNfQVBJX0JBU0VcIlxuICAtIG1vZGVsX25hbWU6IGNsYXVkZS0zLjUtc29ubmV0XG4gICAgbGl0ZWxsbV9wYXJhbXM6XG4gICAgICBtb2RlbDogY2xhdWRlLTMtNS1zb25uZXQtMjAyNDA2MjBcbiAgICAgIGFwaV9rZXk6IFwib3MuZW52aXJvbi9BTlRIUk9QSUNfQVBJX0tFWVwiXG4gICAgICBhcGlfYmFzZTogXCJvcy5lbnZpcm9uL0FOVEhST1BJQ19BUElfQkFTRVwiXG4gICMgVm95YWdlQUlcbiAgLSBtb2RlbF9uYW1lOiB2b3lhZ2UtbGF3LTJcbiAgICBtb2RlbF9pbmZvOlxuICAgICAgb3V0cHV0X3ZlY3Rvcl9zaXplOiAxMDI0XG4gICAgbGl0ZWxsbV9wYXJhbXM6XG4gICAgICBtb2RlbDogdm95YWdlL3ZveWFnZS1sYXctMlxuICAgICAgYXBpX2tleTogXCJvcy5lbnZpcm9uL1ZPWUFHRV9BUElfS0VZXCJcbiAgICAgIGFwaV9iYXNlOiBcIm9zLmVudmlyb24vVk9ZQUdFX0FQSV9CQVNFXCJcbiAgICAgICMgcnBtOiAzMDBcbiAgICAgICMgdHBtOiAxMDAwMDAwXG4gIC0gbW9kZWxfbmFtZTogdm95YWdlLW11bHRpbGluZ3VhbC0yXG4gICAgbW9kZWxfaW5mbzpcbiAgICAgIG1vZGU6IGVtYmVkZGluZ1xuICAgICAgbWF4X3Rva2VuczogMzIwMDBcbiAgICAgIG1heF9pbnB1dF90b2tlbnM6IDMyMDAwXG4gICAgICBvdXRwdXRfdmVjdG9yX3NpemU6IDEwMjRcbiAgICBsaXRlbGxtX3BhcmFtczpcbiAgICAgIG1vZGVsOiB2b3lhZ2Uvdm95YWdlLW11bHRpbGluZ3VhbC0yXG4gICAgICBhcGlfa2V5OiBcIm9zLmVudmlyb24vVk9ZQUdFX0FQSV9LRVlcIlxuICAgICAgYXBpX2Jhc2U6IFwib3MuZW52aXJLine truncated
|
||||
"tags": [
|
||||
"ai",
|
||||
"qdrant",
|
||||
@@ -2884,7 +2902,7 @@
|
||||
"category": "ai",
|
||||
"logo": "svgs/litellm.svg",
|
||||
"minversion": "0.0.0",
|
||||
"template_last_updated_at": "2025-12-14T21:08:27+01:00",
|
||||
"template_last_updated_at": "2026-08-10T13:08:06+02:00",
|
||||
"port": "4000"
|
||||
},
|
||||
"lobe-chat": {
|
||||
@@ -3834,7 +3852,7 @@
|
||||
"opnform": {
|
||||
"documentation": "https://docs.opnform.com/introduction?utm_source=coolify.io",
|
||||
"slogan": "OpnForm is an open-source form builder that lets you create beautiful forms and share them anywhere. It's super fast, you don't need to know how to code",
|
||||
"compose": "eC1zaGFyZWQtZW52OgogIEFQUF9OQU1FOiBPcG5Gb3JtCiAgQVBQX0VOVjogcHJvZHVjdGlvbgogIEFQUF9LRVk6ICcke1NFUlZJQ0VfQkFTRTY0X0FQSUtFWX0nCiAgQVBQX0RFQlVHOiAnJHtBUFBfREVCVUc6LWZhbHNlfScKICBBUFBfVVJMOiAnJHtTRVJWSUNFX1VSTF9OR0lOWH0nCiAgTE9HX0NIQU5ORUw6IGVycm9ybG9nCiAgTE9HX0xFVkVMOiAnJHtMT0dfTEVWRUw6LWRlYnVnfScKICBGSUxFU1lTVEVNX0RSSVZFUjogJyR7RklMRVNZU1RFTV9EUklWRVI6LWxvY2FsfScKICBMT0NBTF9GSUxFU1lTVEVNX1ZJU0lCSUxJVFk6IHB1YmxpYwogIENBQ0hFX0RSSVZFUjogcmVkaXMKICBRVUVVRV9DT05ORUNUSU9OOiByZWRpcwogIFNFU1NJT05fRFJJVkVSOiByZWRpcwogIFNFU1NJT05fTElGRVRJTUU6IDEyMAogIE1BSUxfTUFJTEVSOiAnJHtNQUlMX01BSUxFUjotbG9nfScKICBNQUlMX0hPU1Q6ICcke01BSUxfSE9TVH0nCiAgTUFJTF9QT1JUOiAnJHtNQUlMX1BPUlR9JwogIE1BSUxfVVNFUk5BTUU6ICcke01BSUxfVVNFUk5BTUU6LXlvdXJAZW1haWwuY29tfScKICBNQUlMX1BBU1NXT1JEOiAnJHtNQUlMX1BBU1NXT1JEfScKICBNQUlMX0VOQ1JZUFRJT046ICcke01BSUxfRU5DUllQVElPTn0nCiAgTUFJTF9GUk9NX0FERFJFU1M6ICcke01BSUxfRlJPTV9BRERSRVNTOi15b3VyQGVtYWlsLmNvbX0nCiAgTUFJTF9GUk9NX05BTUU6ICcke01BSUxfRlJPTV9OQU1FOi1PcG5Gb3JtfScKICBBV1NfQUNDRVNTX0tFWV9JRDogJyR7QVdTX0FDQ0VTU19LRVlfSUR9JwogIEFXU19TRUNSRVRfQUNDRVNTX0tFWTogJyR7QVdTX1NFQ1JFVF9BQ0NFU1NfS0VZfScKICBBV1NfREVGQVVMVF9SRUdJT046ICcke0FXU19ERUZBVUxUX1JFR0lPTjotdXMtZWFzdC0xfScKICBBV1NfQlVDS0VUOiAnJHtBV1NfQlVDS0VUfScKICBPUEVOX0FJX0FQSV9LRVk6ICcke09QRU5fQUlfQVBJX0tFWX0nCiAgVEVMRUdSQU1fQk9UX0lEOiAnJHtURUxFR1JBTV9CT1RfSUR9JwogIFRFTEVHUkFNX0JPVF9UT0tFTjogJyR7VEVMRUdSQU1fQk9UX1RPS0VOfScKICBSRURJU19IT1NUOiByZWRpcwogIFJFRElTX1BBU1NXT1JEOiAnJHtTRVJWSUNFX1BBU1NXT1JEXzY0X1JFRElTfScKICBEQl9IT1NUOiBwb3N0Z3Jlc3FsCiAgREJfREFUQUJBU0U6ICcke1BPU1RHUkVTUUxfREFUQUJBU0U6LW9wbmZvcm19JwogIERCX1VTRVJOQU1FOiAnJHtTRVJWSUNFX1VTRVJfUE9TVEdSRVNRTH0nCiAgREJfUEFTU1dPUkQ6ICcke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVNRTH0nCiAgREJfQ09OTkVDVElPTjogcGdzcWwKICBQSFBfTUVNT1JZX0xJTUlUOiAxRwogIFBIUF9NQVhfRVhFQ1VUSU9OX1RJTUU6ICc2MDAnCiAgUEhQX1VQTE9BRF9NQVhfRklMRVNJWkU6IDY0TQogIFBIUF9QT1NUX01BWF9TSVpFOiA2NE0Kc2VydmljZXM6CiAgb3BuZm9ybS1hcGk6CiAgICBpbWFnZTogJ2podW1hbmovb3BuZm9ybS1hcGk6MS4xMi4xJwogICAgdm9sdW1lczoKICAgICAgLSAnYXBpLXN0b3JhZ2U6L3Vzci9zaGFyZS9uZ2lueC9odG1sL3N0b3JhZ2UnCiAgICBlbnZpcm9ubWVudDoKICAgICAgQVBQX05BTUU6IE9wbkZvcm0KICAgICAgQVBQX0VOVjogcHJvZHVjdGlvbgogICAgICBBUFBfS0VZOiAnJHtTRVJWSUNFX0JBU0U2NF9BUElLRVl9JwogICAgICBBUFBfREVCVUc6ICcke0FQUF9ERUJVRzotZmFsc2V9JwogICAgICBBUFBfVVJMOiAnJHtTRVJWSUNFX1VSTF9OR0lOWH0nCiAgICAgIExPR19DSEFOTkVMOiBlcnJvcmxvZwogICAgICBMT0dfTEVWRUw6ICcke0xPR19MRVZFTDotZGVidWd9JwogICAgICBGSUxFU1lTVEVNX0RSSVZFUjogJyR7RklMRVNZU1RFTV9EUklWRVI6LWxvY2FsfScKICAgICAgTE9DQUxfRklMRVNZU1RFTV9WSVNJQklMSVRZOiBwdWJsaWMKICAgICAgQ0FDSEVfRFJJVkVSOiByZWRpcwogICAgICBRVUVVRV9DT05ORUNUSU9OOiByZWRpcwogICAgICBTRVNTSU9OX0RSSVZFUjogcmVkaXMKICAgICAgU0VTU0lPTl9MSUZFVElNRTogMTIwCiAgICAgIE1BSUxfTUFJTEVSOiAnJHtNQUlMX01BSUxFUjotbG9nfScKICAgICAgTUFJTF9IT1NUOiAnJHtNQUlMX0hPU1R9JwogICAgICBNQUlMX1BPUlQ6ICcke01BSUxfUE9SVH0nCiAgICAgIE1BSUxfVVNFUk5BTUU6ICcke01BSUxfVVNFUk5BTUU6LXlvdXJAZW1haWwuY29tfScKICAgICAgTUFJTF9QQVNTV09SRDogJyR7TUFJTF9QQVNTV09SRH0nCiAgICAgIE1BSUxfRU5DUllQVElPTjogJyR7TUFJTF9FTkNSWVBUSU9OfScKICAgICAgTUFJTF9GUk9NX0FERFJFU1M6ICcke01BSUxfRlJPTV9BRERSRVNTOi15b3VyQGVtYWlsLmNvbX0nCiAgICAgIE1BSUxfRlJPTV9OQU1FOiAnJHtNQUlMX0ZST01fTkFNRTotT3BuRm9ybX0nCiAgICAgIEFXU19BQ0NFU1NfS0VZX0lEOiAnJHtBV1NfQUNDRVNTX0tFWV9JRH0nCiAgICAgIEFXU19TRUNSRVRfQUNDRVNTX0tFWTogJyR7QVdTX1NFQ1JFVF9BQ0NFU1NfS0VZfScKICAgICAgQVdTX0RFRkFVTFRfUkVHSU9OOiAnJHtBV1NfREVGQVVMVF9SRUdJT046LXVzLWVhc3QtMX0nCiAgICAgIEFXU19CVUNLRVQ6ICcke0FXU19CVUNLRVR9JwogICAgICBPUEVOX0FJX0FQSV9LRVk6ICcke09QRU5fQUlfQVBJX0tFWX0nCiAgICAgIFRFTEVHUkFNX0JPVF9JRDogJyR7VEVMRUdSQU1fQk9UX0lEfScKICAgICAgVEVMRUdSQU1fQk9UX1RPS0VOOiAnJHtURUxFR1JBTV9CT1RfVE9LRU59JwogICAgICBSRURJU19IT1NUOiByZWRpcwogICAgICBSRURJU19QQVNTV09SRDogJyR7U0VSVklDRV9QQVNTV09SRF82NF9SRURJU30nCiAgICAgIERCX0hPU1Q6IHBvc3RncmVzcWwKICAgICAgREJfREFUQUJBU0U6ICcke1BPU1RHUkVTUUxfREFUQUJBU0U6LW9wbmZvcm19JwogICAgICBEQl9VU0VSTkFNRTogJyR7U0VSVklDRV9VU0VSX1BPU1RHUkVTUUx9JwogICAgICBEQl9QQVNTV09SRDogJyR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU1FMfScKICAgICAgREJfQ09OTkVDVElPTjogcGdzcWwKICAgICAgUEhQX01FTU9SWV9MSU1JVDogMUcKICAgICAgUEhQX01BWF9FWEVDVVRJT05fVElNRTogJzYwMCcKICAgICAgUEhQX1VQTE9BRF9NQVhfRklMRVNJWkU6IDY0TQogICAgICBQSFBfUE9TVF9NQVhfU0laRTogNjRNCiAgICAgIEpXVF9UVEw6ICcke0pXVF9UVEw6LTE0NDB9JwogICAgICBKV1RfU0VDUkVUOiAnJHtTRVJWSUNFX1BBU1NXT1JEX0pXVFNFQ1JFVH0nCiAgICAgIEpXVF9TS0lQX0lQX1VBX1ZBTElEQVRJT046ICcke0pXVF9TS0lQX0lQX1VBX1ZBTElEQVRJT046LXRydWV9JwogICAgICBIX0NBUFRDSEFfU0lURV9LRVk6ICcke0hfQ0FQVENIQV9TSVRFX0tFWX0nCiAgICAgIEhfQ0FQVENIQV9TRUNSRVRfS0VZOiAnJHtIX0NBUFRDSEFfU0VDUkVUX0tFWX0nCiAgICAgIFJFX0NBUFRDSEFfU0lURV9LRVk6ICcke1JFX0NBUFRDSEFfU0lURV9LRVl9JwogICAgICBSRV9DQVBUQ0hBX1NFQ1JFVF9LRVk6ICcke1JFX0NBUFRDSEFfU0VDUkVUX0tFWX0nCiAgICAgIFNIT1dfT0ZGSUNJQUxfVEVNUExBVEVTOiAnJHtTSE9XX09GRklDSUFMX1RFTVBMQVRFUzotdHJ1ZX0nCiAgICBkZXBlbmRzX29uOgogICAgICBwb3N0Z3Jlc3FsOgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9oZWFsdGh5CiAgICAgIHJlZGlzOgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9oZWFsdGh5CiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gJ3BocCAvdXNyL3NoYXJlL25Line truncated
|
||||
"compose": "eC1zaGFyZWQtZW52OgogIEFQUF9OQU1FOiBPcG5Gb3JtCiAgQVBQX0VOVjogcHJvZHVjdGlvbgogIEFQUF9LRVk6ICcke1NFUlZJQ0VfQkFTRTY0X0FQSUtFWX0nCiAgQVBQX0RFQlVHOiAnJHtBUFBfREVCVUc6LWZhbHNlfScKICBBUFBfVVJMOiAnJHtTRVJWSUNFX1VSTF9OR0lOWH0nCiAgTE9HX0NIQU5ORUw6IGVycm9ybG9nCiAgTE9HX0xFVkVMOiAnJHtMT0dfTEVWRUw6LWRlYnVnfScKICBGSUxFU1lTVEVNX0RSSVZFUjogJyR7RklMRVNZU1RFTV9EUklWRVI6LWxvY2FsfScKICBMT0NBTF9GSUxFU1lTVEVNX1ZJU0lCSUxJVFk6IHB1YmxpYwogIENBQ0hFX0RSSVZFUjogcmVkaXMKICBRVUVVRV9DT05ORUNUSU9OOiByZWRpcwogIFNFU1NJT05fRFJJVkVSOiByZWRpcwogIFNFU1NJT05fTElGRVRJTUU6IDEyMAogIE1BSUxfTUFJTEVSOiAnJHtNQUlMX01BSUxFUjotbG9nfScKICBNQUlMX0hPU1Q6ICcke01BSUxfSE9TVH0nCiAgTUFJTF9QT1JUOiAnJHtNQUlMX1BPUlR9JwogIE1BSUxfVVNFUk5BTUU6ICcke01BSUxfVVNFUk5BTUU6LXlvdXJAZW1haWwuY29tfScKICBNQUlMX1BBU1NXT1JEOiAnJHtNQUlMX1BBU1NXT1JEfScKICBNQUlMX0VOQ1JZUFRJT046ICcke01BSUxfRU5DUllQVElPTn0nCiAgTUFJTF9GUk9NX0FERFJFU1M6ICcke01BSUxfRlJPTV9BRERSRVNTOi15b3VyQGVtYWlsLmNvbX0nCiAgTUFJTF9GUk9NX05BTUU6ICcke01BSUxfRlJPTV9OQU1FOi1PcG5Gb3JtfScKICBBV1NfQUNDRVNTX0tFWV9JRDogJyR7QVdTX0FDQ0VTU19LRVlfSUR9JwogIEFXU19TRUNSRVRfQUNDRVNTX0tFWTogJyR7QVdTX1NFQ1JFVF9BQ0NFU1NfS0VZfScKICBBV1NfREVGQVVMVF9SRUdJT046ICcke0FXU19ERUZBVUxUX1JFR0lPTjotdXMtZWFzdC0xfScKICBBV1NfQlVDS0VUOiAnJHtBV1NfQlVDS0VUfScKICBPUEVOX0FJX0FQSV9LRVk6ICcke09QRU5fQUlfQVBJX0tFWX0nCiAgVEVMRUdSQU1fQk9UX0lEOiAnJHtURUxFR1JBTV9CT1RfSUR9JwogIFRFTEVHUkFNX0JPVF9UT0tFTjogJyR7VEVMRUdSQU1fQk9UX1RPS0VOfScKICBSRURJU19IT1NUOiByZWRpcwogIFJFRElTX1BBU1NXT1JEOiAnJHtTRVJWSUNFX1BBU1NXT1JEXzY0X1JFRElTfScKICBEQl9IT1NUOiBwb3N0Z3Jlc3FsCiAgREJfREFUQUJBU0U6ICcke1BPU1RHUkVTUUxfREFUQUJBU0U6LW9wbmZvcm19JwogIERCX1VTRVJOQU1FOiAnJHtTRVJWSUNFX1VTRVJfUE9TVEdSRVNRTH0nCiAgREJfUEFTU1dPUkQ6ICcke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVNRTH0nCiAgREJfQ09OTkVDVElPTjogcGdzcWwKICBQSFBfTUVNT1JZX0xJTUlUOiAxRwogIFBIUF9NQVhfRVhFQ1VUSU9OX1RJTUU6ICc2MDAnCiAgUEhQX1VQTE9BRF9NQVhfRklMRVNJWkU6IDY0TQogIFBIUF9QT1NUX01BWF9TSVpFOiA2NE0KICBGUk9OVF9VUkw6ICcke1NFUlZJQ0VfVVJMX05HSU5YfScKICBGUk9OVF9BUElfU0VDUkVUOiAnJHtTRVJWSUNFX1BBU1NXT1JEX0ZST05UQVBJU0VDUkVUfScKICBQVUJMSUNfVVBMT0FEU19SQVRFX0xJTUlUX1BFUl9NSU5VVEU6ICcke1BVQkxJQ19VUExPQURTX1JBVEVfTElNSVRfUEVSX01JTlVURTotMzB9JwogIFBVQkxJQ19VUExPQURTX1JBVEVfTElNSVRfUEVSX0hPVVI6ICcke1BVQkxJQ19VUExPQURTX1JBVEVfTElNSVRfUEVSX0hPVVI6LTMwMH0nCnNlcnZpY2VzOgogIG9wbmZvcm0tYXBpOgogICAgaW1hZ2U6ICdqaHVtYW5qL29wbmZvcm0tYXBpOjIuMi40JwogICAgdm9sdW1lczoKICAgICAgLSAnYXBpLXN0b3JhZ2U6L3Vzci9zaGFyZS9uZ2lueC9odG1sL3N0b3JhZ2UnCiAgICBlbnZpcm9ubWVudDoKICAgICAgQVBQX05BTUU6IE9wbkZvcm0KICAgICAgQVBQX0VOVjogcHJvZHVjdGlvbgogICAgICBBUFBfS0VZOiAnJHtTRVJWSUNFX0JBU0U2NF9BUElLRVl9JwogICAgICBBUFBfREVCVUc6ICcke0FQUF9ERUJVRzotZmFsc2V9JwogICAgICBBUFBfVVJMOiAnJHtTRVJWSUNFX1VSTF9OR0lOWH0nCiAgICAgIExPR19DSEFOTkVMOiBlcnJvcmxvZwogICAgICBMT0dfTEVWRUw6ICcke0xPR19MRVZFTDotZGVidWd9JwogICAgICBGSUxFU1lTVEVNX0RSSVZFUjogJyR7RklMRVNZU1RFTV9EUklWRVI6LWxvY2FsfScKICAgICAgTE9DQUxfRklMRVNZU1RFTV9WSVNJQklMSVRZOiBwdWJsaWMKICAgICAgQ0FDSEVfRFJJVkVSOiByZWRpcwogICAgICBRVUVVRV9DT05ORUNUSU9OOiByZWRpcwogICAgICBTRVNTSU9OX0RSSVZFUjogcmVkaXMKICAgICAgU0VTU0lPTl9MSUZFVElNRTogMTIwCiAgICAgIE1BSUxfTUFJTEVSOiAnJHtNQUlMX01BSUxFUjotbG9nfScKICAgICAgTUFJTF9IT1NUOiAnJHtNQUlMX0hPU1R9JwogICAgICBNQUlMX1BPUlQ6ICcke01BSUxfUE9SVH0nCiAgICAgIE1BSUxfVVNFUk5BTUU6ICcke01BSUxfVVNFUk5BTUU6LXlvdXJAZW1haWwuY29tfScKICAgICAgTUFJTF9QQVNTV09SRDogJyR7TUFJTF9QQVNTV09SRH0nCiAgICAgIE1BSUxfRU5DUllQVElPTjogJyR7TUFJTF9FTkNSWVBUSU9OfScKICAgICAgTUFJTF9GUk9NX0FERFJFU1M6ICcke01BSUxfRlJPTV9BRERSRVNTOi15b3VyQGVtYWlsLmNvbX0nCiAgICAgIE1BSUxfRlJPTV9OQU1FOiAnJHtNQUlMX0ZST01fTkFNRTotT3BuRm9ybX0nCiAgICAgIEFXU19BQ0NFU1NfS0VZX0lEOiAnJHtBV1NfQUNDRVNTX0tFWV9JRH0nCiAgICAgIEFXU19TRUNSRVRfQUNDRVNTX0tFWTogJyR7QVdTX1NFQ1JFVF9BQ0NFU1NfS0VZfScKICAgICAgQVdTX0RFRkFVTFRfUkVHSU9OOiAnJHtBV1NfREVGQVVMVF9SRUdJT046LXVzLWVhc3QtMX0nCiAgICAgIEFXU19CVUNLRVQ6ICcke0FXU19CVUNLRVR9JwogICAgICBPUEVOX0FJX0FQSV9LRVk6ICcke09QRU5fQUlfQVBJX0tFWX0nCiAgICAgIFRFTEVHUkFNX0JPVF9JRDogJyR7VEVMRUdSQU1fQk9UX0lEfScKICAgICAgVEVMRUdSQU1fQk9UX1RPS0VOOiAnJHtURUxFR1JBTV9CT1RfVE9LRU59JwogICAgICBSRURJU19IT1NUOiByZWRpcwogICAgICBSRURJU19QQVNTV09SRDogJyR7U0VSVklDRV9QQVNTV09SRF82NF9SRURJU30nCiAgICAgIERCX0hPU1Q6IHBvc3RncmVzcWwKICAgICAgREJfREFUQUJBU0U6ICcke1BPU1RHUkVTUUxfREFUQUJBU0U6LW9wbmZvcm19JwogICAgICBEQl9VU0VSTkFNRTogJyR7U0VSVklDRV9VU0VSX1BPU1RHUkVTUUx9JwogICAgICBEQl9QQVNTV09SRDogJyR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU1FMfScKICAgICAgREJfQ09OTkVDVElPTjogcGdzcWwKICAgICAgUEhQX01FTU9SWV9MSU1JVDogMUcKICAgICAgUEhQX01BWF9FWEVDVVRJT05fVElNRTogJzYwMCcKICAgICAgUEhQX1VQTE9BRF9NQVhfRklMRVNJWkU6IDY0TQogICAgICBQSFBfUE9TVF9NQVhfU0laRTogNjRNCiAgICAgIEZST05UX1VSTDogJyR7U0VSVklDRV9VUkxfTkdJTlh9JwogICAgICBGUk9OVF9BUElfU0VDUkVUOiAnJHtTRVJWSUNFX1BBU1NXT1JEX0ZST05UQVBJU0VDUkVUfScKICAgICAgUFVCTElDX1VQTE9BRFNfUkFURV9MSU1JVF9QRVJfTUlOVVRFOiAnJHtQVUJMSUNfVVBMT0FEU19SQVRFX0xJTUlUX1BFUl9NSU5VVEU6LTMwfScKICAgICAgUFVCTElDX1VQTE9BRFNfUkFURV9MSU1JVF9QRVJfSE9VUjogJyR7UFVCTElDX1VQTE9BRFNfUkFURV9MSU1JVF9QRVJfSE9VUjotMzAwfScKICAgICAgSldUX1RUTDogJyR7SldUX1RUTDotMTQ0MH0nCiAgICAgIEpXVF9TRUNSRVQ6ICcke1NFUlZJQ0VfUEFTU1dPUkRfSldUU0VDUkVUfScKICALine truncated
|
||||
"tags": [
|
||||
"opnform",
|
||||
"form",
|
||||
@@ -3849,7 +3867,7 @@
|
||||
"category": "productivity",
|
||||
"logo": "svg/opnform.svg",
|
||||
"minversion": "0.0.0",
|
||||
"template_last_updated_at": "2026-04-06T11:35:16-05:00",
|
||||
"template_last_updated_at": "2026-08-10T12:49:29+02:00",
|
||||
"port": "80"
|
||||
},
|
||||
"orangehrm": {
|
||||
@@ -4601,7 +4619,7 @@
|
||||
"seaweedfs": {
|
||||
"documentation": "https://github.com/seaweedfs/seaweedfs?utm_source=coolify.io",
|
||||
"slogan": "SeaweedFS is a simple and highly scalable distributed file system. Compatible with S3, with an admin web interface.",
|
||||
"compose": "c2VydmljZXM6CiAgc2Vhd2VlZGZzLW1hc3RlcjoKICAgIGltYWdlOiAnY2hyaXNsdXNmL3NlYXdlZWRmczo0LjEzJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9VUkxfUzNfODMzMwogICAgICAtICdBV1NfQUNDRVNTX0tFWV9JRD0ke1NFUlZJQ0VfVVNFUl9TM30nCiAgICAgIC0gJ0FXU19TRUNSRVRfQUNDRVNTX0tFWT0ke1NFUlZJQ0VfUEFTU1dPUkRfUzN9JwogICAgdm9sdW1lczoKICAgICAgLSAnc2Vhd2VlZGZzLXMzLWRhdGE6L2RhdGEnCiAgICAgIC0KICAgICAgICB0eXBlOiBiaW5kCiAgICAgICAgc291cmNlOiAuL2Jhc2UtY29uZmlnLmpzb24KICAgICAgICB0YXJnZXQ6IC9iYXNlLWNvbmZpZy5qc29uCiAgICAgICAgY29udGVudDogIntcbiAgXCJpZGVudGl0aWVzXCI6IFtcbiAgICB7XG4gICAgICBcIm5hbWVcIjogXCJhbm9ueW1vdXNcIixcbiAgICAgIFwiYWN0aW9uc1wiOiBbXG4gICAgICAgIFwiUmVhZFwiXG4gICAgICBdXG4gICAgfSxcbiAgICB7XG4gICAgICBcIm5hbWVcIjogXCJhZG1pblwiLFxuICAgICAgXCJjcmVkZW50aWFsc1wiOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBcImFjY2Vzc0tleVwiOiBcImVudjpBV1NfQUNDRVNTX0tFWV9JRFwiLFxuICAgICAgICAgIFwic2VjcmV0S2V5XCI6IFwiZW52OkFXU19TRUNSRVRfQUNDRVNTX0tFWVwiXG4gICAgICAgIH1cbiAgICAgIF0sXG4gICAgICBcImFjdGlvbnNcIjogW1xuICAgICAgICBcIkFkbWluXCIsXG4gICAgICAgIFwiUmVhZFwiLFxuICAgICAgICBcIlJlYWRBY3BcIixcbiAgICAgICAgXCJMaXN0XCIsXG4gICAgICAgIFwiVGFnZ2luZ1wiLFxuICAgICAgICBcIldyaXRlXCIsXG4gICAgICAgIFwiV3JpdGVBY3BcIlxuICAgICAgXVxuICAgIH1cbiAgXVxufVxuIgogICAgZW50cnlwb2ludDogInNoIC1jICdcXFxuc2VkIFwicy9lbnY6QVdTX0FDQ0VTU19LRVlfSUQvJEFXU19BQ0NFU1NfS0VZX0lEL2dcIiAvYmFzZS1jb25maWcuanNvbiA+IC9iYXNlMS1jb25maWcuanNvbjsgXFxcbnNlZCBcInMvZW52OkFXU19TRUNSRVRfQUNDRVNTX0tFWS8kQVdTX1NFQ1JFVF9BQ0NFU1NfS0VZL2dcIiAvYmFzZTEtY29uZmlnLmpzb24gPiAvY29uZmlnLmpzb247IFxcXG53ZWVkIHNlcnZlciAtZGlyPS9kYXRhIC1tYXN0ZXIucG9ydD05MzMzIC1zMyAtczMucG9ydD04MzMzIC1zMy5jb25maWc9L2NvbmZpZy5qc29uXFxcbidcbiIKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ELVNIRUxMCiAgICAgICAgLSAnd2dldCAtLXNwaWRlciAtcSBodHRwOi8vMC4wLjAuMDo4MzMzOyBbICQkPyAtbGUgOCBdJwogICAgICBpbnRlcnZhbDogMTBzCiAgICAgIHRpbWVvdXQ6IDVzCiAgICAgIHJldHJpZXM6IDEwCiAgc2Vhd2VlZGZzLWFkbWluOgogICAgaW1hZ2U6ICdjaHJpc2x1c2Yvc2Vhd2VlZGZzOjQuMTMnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTRVJWSUNFX1VSTF9BRE1JTl8yMzY0NgogICAgICAtICdTRUFXRUVEX1VTRVJfQURNSU49JHtTRVJWSUNFX1VTRVJfQURNSU59JwogICAgICAtICdTRUFXRUVEX1BBU1NXT1JEX0FETUlOPSR7U0VSVklDRV9QQVNTV09SRF9BRE1JTn0nCiAgICBjb21tYW5kOgogICAgICAtIGFkbWluCiAgICAgIC0gJy1tYXN0ZXI9c2Vhd2VlZGZzLW1hc3Rlcjo5MzMzJwogICAgICAtICctYWRtaW5Vc2VyPSR7U0VBV0VFRF9VU0VSX0FETUlOfScKICAgICAgLSAnLWFkbWluUGFzc3dvcmQ9JHtTRUFXRUVEX1BBU1NXT1JEX0FETUlOfScKICAgICAgLSAnLXBvcnQ9MjM2NDYnCiAgICAgIC0gJy1kYXRhRGlyPS9kYXRhJwogICAgdm9sdW1lczoKICAgICAgLSAnc2Vhd2VlZGZzLWFkbWluLWRhdGE6L2RhdGEnCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gJ3dnZXQgLS1zcGlkZXIgLXEgaHR0cDovLzAuMC4wLjA6MjM2NDY7IFsgJCQ/IC1sZSA4IF0nCiAgICAgIGludGVydmFsOiAxMHMKICAgICAgdGltZW91dDogNXMKICAgICAgcmV0cmllczogMTAKICAgIGRlcGVuZHNfb246CiAgICAgIHNlYXdlZWRmcy1tYXN0ZXI6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkK",
|
||||
"compose": "c2VydmljZXM6CiAgc2Vhd2VlZGZzLW1hc3RlcjoKICAgIGltYWdlOiAnY2hyaXNsdXNmL3NlYXdlZWRmczo0LjQxJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9VUkxfUzNfODMzMwogICAgICAtICdBV1NfQUNDRVNTX0tFWV9JRD0ke1NFUlZJQ0VfVVNFUl9TM30nCiAgICAgIC0gJ0FXU19TRUNSRVRfQUNDRVNTX0tFWT0ke1NFUlZJQ0VfUEFTU1dPUkRfUzN9JwogICAgdm9sdW1lczoKICAgICAgLSAnc2Vhd2VlZGZzLXMzLWRhdGE6L2RhdGEnCiAgICAgIC0KICAgICAgICB0eXBlOiBiaW5kCiAgICAgICAgc291cmNlOiAuL2Jhc2UtY29uZmlnLmpzb24KICAgICAgICB0YXJnZXQ6IC9iYXNlLWNvbmZpZy5qc29uCiAgICAgICAgY29udGVudDogIntcbiAgXCJpZGVudGl0aWVzXCI6IFtcbiAgICB7XG4gICAgICBcIm5hbWVcIjogXCJhbm9ueW1vdXNcIixcbiAgICAgIFwiYWN0aW9uc1wiOiBbXG4gICAgICAgIFwiUmVhZFwiXG4gICAgICBdXG4gICAgfSxcbiAgICB7XG4gICAgICBcIm5hbWVcIjogXCJhZG1pblwiLFxuICAgICAgXCJjcmVkZW50aWFsc1wiOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBcImFjY2Vzc0tleVwiOiBcImVudjpBV1NfQUNDRVNTX0tFWV9JRFwiLFxuICAgICAgICAgIFwic2VjcmV0S2V5XCI6IFwiZW52OkFXU19TRUNSRVRfQUNDRVNTX0tFWVwiXG4gICAgICAgIH1cbiAgICAgIF0sXG4gICAgICBcImFjdGlvbnNcIjogW1xuICAgICAgICBcIkFkbWluXCIsXG4gICAgICAgIFwiUmVhZFwiLFxuICAgICAgICBcIlJlYWRBY3BcIixcbiAgICAgICAgXCJMaXN0XCIsXG4gICAgICAgIFwiVGFnZ2luZ1wiLFxuICAgICAgICBcIldyaXRlXCIsXG4gICAgICAgIFwiV3JpdGVBY3BcIlxuICAgICAgXVxuICAgIH1cbiAgXVxufVxuIgogICAgZW50cnlwb2ludDogInNoIC1jICdcXFxuc2VkIFwicy9lbnY6QVdTX0FDQ0VTU19LRVlfSUQvJEFXU19BQ0NFU1NfS0VZX0lEL2dcIiAvYmFzZS1jb25maWcuanNvbiA+IC9iYXNlMS1jb25maWcuanNvbjsgXFxcbnNlZCBcInMvZW52OkFXU19TRUNSRVRfQUNDRVNTX0tFWS8kQVdTX1NFQ1JFVF9BQ0NFU1NfS0VZL2dcIiAvYmFzZTEtY29uZmlnLmpzb24gPiAvY29uZmlnLmpzb247IFxcXG53ZWVkIHNlcnZlciAtZGlyPS9kYXRhIC1tYXN0ZXIucG9ydD05MzMzIC1zMyAtczMucG9ydD04MzMzIC1zMy5jb25maWc9L2NvbmZpZy5qc29uXFxcbidcbiIKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ELVNIRUxMCiAgICAgICAgLSAnd2dldCAtLXNwaWRlciAtcSBodHRwOi8vMC4wLjAuMDo4MzMzOyBbICQkPyAtbGUgOCBdJwogICAgICBpbnRlcnZhbDogMTBzCiAgICAgIHRpbWVvdXQ6IDVzCiAgICAgIHJldHJpZXM6IDEwCiAgc2Vhd2VlZGZzLWFkbWluOgogICAgaW1hZ2U6ICdjaHJpc2x1c2Yvc2Vhd2VlZGZzOjQuNDEnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTRVJWSUNFX1VSTF9BRE1JTl8yMzY0NgogICAgICAtICdTRUFXRUVEX1VTRVJfQURNSU49JHtTRVJWSUNFX1VTRVJfQURNSU59JwogICAgICAtICdTRUFXRUVEX1BBU1NXT1JEX0FETUlOPSR7U0VSVklDRV9QQVNTV09SRF9BRE1JTn0nCiAgICBjb21tYW5kOgogICAgICAtIGFkbWluCiAgICAgIC0gJy1tYXN0ZXI9c2Vhd2VlZGZzLW1hc3Rlcjo5MzMzJwogICAgICAtICctYWRtaW5Vc2VyPSR7U0VBV0VFRF9VU0VSX0FETUlOfScKICAgICAgLSAnLWFkbWluUGFzc3dvcmQ9JHtTRUFXRUVEX1BBU1NXT1JEX0FETUlOfScKICAgICAgLSAnLXBvcnQ9MjM2NDYnCiAgICAgIC0gJy1kYXRhRGlyPS9kYXRhJwogICAgdm9sdW1lczoKICAgICAgLSAnc2Vhd2VlZGZzLWFkbWluLWRhdGE6L2RhdGEnCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gJ3dnZXQgLS1zcGlkZXIgLXEgaHR0cDovLzAuMC4wLjA6MjM2NDY7IFsgJCQ/IC1sZSA4IF0nCiAgICAgIGludGVydmFsOiAxMHMKICAgICAgdGltZW91dDogNXMKICAgICAgcmV0cmllczogMTAKICAgIGRlcGVuZHNfb246CiAgICAgIHNlYXdlZWRmcy1tYXN0ZXI6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkK",
|
||||
"tags": [
|
||||
"object",
|
||||
"storage",
|
||||
@@ -4612,7 +4630,7 @@
|
||||
"category": "storage",
|
||||
"logo": "svgs/seaweedfs.svg",
|
||||
"minversion": "0.0.0",
|
||||
"template_last_updated_at": "2026-03-02T20:04:29-03:00",
|
||||
"template_last_updated_at": "2026-08-10T11:21:26+02:00",
|
||||
"port": "8333"
|
||||
},
|
||||
"sequin": {
|
||||
@@ -4855,7 +4873,7 @@
|
||||
"sparkyfitness": {
|
||||
"documentation": "https://codewithcj.github.io/SparkyFitness/?utm_source=coolify.io",
|
||||
"slogan": "SparkyFitness is a comprehensive fitness tracking and management application designed to help users monitor their nutrition, exercise, and body measurements. It provides tools for daily progress tracking, goal setting, and insightful reports to support a healthy lifestyle.",
|
||||
"compose": "c2VydmljZXM6CiAgc3Bhcmt5Zml0bmVzcy1mcm9udGVuZDoKICAgIGltYWdlOiAnY29kZXdpdGhjai9zcGFya3lmaXRuZXNzOnYwLjE1LjcuMycKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfVVJMX1NQQVJLWUZJVE5FU1NfODAKICAgIGRlcGVuZHNfb246CiAgICAgIC0gc3Bhcmt5Zml0bmVzcy1zZXJ2ZXIKICBzcGFya3lmaXRuZXNzLXNlcnZlcjoKICAgIGltYWdlOiAnY29kZXdpdGhjai9zcGFya3lmaXRuZXNzX3NlcnZlcjp2MC4xNS43LjMnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSAnU1BBUktZX0ZJVE5FU1NfTE9HX0xFVkVMPSR7U1BBUktZX0ZJVE5FU1NfTE9HX0xFVkVMOi1pbmZvfScKICAgICAgLSAnU1BBUktZX0ZJVE5FU1NfREJfVVNFUj0ke1NFUlZJQ0VfVVNFUl9QT1NUR1JFU30nCiAgICAgIC0gU1BBUktZX0ZJVE5FU1NfREJfSE9TVD1zcGFya3lmaXRuZXNzLWRiCiAgICAgIC0gJ1NQQVJLWV9GSVRORVNTX0RCX05BTUU9JHtTUEFSS1lfRklUTkVTU19EQl9OQU1FOi1zcGFya3lmaXRuZXNzfScKICAgICAgLSAnU1BBUktZX0ZJVE5FU1NfREJfUEFTU1dPUkQ9JHtTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTfScKICAgICAgLSAnU1BBUktZX0ZJVE5FU1NfREJfUE9SVD0ke1NQQVJLWV9GSVRORVNTX0RCX1BPUlQ6LTU0MzJ9JwogICAgICAtICdTUEFSS1lfRklUTkVTU19BUElfRU5DUllQVElPTl9LRVk9JHtTRVJWSUNFX1BBU1NXT1JEXzY0X1NFUlZFUkFQSUVOQ1JZUFRJT05LRVl9JwogICAgICAtICdKV1RfU0VDUkVUPSR7U0VSVklDRV9QQVNTV09SRF82NF9TRVJWRVJKV1RTRUNSRVR9JwogICAgICAtICdTUEFSS1lfRklUTkVTU19GUk9OVEVORF9VUkw9JHtTRVJWSUNFX1VSTF9TUEFSS1lGSVRORVNTXzgwfScKICAgICAgLSAnU1BBUktZX0ZJVE5FU1NfRElTQUJMRV9TSUdOVVA9JHtTUEFSS1lfRklUTkVTU19ESVNBQkxFX1NJR05VUDotZmFsc2V9JwogICAgICAtICdTUEFSS1lfRklUTkVTU19BRE1JTl9FTUFJTD0ke1NQQVJLWV9GSVRORVNTX0FETUlOX0VNQUlMOi1hZG1pbkBleGFtcGxlLmNvbX0nCiAgICAgIC0gJ1NQQVJLWV9GSVRORVNTX0VNQUlMX0hPU1Q9JHtTUEFSS1lfRklUTkVTU19FTUFJTF9IT1NUOi1zbXRwLmdtYWlsLmNvbX0nCiAgICAgIC0gJ1NQQVJLWV9GSVRORVNTX0VNQUlMX1BPUlQ9JHtTUEFSS1lfRklUTkVTU19FTUFJTF9QT1JUOi01ODd9JwogICAgICAtICdTUEFSS1lfRklUTkVTU19FTUFJTF9TRUNVUkU9JHtTUEFSS1lfRklUTkVTU19FTUFJTF9TRUNVUkU6LWZhbHNlfScKICAgICAgLSAnU1BBUktZX0ZJVE5FU1NfRU1BSUxfVVNFUj0ke1NQQVJLWV9GSVRORVNTX0VNQUlMX1VTRVJ9JwogICAgICAtICdTUEFSS1lfRklUTkVTU19FTUFJTF9QQVNTPSR7U1BBUktZX0ZJVE5FU1NfRU1BSUxfUEFTU30nCiAgICAgIC0gJ1NQQVJLWV9GSVRORVNTX0VNQUlMX0ZST009JHtTUEFSS1lfRklUTkVTU19FTUFJTF9GUk9NOi0iU3Bhcmt5IEZpdG5lc3MgPG5vcmVwbHlAc3Bhcmt5Zml0bmVzcy5jb20+In0nCiAgICBkZXBlbmRzX29uOgogICAgICAtIHNwYXJreWZpdG5lc3MtZGIKICAgIHZvbHVtZXM6CiAgICAgIC0gJ3NwYXJreWZpdG5lc3Mtc2VydmVyLWJhY2t1cDovYXBwL1NwYXJreUZpdG5lc3NTZXJ2ZXIvYmFja3VwJwogICAgICAtICdzcGFya3lmaXRuZXNzLXNlcnZlci11cGxvYWRzOi9hcHAvU3Bhcmt5Rml0bmVzc1NlcnZlci91cGxvYWRzJwogIHNwYXJreWZpdG5lc3MtZGI6CiAgICBpbWFnZTogJ3Bvc3RncmVzOjE1LWFscGluZScKICAgIGVudmlyb25tZW50OgogICAgICAtICdQT1NUR1JFU19EQj0ke1NQQVJLWV9GSVRORVNTX0RCX05BTUU6LXNwYXJreWZpdG5lc3N9JwogICAgICAtICdQT1NUR1JFU19VU0VSPSR7U0VSVklDRV9VU0VSX1BPU1RHUkVTfScKICAgICAgLSAnUE9TVEdSRVNfUEFTU1dPUkQ9JHtTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTfScKICAgICAgLSAnUE9TVEdSRVNfUE9SVD0ke1NQQVJLWV9GSVRORVNTX0RCX1BPUlQ6LTU0MzJ9JwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQtU0hFTEwKICAgICAgICAtICdwZ19pc3JlYWR5IC1VICQke1BPU1RHUkVTX1VTRVJ9IC1kICQke1BPU1RHUkVTX0RCfScKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHRpbWVvdXQ6IDIwcwogICAgICByZXRyaWVzOiAxMAogICAgdm9sdW1lczoKICAgICAgLSAnc3Bhcmt5Zml0bmVzcy1kYi1wb3N0Z3Jlc3FsOi92YXIvbGliL3Bvc3RncmVzcWwvZGF0YScK",
|
||||
"compose": "c2VydmljZXM6CiAgc3Bhcmt5Zml0bmVzcy1mcm9udGVuZDoKICAgIGltYWdlOiAnY29kZXdpdGhjai9zcGFya3lmaXRuZXNzOnYxLjYuMScKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfVVJMX1NQQVJLWUZJVE5FU1NfODAKICAgICAgLSAnU1BBUktZX0ZJVE5FU1NfRlJPTlRFTkRfVVJMPSR7U0VSVklDRV9VUkxfU1BBUktZRklUTkVTU184MH0nCiAgICAgIC0gU1BBUktZX0ZJVE5FU1NfU0VSVkVSX0hPU1Q9c3Bhcmt5Zml0bmVzcy1zZXJ2ZXIKICAgICAgLSBTUEFSS1lfRklUTkVTU19TRVJWRVJfUE9SVD0zMDEwCiAgICBkZXBlbmRzX29uOgogICAgICAtIHNwYXJreWZpdG5lc3Mtc2VydmVyCiAgc3Bhcmt5Zml0bmVzcy1zZXJ2ZXI6CiAgICBpbWFnZTogJ2NvZGV3aXRoY2ovc3Bhcmt5Zml0bmVzc19zZXJ2ZXI6djEuNi4xJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ1NQQVJLWV9GSVRORVNTX0xPR19MRVZFTD0ke1NQQVJLWV9GSVRORVNTX0xPR19MRVZFTDotaW5mb30nCiAgICAgIC0gJ05PREVfRU5WPSR7Tk9ERV9FTlY6LXByb2R1Y3Rpb259JwogICAgICAtICdUWj0ke1RaOi1FdGMvVVRDfScKICAgICAgLSAnU1BBUktZX0ZJVE5FU1NfREJfVVNFUj0ke1NFUlZJQ0VfVVNFUl9QT1NUR1JFU30nCiAgICAgIC0gU1BBUktZX0ZJVE5FU1NfREJfSE9TVD1zcGFya3lmaXRuZXNzLWRiCiAgICAgIC0gJ1NQQVJLWV9GSVRORVNTX0RCX05BTUU9JHtTUEFSS1lfRklUTkVTU19EQl9OQU1FOi1zcGFya3lmaXRuZXNzfScKICAgICAgLSAnU1BBUktZX0ZJVE5FU1NfREJfUEFTU1dPUkQ9JHtTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTfScKICAgICAgLSAnU1BBUktZX0ZJVE5FU1NfREJfUE9SVD0ke1NQQVJLWV9GSVRORVNTX0RCX1BPUlQ6LTU0MzJ9JwogICAgICAtICdTUEFSS1lfRklUTkVTU19BUFBfREJfVVNFUj0ke1NQQVJLWV9GSVRORVNTX0FQUF9EQl9VU0VSOi1zcGFya3lhcHB9JwogICAgICAtICdTUEFSS1lfRklUTkVTU19BUFBfREJfUEFTU1dPUkQ9JHtTRVJWSUNFX1BBU1NXT1JEXzY0X0FQUERCUEFTU1dPUkR9JwogICAgICAtICdTUEFSS1lfRklUTkVTU19BUElfRU5DUllQVElPTl9LRVk9JHtTRVJWSUNFX1BBU1NXT1JEXzY0X1NFUlZFUkFQSUVOQ1JZUFRJT05LRVl9JwogICAgICAtICdCRVRURVJfQVVUSF9TRUNSRVQ9JHtTRVJWSUNFX1BBU1NXT1JEXzY0X0JFVFRFUkFVVEhTRUNSRVR9JwogICAgICAtICdTUEFSS1lfRklUTkVTU19GUk9OVEVORF9VUkw9JHtTRVJWSUNFX1VSTF9TUEFSS1lGSVRORVNTXzgwfScKICAgICAgLSAnQUxMT1dfUFJJVkFURV9ORVRXT1JLX0NPUlM9JHtBTExPV19QUklWQVRFX05FVFdPUktfQ09SUzotZmFsc2V9JwogICAgICAtICdTUEFSS1lfRklUTkVTU19FWFRSQV9UUlVTVEVEX09SSUdJTlM9JHtTUEFSS1lfRklUTkVTU19FWFRSQV9UUlVTVEVEX09SSUdJTlM6LX0nCiAgICAgIC0gJ1NQQVJLWV9GSVRORVNTX0RJU0FCTEVfU0lHTlVQPSR7U1BBUktZX0ZJVE5FU1NfRElTQUJMRV9TSUdOVVA6LWZhbHNlfScKICAgICAgLSAnU1BBUktZX0ZJVE5FU1NfRk9SQ0VfRU1BSUxfTE9HSU49JHtTUEFSS1lfRklUTkVTU19GT1JDRV9FTUFJTF9MT0dJTjotdHJ1ZX0nCiAgICAgIC0gJ1NQQVJLWV9GSVRORVNTX0FETUlOX0VNQUlMPSR7U1BBUktZX0ZJVE5FU1NfQURNSU5fRU1BSUw6LWFkbWluQGV4YW1wbGUuY29tfScKICAgICAgLSAnU1BBUktZX0ZJVE5FU1NfRU1BSUxfSE9TVD0ke1NQQVJLWV9GSVRORVNTX0VNQUlMX0hPU1Q6LXNtdHAuZ21haWwuY29tfScKICAgICAgLSAnU1BBUktZX0ZJVE5FU1NfRU1BSUxfUE9SVD0ke1NQQVJLWV9GSVRORVNTX0VNQUlMX1BPUlQ6LTU4N30nCiAgICAgIC0gJ1NQQVJLWV9GSVRORVNTX0VNQUlMX1NFQ1VSRT0ke1NQQVJLWV9GSVRORVNTX0VNQUlMX1NFQ1VSRTotZmFsc2V9JwogICAgICAtICdTUEFSS1lfRklUTkVTU19FTUFJTF9VU0VSPSR7U1BBUktZX0ZJVE5FU1NfRU1BSUxfVVNFUn0nCiAgICAgIC0gJ1NQQVJLWV9GSVRORVNTX0VNQUlMX1BBU1M9JHtTUEFSS1lfRklUTkVTU19FTUFJTF9QQVNTfScKICAgICAgLSAnU1BBUktZX0ZJVE5FU1NfRU1BSUxfRlJPTT0ke1NQQVJLWV9GSVRORVNTX0VNQUlMX0ZST006LSJTcGFya3kgRml0bmVzcyA8bm9yZXBseUBzcGFya3lmaXRuZXNzLmNvbT4ifScKICAgIGRlcGVuZHNfb246CiAgICAgIC0gc3Bhcmt5Zml0bmVzcy1kYgogICAgdm9sdW1lczoKICAgICAgLSAnc3Bhcmt5Zml0bmVzcy1zZXJ2ZXItYmFja3VwOi9hcHAvU3Bhcmt5Rml0bmVzc1NlcnZlci9iYWNrdXAnCiAgICAgIC0gJ3NwYXJreWZpdG5lc3Mtc2VydmVyLXVwbG9hZHM6L2FwcC9TcGFya3lGaXRuZXNzU2VydmVyL3VwbG9hZHMnCiAgc3Bhcmt5Zml0bmVzcy1kYjoKICAgIGltYWdlOiAncG9zdGdyZXM6MTgtYWxwaW5lJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ1BPU1RHUkVTX0RCPSR7U1BBUktZX0ZJVE5FU1NfREJfTkFNRTotc3Bhcmt5Zml0bmVzc30nCiAgICAgIC0gJ1BPU1RHUkVTX1VTRVI9JHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9JwogICAgICAtICdQT1NUR1JFU19QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVN9JwogICAgICAtICdQT1NUR1JFU19QT1JUPSR7U1BBUktZX0ZJVE5FU1NfREJfUE9SVDotNTQzMn0nCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gJ3BnX2lzcmVhZHkgLVUgJCR7UE9TVEdSRVNfVVNFUn0gLWQgJCR7UE9TVEdSRVNfREJ9JwogICAgICBpbnRlcnZhbDogNXMKICAgICAgdGltZW91dDogMjBzCiAgICAgIHJldHJpZXM6IDEwCiAgICB2b2x1bWVzOgogICAgICAtICdzcGFya3lmaXRuZXNzLWRiLXBvc3RncmVzcWw6L3Zhci9saWIvcG9zdGdyZXNxbCcK",
|
||||
"tags": [
|
||||
"sparkyfitness",
|
||||
"fitness",
|
||||
@@ -4867,9 +4885,29 @@
|
||||
"category": "health",
|
||||
"logo": "svgs/sparkyfitness.svg",
|
||||
"minversion": "0.0.0",
|
||||
"template_last_updated_at": "2025-10-22T07:08:46+07:00",
|
||||
"template_last_updated_at": "2026-08-10T13:18:10+02:00",
|
||||
"port": "80"
|
||||
},
|
||||
"stalwart": {
|
||||
"documentation": "https://stalw.art/docs/?utm_source=coolify.io",
|
||||
"slogan": "Modern mail server platform",
|
||||
"compose": "c2VydmljZXM6CiAgc3RhbHdhcnQ6CiAgICBpbWFnZTogJ3N0YWx3YXJ0bGFicy9zdGFsd2FydDp2MC4xNi4xMycKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfVVJMX1NUQUxXQVJUXzgwODAKICAgIGV4cG9zZToKICAgICAgLSAnODA4MCcKICAgIHBvcnRzOgogICAgICAtICcyNToyNScKICAgICAgLSAnNDY1OjQ2NScKICAgICAgLSAnNTg3OjU4NycKICAgICAgLSAnOTkzOjk5MycKICAgICAgLSAnOTk1Ojk5NScKICAgICAgLSAnMTQzOjE0MycKICAgICAgLSAnMTEwOjExMCcKICAgICAgLSAnNDE5MDo0MTkwJwogICAgdm9sdW1lczoKICAgICAgLSAnc3RhbHdhcnQtbWFpbDovZXRjL3N0YWx3YXJ0JwogICAgICAtICdzdGFsd2FydC1kYXRhOi92YXIvbGliL3N0YWx3YXJ0JwogICAgICAtICcvZXRjL2xvY2FsdGltZTovZXRjL2xvY2FsdGltZTpybycKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSBjdXJsCiAgICAgICAgLSAnLWYnCiAgICAgICAgLSAnaHR0cDovL2xvY2FsaG9zdDo4MDgwLycKICAgICAgaW50ZXJ2YWw6IDMwcwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgcmV0cmllczogMwo=",
|
||||
"tags": [
|
||||
"mail",
|
||||
"smtp",
|
||||
"imap",
|
||||
"pop3",
|
||||
"jmap",
|
||||
"email",
|
||||
"sieve",
|
||||
"messaging"
|
||||
],
|
||||
"category": "Mail",
|
||||
"logo": "svgs/stalwart.svg",
|
||||
"minversion": "0.0.0",
|
||||
"template_last_updated_at": "2026-08-10T12:58:58+02:00",
|
||||
"port": "8080"
|
||||
},
|
||||
"statusnook": {
|
||||
"documentation": "https://statusnook.com?utm_source=coolify.io",
|
||||
"slogan": "Effortlessly deploy a status page and start monitoring endpoints in minutes",
|
||||
@@ -5087,6 +5125,25 @@
|
||||
"template_last_updated_at": "2025-08-17T18:23:57+02:00",
|
||||
"port": "3000"
|
||||
},
|
||||
"termix": {
|
||||
"documentation": "https://docs.termix.site/install/server/docker?utm_source=coolify.io",
|
||||
"slogan": "All-in-One SSH & Remote Desktop management app.",
|
||||
"compose": "c2VydmljZXM6CiAgdGVybWl4OgogICAgaW1hZ2U6ICdnaGNyLmlvL2x1a2VndXMvdGVybWl4OjIuNi4xJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9VUkxfVEVSTUlYXzgwODAKICAgICAgLSBQT1JUPTgwODAKICAgICAgLSAnTE9HX0xFVkVMPSR7TE9HX0xFVkVMOi1pbmZvfScKICAgICAgLSBHVUFDRF9IT1NUPWd1YWNkCiAgICAgIC0gR1VBQ0RfUkVDT1JESU5HX1BBVEg9L3Rlcm1peC1kYXRhL3Nlc3Npb25fcmVjb3JkaW5ncy9ndWFjYW1vbGUKICAgIGRlcGVuZHNfb246CiAgICAgIC0gZ3VhY2QKICAgIHZvbHVtZXM6CiAgICAgIC0gJ3Rlcm1peC1kYXRhOi9hcHAvZGF0YScKICBndWFjZDoKICAgIGltYWdlOiAnZ3VhY2Ftb2xlL2d1YWNkOjEuNi4wJwo=",
|
||||
"tags": [
|
||||
"ssh",
|
||||
"terminal",
|
||||
"remote-desktop",
|
||||
"rdp",
|
||||
"vnc",
|
||||
"server-management",
|
||||
"remote-access"
|
||||
],
|
||||
"category": "developer-tools",
|
||||
"logo": "svgs/termix.svg",
|
||||
"minversion": "0.0.0",
|
||||
"template_last_updated_at": "2026-08-10T11:46:48+02:00",
|
||||
"port": "8080"
|
||||
},
|
||||
"terraria-server": {
|
||||
"documentation": "https://github.com/hexlo/terraria-server-docker?utm_source=coolify.io",
|
||||
"slogan": "Docker multi-arch Image for Terraria Server.",
|
||||
|
||||
@@ -1465,7 +1465,7 @@
|
||||
"firefly": {
|
||||
"documentation": "https://firefly-iii.org?utm_source=coolify.io",
|
||||
"slogan": "A personal finances manager that can help you save money.",
|
||||
"compose": "c2VydmljZXM6CiAgZmlyZWZseToKICAgIGltYWdlOiAnZmlyZWZseWlpaS9jb3JlOmxhdGVzdCcKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9GSVJFRkxZXzgwODAKICAgICAgLSBBUFBfS0VZPSRTRVJWSUNFX0JBU0U2NF9BUFBLRVkKICAgICAgLSBEQl9IT1NUPW15c3FsCiAgICAgIC0gREJfUE9SVD0zMzA2CiAgICAgIC0gREJfQ09OTkVDVElPTj1teXNxbAogICAgICAtICdEQl9EQVRBQkFTRT0ke01ZU1FMX0RBVEFCQVNFOi1maXJlZmx5fScKICAgICAgLSBEQl9VU0VSTkFNRT0kU0VSVklDRV9VU0VSX01ZU1FMCiAgICAgIC0gREJfUEFTU1dPUkQ9JFNFUlZJQ0VfUEFTU1dPUkRfTVlTUUwKICAgICAgLSBTVEFUSUNfQ1JPTl9UT0tFTj0kU0VSVklDRV9CQVNFNjRfQ1JPTlRPS0VOCiAgICAgIC0gJ1RSVVNURURfUFJPWElFUz0qJwogICAgdm9sdW1lczoKICAgICAgLSAnZmlyZWZseS11cGxvYWQ6L3Zhci93d3cvaHRtbC9zdG9yYWdlL3VwbG9hZCcKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSBjdXJsCiAgICAgICAgLSAnLWYnCiAgICAgICAgLSAnaHR0cDovLzEyNy4wLjAuMTo4MDgwJwogICAgICBpbnRlcnZhbDogNXMKICAgICAgdGltZW91dDogMjBzCiAgICAgIHJldHJpZXM6IDEwCiAgICBkZXBlbmRzX29uOgogICAgICBteXNxbDoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogIG15c3FsOgogICAgaW1hZ2U6ICdtYXJpYWRiOjExJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ01ZU1FMX1VTRVI9JHtTRVJWSUNFX1VTRVJfTVlTUUx9JwogICAgICAtICdNWVNRTF9QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfTVlTUUx9JwogICAgICAtICdNWVNRTF9EQVRBQkFTRT0ke01ZU1FMX0RBVEFCQVNFOi1maXJlZmx5fScKICAgICAgLSAnTVlTUUxfUk9PVF9QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfTVlTUUxST09UfScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSBtYXJpYWRiLWFkbWluCiAgICAgICAgLSBwaW5nCiAgICAgICAgLSAnLWgnCiAgICAgICAgLSAxMjcuMC4wLjEKICAgICAgICAtICctdXJvb3QnCiAgICAgICAgLSAnLXAke1NFUlZJQ0VfUEFTU1dPUkRfTVlTUUxST09UfScKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHRpbWVvdXQ6IDIwcwogICAgICByZXRyaWVzOiAxMAogICAgdm9sdW1lczoKICAgICAgLSAnZmlyZWZseS1teXNxbC1kYXRhOi92YXIvbGliL215c3FsJwogIGNyb246CiAgICBpbWFnZTogYWxwaW5lCiAgICBlbnRyeXBvaW50OgogICAgICAtIC9lbnRyeXBvaW50LnNoCiAgICB2b2x1bWVzOgogICAgICAtCiAgICAgICAgdHlwZTogYmluZAogICAgICAgIHNvdXJjZTogLi9lbnRyeXBvaW50LnNoCiAgICAgICAgdGFyZ2V0OiAvZW50cnlwb2ludC5zaAogICAgICAgIGNvbnRlbnQ6ICIjIS9iaW4vc2hcbiMgU3Vic3RpdHV0ZSB0aGUgZW52aXJvbm1lbnQgdmFyaWFibGUgaW50byB0aGUgY3JvbiBjb21tYW5kXG5DUk9OX0NPTU1BTkQ9XCIwIDMgKiAqICogd2dldCAtcU8tIGh0dHA6Ly9maXJlZmx5OjgwODAvYXBpL3YxL2Nyb24vJHtTVEFUSUNfQ1JPTl9UT0tFTn1cIlxuIyBBZGQgdGhlIGNyb24gY29tbWFuZCB0byB0aGUgY3JvbnRhYlxuZWNobyBcIiRDUk9OX0NPTU1BTkRcIiB8IGNyb250YWIgLVxuIyBTdGFydCB0aGUgY3JvbiBkYWVtb24gaW4gdGhlIGZvcmVncm91bmQgd2l0aCBsb2dnaW5nIHRvIHN0ZG91dFxuY3JvbmQgLWYgLUwgL2Rldi9zdGRvdXQiCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTVEFUSUNfQ1JPTl9UT0tFTj0kU0VSVklDRV9CQVNFNjRfQ1JPTlRPS0VOCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gJ2xzIC9lbnRyeXBvaW50LnNoIHx8IGV4aXQgMScKICAgICAgaW50ZXJ2YWw6IDMwcwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgcmV0cmllczogMwogICAgICBzdGFydF9wZXJpb2Q6IDQwcwo=",
|
||||
"compose": "c2VydmljZXM6CiAgZmlyZWZseToKICAgIGltYWdlOiAnZmlyZWZseWlpaS9jb3JlOmxhdGVzdCcKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9GSVJFRkxZXzgwODAKICAgICAgLSBBUFBfS0VZPSRTRVJWSUNFX0JBU0U2NF9BUFBLRVkKICAgICAgLSBEQl9IT1NUPW15c3FsCiAgICAgIC0gREJfUE9SVD0zMzA2CiAgICAgIC0gREJfQ09OTkVDVElPTj1teXNxbAogICAgICAtICdEQl9EQVRBQkFTRT0ke01ZU1FMX0RBVEFCQVNFOi1maXJlZmx5fScKICAgICAgLSBEQl9VU0VSTkFNRT0kU0VSVklDRV9VU0VSX01ZU1FMCiAgICAgIC0gREJfUEFTU1dPUkQ9JFNFUlZJQ0VfUEFTU1dPUkRfTVlTUUwKICAgICAgLSBTVEFUSUNfQ1JPTl9UT0tFTj0kU0VSVklDRV9CQVNFNjRfQ1JPTlRPS0VOCiAgICAgIC0gJ1RSVVNURURfUFJPWElFUz0qJwogICAgdm9sdW1lczoKICAgICAgLSAnZmlyZWZseS11cGxvYWQ6L3Zhci93d3cvaHRtbC9zdG9yYWdlL3VwbG9hZCcKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSBjdXJsCiAgICAgICAgLSAnLWYnCiAgICAgICAgLSAnaHR0cDovLzEyNy4wLjAuMTo4MDgwL2hlYWx0aCcKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHRpbWVvdXQ6IDIwcwogICAgICByZXRyaWVzOiAxMAogICAgZGVwZW5kc19vbjoKICAgICAgbXlzcWw6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICBteXNxbDoKICAgIGltYWdlOiAnbWFyaWFkYjoxMScKICAgIGVudmlyb25tZW50OgogICAgICAtICdNWVNRTF9VU0VSPSR7U0VSVklDRV9VU0VSX01ZU1FMfScKICAgICAgLSAnTVlTUUxfUEFTU1dPUkQ9JHtTRVJWSUNFX1BBU1NXT1JEX01ZU1FMfScKICAgICAgLSAnTVlTUUxfREFUQUJBU0U9JHtNWVNRTF9EQVRBQkFTRTotZmlyZWZseX0nCiAgICAgIC0gJ01ZU1FMX1JPT1RfUEFTU1dPUkQ9JHtTRVJWSUNFX1BBU1NXT1JEX01ZU1FMUk9PVH0nCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRAogICAgICAgIC0gbWFyaWFkYi1hZG1pbgogICAgICAgIC0gcGluZwogICAgICAgIC0gJy1oJwogICAgICAgIC0gMTI3LjAuMC4xCiAgICAgICAgLSAnLXVyb290JwogICAgICAgIC0gJy1wJHtTRVJWSUNFX1BBU1NXT1JEX01ZU1FMUk9PVH0nCiAgICAgIGludGVydmFsOiA1cwogICAgICB0aW1lb3V0OiAyMHMKICAgICAgcmV0cmllczogMTAKICAgIHZvbHVtZXM6CiAgICAgIC0gJ2ZpcmVmbHktbXlzcWwtZGF0YTovdmFyL2xpYi9teXNxbCcKICBjcm9uOgogICAgaW1hZ2U6IGFscGluZQogICAgZW50cnlwb2ludDoKICAgICAgLSAvZW50cnlwb2ludC5zaAogICAgdm9sdW1lczoKICAgICAgLQogICAgICAgIHR5cGU6IGJpbmQKICAgICAgICBzb3VyY2U6IC4vZW50cnlwb2ludC5zaAogICAgICAgIHRhcmdldDogL2VudHJ5cG9pbnQuc2gKICAgICAgICBjb250ZW50OiAiIyEvYmluL3NoXG4jIFN1YnN0aXR1dGUgdGhlIGVudmlyb25tZW50IHZhcmlhYmxlIGludG8gdGhlIGNyb24gY29tbWFuZFxuQ1JPTl9DT01NQU5EPVwiMCAzICogKiAqIHdnZXQgLXFPLSBodHRwOi8vZmlyZWZseTo4MDgwL2FwaS92MS9jcm9uLyR7U1RBVElDX0NST05fVE9LRU59XCJcbiMgQWRkIHRoZSBjcm9uIGNvbW1hbmQgdG8gdGhlIGNyb250YWJcbmVjaG8gXCIkQ1JPTl9DT01NQU5EXCIgfCBjcm9udGFiIC1cbiMgU3RhcnQgdGhlIGNyb24gZGFlbW9uIGluIHRoZSBmb3JlZ3JvdW5kIHdpdGggbG9nZ2luZyB0byBzdGRvdXRcbmNyb25kIC1mIC1MIC9kZXYvc3Rkb3V0IgogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU1RBVElDX0NST05fVE9LRU49JFNFUlZJQ0VfQkFTRTY0X0NST05UT0tFTgogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQtU0hFTEwKICAgICAgICAtICdscyAvZW50cnlwb2ludC5zaCB8fCBleGl0IDEnCiAgICAgIGludGVydmFsOiAzMHMKICAgICAgdGltZW91dDogMTBzCiAgICAgIHJldHJpZXM6IDMKICAgICAgc3RhcnRfcGVyaW9kOiA0MHMK",
|
||||
"tags": [
|
||||
"finance",
|
||||
"money",
|
||||
@@ -1475,7 +1475,7 @@
|
||||
"category": "finance",
|
||||
"logo": "svgs/firefly.svg",
|
||||
"minversion": "0.0.0",
|
||||
"template_last_updated_at": "2026-04-06T11:35:16-05:00",
|
||||
"template_last_updated_at": "2026-08-10T10:43:04+02:00",
|
||||
"port": "8080"
|
||||
},
|
||||
"firefox": {
|
||||
@@ -1583,7 +1583,7 @@
|
||||
"forgejo-with-mariadb": {
|
||||
"documentation": "https://forgejo.org/docs?utm_source=coolify.io",
|
||||
"slogan": "Forgejo is a self-hosted lightweight software forge. Easy to install and low maintenance, it just does the job.",
|
||||
"compose": "c2VydmljZXM6CiAgZm9yZ2VqbzoKICAgIGltYWdlOiAnY29kZWJlcmcub3JnL2Zvcmdlam8vZm9yZ2Vqbzo4JwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9GUUROX0ZPUkdFSk9fMzAwMAogICAgICAtICdGT1JHRUpPX19zZXJ2ZXJfX1JPT1RfVVJMPSR7U0VSVklDRV9GUUROX0ZPUkdFSk99JwogICAgICAtICdGT1JHRUpPX19taWdyYXRpb25zX19BTExPV0VEX0RPTUFJTlM9JHtGT1JHRUpPX19taWdyYXRpb25zX19BTExPV0VEX0RPTUFJTlN9JwogICAgICAtICdGT1JHRUpPX19taWdyYXRpb25zX19BTExPV19MT0NBTE5FVFdPUktTPSR7Rk9SR0VKT19fbWlncmF0aW9uc19fQUxMT1dfTE9DQUxORVRXT1JLUy1mYWxzZX0nCiAgICAgIC0gVVNFUl9VSUQ9MTAwMAogICAgICAtIFVTRVJfR0lEPTEwMDAKICAgICAgLSBGT1JHRUpPX19kYXRhYmFzZV9fREJfVFlQRT1teXNxbAogICAgICAtIEZPUkdFSk9fX2RhdGFiYXNlX19IT1NUPW1hcmlhZGIKICAgICAgLSAnRk9SR0VKT19fZGF0YWJhc2VfX05BTUU9JHtNWVNRTF9EQVRBQkFTRS1mb3JnZWpvfScKICAgICAgLSBGT1JHRUpPX19kYXRhYmFzZV9fVVNFUj0kU0VSVklDRV9VU0VSX01ZU1FMCiAgICAgIC0gRk9SR0VKT19fZGF0YWJhc2VfX1BBU1NXRD0kU0VSVklDRV9QQVNTV09SRF9NWVNRTAogICAgdm9sdW1lczoKICAgICAgLSAnZm9yZ2Vqby1kYXRhOi9kYXRhJwogICAgICAtICdmb3JnZWpvLXRpbWV6b25lOi9ldGMvdGltZXpvbmU6cm8nCiAgICAgIC0gJ2Zvcmdlam8tbG9jYWx0aW1lOi9ldGMvbG9jYWx0aW1lOnJvJwogICAgcG9ydHM6CiAgICAgIC0gJzIyMjIyOjIyJwogICAgZGVwZW5kc19vbjoKICAgICAgbWFyaWFkYjoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIGN1cmwKICAgICAgICAtICctZicKICAgICAgICAtICdodHRwOi8vMTI3LjAuMC4xOjMwMDAnCiAgICAgIGludGVydmFsOiAycwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgcmV0cmllczogMTUKICBtYXJpYWRiOgogICAgaW1hZ2U6ICdtYXJpYWRiOjExJwogICAgdm9sdW1lczoKICAgICAgLSAnZm9yZ2Vqby1tYXJpYWRiLWRhdGE6L3Zhci9saWIvbXlzcWwnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSAnTVlTUUxfVVNFUj0ke1NFUlZJQ0VfVVNFUl9NWVNRTH0nCiAgICAgIC0gJ01ZU1FMX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9NWVNRTH0nCiAgICAgIC0gJ01ZU1FMX0RBVEFCQVNFPSR7TVlTUUxfREFUQUJBU0V9JwogICAgICAtICdNWVNRTF9ST09UX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9NWVNRTFJPT1R9JwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIGhlYWx0aGNoZWNrLnNoCiAgICAgICAgLSAnLS1jb25uZWN0JwogICAgICAgIC0gJy0taW5ub2RiX2luaXRpYWxpemVkJwogICAgICBpbnRlcnZhbDogNXMKICAgICAgdGltZW91dDogMjBzCiAgICAgIHJldHJpZXM6IDEwCg==",
|
||||
"compose": "c2VydmljZXM6CiAgZm9yZ2VqbzoKICAgIGltYWdlOiAnY29kZWJlcmcub3JnL2Zvcmdlam8vZm9yZ2VqbzoxNScKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9GT1JHRUpPXzMwMDAKICAgICAgLSAnRk9SR0VKT19fc2VydmVyX19ST09UX1VSTD0ke1NFUlZJQ0VfRlFETl9GT1JHRUpPfScKICAgICAgLSAnRk9SR0VKT19fbWlncmF0aW9uc19fQUxMT1dFRF9ET01BSU5TPSR7Rk9SR0VKT19fbWlncmF0aW9uc19fQUxMT1dFRF9ET01BSU5TfScKICAgICAgLSAnRk9SR0VKT19fbWlncmF0aW9uc19fQUxMT1dfTE9DQUxORVRXT1JLUz0ke0ZPUkdFSk9fX21pZ3JhdGlvbnNfX0FMTE9XX0xPQ0FMTkVUV09SS1MtZmFsc2V9JwogICAgICAtIFVTRVJfVUlEPTEwMDAKICAgICAgLSBVU0VSX0dJRD0xMDAwCiAgICAgIC0gRk9SR0VKT19fZGF0YWJhc2VfX0RCX1RZUEU9bXlzcWwKICAgICAgLSBGT1JHRUpPX19kYXRhYmFzZV9fSE9TVD1tYXJpYWRiCiAgICAgIC0gJ0ZPUkdFSk9fX2RhdGFiYXNlX19OQU1FPSR7TVlTUUxfREFUQUJBU0UtZm9yZ2Vqb30nCiAgICAgIC0gRk9SR0VKT19fZGF0YWJhc2VfX1VTRVI9JFNFUlZJQ0VfVVNFUl9NWVNRTAogICAgICAtIEZPUkdFSk9fX2RhdGFiYXNlX19QQVNTV0Q9JFNFUlZJQ0VfUEFTU1dPUkRfTVlTUUwKICAgIHZvbHVtZXM6CiAgICAgIC0gJ2Zvcmdlam8tZGF0YTovZGF0YScKICAgICAgLSAnZm9yZ2Vqby10aW1lem9uZTovZXRjL3RpbWV6b25lOnJvJwogICAgICAtICdmb3JnZWpvLWxvY2FsdGltZTovZXRjL2xvY2FsdGltZTpybycKICAgIHBvcnRzOgogICAgICAtICcyMjIyMjoyMicKICAgIGRlcGVuZHNfb246CiAgICAgIG1hcmlhZGI6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSBjdXJsCiAgICAgICAgLSAnLWYnCiAgICAgICAgLSAnaHR0cDovLzEyNy4wLjAuMTozMDAwJwogICAgICBpbnRlcnZhbDogMnMKICAgICAgdGltZW91dDogMTBzCiAgICAgIHJldHJpZXM6IDE1CiAgbWFyaWFkYjoKICAgIGltYWdlOiAnbWFyaWFkYjoxMScKICAgIHZvbHVtZXM6CiAgICAgIC0gJ2Zvcmdlam8tbWFyaWFkYi1kYXRhOi92YXIvbGliL215c3FsJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ01ZU1FMX1VTRVI9JHtTRVJWSUNFX1VTRVJfTVlTUUx9JwogICAgICAtICdNWVNRTF9QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfTVlTUUx9JwogICAgICAtICdNWVNRTF9EQVRBQkFTRT0ke01ZU1FMX0RBVEFCQVNFfScKICAgICAgLSAnTVlTUUxfUk9PVF9QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfTVlTUUxST09UfScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSBoZWFsdGhjaGVjay5zaAogICAgICAgIC0gJy0tY29ubmVjdCcKICAgICAgICAtICctLWlubm9kYl9pbml0aWFsaXplZCcKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHRpbWVvdXQ6IDIwcwogICAgICByZXRyaWVzOiAxMAo=",
|
||||
"tags": [
|
||||
"version control",
|
||||
"collaboration",
|
||||
@@ -1595,13 +1595,13 @@
|
||||
"category": "git",
|
||||
"logo": "svgs/forgejo.svg",
|
||||
"minversion": "0.0.0",
|
||||
"template_last_updated_at": "2026-02-04T17:34:52+01:00",
|
||||
"template_last_updated_at": "2026-08-10T11:35:20+02:00",
|
||||
"port": "3000"
|
||||
},
|
||||
"forgejo-with-mysql": {
|
||||
"documentation": "https://forgejo.org/docs?utm_source=coolify.io",
|
||||
"slogan": "Forgejo is a self-hosted lightweight software forge. Easy to install and low maintenance, it just does the job.",
|
||||
"compose": "c2VydmljZXM6CiAgZm9yZ2VqbzoKICAgIGltYWdlOiAnY29kZWJlcmcub3JnL2Zvcmdlam8vZm9yZ2Vqbzo4JwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9GUUROX0ZPUkdFSk9fMzAwMAogICAgICAtICdGT1JHRUpPX19zZXJ2ZXJfX1JPT1RfVVJMPSR7U0VSVklDRV9GUUROX0ZPUkdFSk99JwogICAgICAtICdGT1JHRUpPX19taWdyYXRpb25zX19BTExPV0VEX0RPTUFJTlM9JHtGT1JHRUpPX19taWdyYXRpb25zX19BTExPV0VEX0RPTUFJTlN9JwogICAgICAtICdGT1JHRUpPX19taWdyYXRpb25zX19BTExPV19MT0NBTE5FVFdPUktTPSR7Rk9SR0VKT19fbWlncmF0aW9uc19fQUxMT1dfTE9DQUxORVRXT1JLUy1mYWxzZX0nCiAgICAgIC0gVVNFUl9VSUQ9MTAwMAogICAgICAtIFVTRVJfR0lEPTEwMDAKICAgICAgLSBGT1JHRUpPX19kYXRhYmFzZV9fREJfVFlQRT1teXNxbAogICAgICAtIEZPUkdFSk9fX2RhdGFiYXNlX19IT1NUPW15c3FsCiAgICAgIC0gJ0ZPUkdFSk9fX2RhdGFiYXNlX19OQU1FPSR7TVlTUUxfREFUQUJBU0UtZm9yZ2Vqb30nCiAgICAgIC0gRk9SR0VKT19fZGF0YWJhc2VfX1VTRVI9JFNFUlZJQ0VfVVNFUl9NWVNRTAogICAgICAtIEZPUkdFSk9fX2RhdGFiYXNlX19QQVNTV0Q9JFNFUlZJQ0VfUEFTU1dPUkRfTVlTUUwKICAgIHZvbHVtZXM6CiAgICAgIC0gJ2Zvcmdlam8tZGF0YTovZGF0YScKICAgICAgLSAnZm9yZ2Vqby10aW1lem9uZTovZXRjL3RpbWV6b25lOnJvJwogICAgICAtICdmb3JnZWpvLWxvY2FsdGltZTovZXRjL2xvY2FsdGltZTpybycKICAgIHBvcnRzOgogICAgICAtICcyMjIyMjoyMicKICAgIGRlcGVuZHNfb246CiAgICAgIG15c3FsOgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9oZWFsdGh5CiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRAogICAgICAgIC0gY3VybAogICAgICAgIC0gJy1mJwogICAgICAgIC0gJ2h0dHA6Ly8xMjcuMC4wLjE6MzAwMCcKICAgICAgaW50ZXJ2YWw6IDJzCiAgICAgIHRpbWVvdXQ6IDEwcwogICAgICByZXRyaWVzOiAxNQogIG15c3FsOgogICAgaW1hZ2U6ICdteXNxbDo4JwogICAgdm9sdW1lczoKICAgICAgLSAnZm9yZ2Vqby1teXNxbC1kYXRhOi92YXIvbGliL215c3FsJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ01ZU1FMX1VTRVI9JHtTRVJWSUNFX1VTRVJfTVlTUUx9JwogICAgICAtICdNWVNRTF9QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfTVlTUUx9JwogICAgICAtICdNWVNRTF9EQVRBQkFTRT0ke01ZU1FMX0RBVEFCQVNFfScKICAgICAgLSAnTVlTUUxfUk9PVF9QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfTVlTUUxST09UfScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSBteXNxbGFkbWluCiAgICAgICAgLSBwaW5nCiAgICAgICAgLSAnLWgnCiAgICAgICAgLSAxMjcuMC4wLjEKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHRpbWVvdXQ6IDIwcwogICAgICByZXRyaWVzOiAxMAo=",
|
||||
"compose": "c2VydmljZXM6CiAgZm9yZ2VqbzoKICAgIGltYWdlOiAnY29kZWJlcmcub3JnL2Zvcmdlam8vZm9yZ2VqbzoxNScKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9GT1JHRUpPXzMwMDAKICAgICAgLSAnRk9SR0VKT19fc2VydmVyX19ST09UX1VSTD0ke1NFUlZJQ0VfRlFETl9GT1JHRUpPfScKICAgICAgLSAnRk9SR0VKT19fbWlncmF0aW9uc19fQUxMT1dFRF9ET01BSU5TPSR7Rk9SR0VKT19fbWlncmF0aW9uc19fQUxMT1dFRF9ET01BSU5TfScKICAgICAgLSAnRk9SR0VKT19fbWlncmF0aW9uc19fQUxMT1dfTE9DQUxORVRXT1JLUz0ke0ZPUkdFSk9fX21pZ3JhdGlvbnNfX0FMTE9XX0xPQ0FMTkVUV09SS1MtZmFsc2V9JwogICAgICAtIFVTRVJfVUlEPTEwMDAKICAgICAgLSBVU0VSX0dJRD0xMDAwCiAgICAgIC0gRk9SR0VKT19fZGF0YWJhc2VfX0RCX1RZUEU9bXlzcWwKICAgICAgLSBGT1JHRUpPX19kYXRhYmFzZV9fSE9TVD1teXNxbAogICAgICAtICdGT1JHRUpPX19kYXRhYmFzZV9fTkFNRT0ke01ZU1FMX0RBVEFCQVNFLWZvcmdlam99JwogICAgICAtIEZPUkdFSk9fX2RhdGFiYXNlX19VU0VSPSRTRVJWSUNFX1VTRVJfTVlTUUwKICAgICAgLSBGT1JHRUpPX19kYXRhYmFzZV9fUEFTU1dEPSRTRVJWSUNFX1BBU1NXT1JEX01ZU1FMCiAgICB2b2x1bWVzOgogICAgICAtICdmb3JnZWpvLWRhdGE6L2RhdGEnCiAgICAgIC0gJ2Zvcmdlam8tdGltZXpvbmU6L2V0Yy90aW1lem9uZTpybycKICAgICAgLSAnZm9yZ2Vqby1sb2NhbHRpbWU6L2V0Yy9sb2NhbHRpbWU6cm8nCiAgICBwb3J0czoKICAgICAgLSAnMjIyMjI6MjInCiAgICBkZXBlbmRzX29uOgogICAgICBteXNxbDoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIGN1cmwKICAgICAgICAtICctZicKICAgICAgICAtICdodHRwOi8vMTI3LjAuMC4xOjMwMDAnCiAgICAgIGludGVydmFsOiAycwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgcmV0cmllczogMTUKICBteXNxbDoKICAgIGltYWdlOiAnbXlzcWw6OCcKICAgIHZvbHVtZXM6CiAgICAgIC0gJ2Zvcmdlam8tbXlzcWwtZGF0YTovdmFyL2xpYi9teXNxbCcKICAgIGVudmlyb25tZW50OgogICAgICAtICdNWVNRTF9VU0VSPSR7U0VSVklDRV9VU0VSX01ZU1FMfScKICAgICAgLSAnTVlTUUxfUEFTU1dPUkQ9JHtTRVJWSUNFX1BBU1NXT1JEX01ZU1FMfScKICAgICAgLSAnTVlTUUxfREFUQUJBU0U9JHtNWVNRTF9EQVRBQkFTRX0nCiAgICAgIC0gJ01ZU1FMX1JPT1RfUEFTU1dPUkQ9JHtTRVJWSUNFX1BBU1NXT1JEX01ZU1FMUk9PVH0nCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRAogICAgICAgIC0gbXlzcWxhZG1pbgogICAgICAgIC0gcGluZwogICAgICAgIC0gJy1oJwogICAgICAgIC0gMTI3LjAuMC4xCiAgICAgIGludGVydmFsOiA1cwogICAgICB0aW1lb3V0OiAyMHMKICAgICAgcmV0cmllczogMTAK",
|
||||
"tags": [
|
||||
"version control",
|
||||
"collaboration",
|
||||
@@ -1613,13 +1613,13 @@
|
||||
"category": "git",
|
||||
"logo": "svgs/forgejo.svg",
|
||||
"minversion": "0.0.0",
|
||||
"template_last_updated_at": "2026-02-04T17:34:52+01:00",
|
||||
"template_last_updated_at": "2026-08-10T11:35:20+02:00",
|
||||
"port": "3000"
|
||||
},
|
||||
"forgejo-with-postgresql": {
|
||||
"documentation": "https://forgejo.org/docs?utm_source=coolify.io",
|
||||
"slogan": "Forgejo is a self-hosted lightweight software forge. Easy to install and low maintenance, it just does the job.",
|
||||
"compose": "c2VydmljZXM6CiAgZm9yZ2VqbzoKICAgIGltYWdlOiAnY29kZWJlcmcub3JnL2Zvcmdlam8vZm9yZ2Vqbzo4JwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9GUUROX0ZPUkdFSk9fMzAwMAogICAgICAtICdGT1JHRUpPX19zZXJ2ZXJfX1JPT1RfVVJMPSR7U0VSVklDRV9GUUROX0ZPUkdFSk99JwogICAgICAtICdGT1JHRUpPX19taWdyYXRpb25zX19BTExPV0VEX0RPTUFJTlM9JHtGT1JHRUpPX19taWdyYXRpb25zX19BTExPV0VEX0RPTUFJTlN9JwogICAgICAtICdGT1JHRUpPX19taWdyYXRpb25zX19BTExPV19MT0NBTE5FVFdPUktTPSR7Rk9SR0VKT19fbWlncmF0aW9uc19fQUxMT1dfTE9DQUxORVRXT1JLUy1mYWxzZX0nCiAgICAgIC0gVVNFUl9VSUQ9MTAwMAogICAgICAtIFVTRVJfR0lEPTEwMDAKICAgICAgLSBGT1JHRUpPX19kYXRhYmFzZV9fREJfVFlQRT1wb3N0Z3JlcwogICAgICAtIEZPUkdFSk9fX2RhdGFiYXNlX19IT1NUPXBvc3RncmVzcWwKICAgICAgLSAnRk9SR0VKT19fZGF0YWJhc2VfX05BTUU9JHtQT1NUR1JFU1FMX0RBVEFCQVNFLWZvcmdlam99JwogICAgICAtIEZPUkdFSk9fX2RhdGFiYXNlX19VU0VSPSRTRVJWSUNFX1VTRVJfUE9TVEdSRVNRTAogICAgICAtIEZPUkdFSk9fX2RhdGFiYXNlX19QQVNTV0Q9JFNFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVNRTAogICAgdm9sdW1lczoKICAgICAgLSAnZm9yZ2Vqby1kYXRhOi9kYXRhJwogICAgICAtICdmb3JnZWpvLXRpbWV6b25lOi9ldGMvdGltZXpvbmU6cm8nCiAgICAgIC0gJ2Zvcmdlam8tbG9jYWx0aW1lOi9ldGMvbG9jYWx0aW1lOnJvJwogICAgcG9ydHM6CiAgICAgIC0gJzIyMjIyOjIyJwogICAgZGVwZW5kc19vbjoKICAgICAgcG9zdGdyZXNxbDoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIGN1cmwKICAgICAgICAtICctZicKICAgICAgICAtICdodHRwOi8vMTI3LjAuMC4xOjMwMDAnCiAgICAgIGludGVydmFsOiAycwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgcmV0cmllczogMTUKICBwb3N0Z3Jlc3FsOgogICAgaW1hZ2U6ICdwb3N0Z3JlczoxNi1hbHBpbmUnCiAgICB2b2x1bWVzOgogICAgICAtICdmb3JnZWpvLXBvc3RncmVzcWwtZGF0YTovdmFyL2xpYi9wb3N0Z3Jlc3FsL2RhdGEnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSAnUE9TVEdSRVNfVVNFUj0ke1NFUlZJQ0VfVVNFUl9QT1NUR1JFU1FMfScKICAgICAgLSAnUE9TVEdSRVNfUEFTU1dPUkQ9JHtTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTUUx9JwogICAgICAtICdQT1NUR1JFU19EQj0ke1BPU1RHUkVTUUxfREFUQUJBU0V9JwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQtU0hFTEwKICAgICAgICAtICdwZ19pc3JlYWR5IC1VICQke1BPU1RHUkVTX1VTRVJ9IC1kICQke1BPU1RHUkVTX0RCfScKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHRpbWVvdXQ6IDIwcwogICAgICByZXRyaWVzOiAxMAo=",
|
||||
"compose": "c2VydmljZXM6CiAgZm9yZ2VqbzoKICAgIGltYWdlOiAnY29kZWJlcmcub3JnL2Zvcmdlam8vZm9yZ2VqbzoxNScKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9GT1JHRUpPXzMwMDAKICAgICAgLSAnRk9SR0VKT19fc2VydmVyX19ST09UX1VSTD0ke1NFUlZJQ0VfRlFETl9GT1JHRUpPfScKICAgICAgLSAnRk9SR0VKT19fbWlncmF0aW9uc19fQUxMT1dFRF9ET01BSU5TPSR7Rk9SR0VKT19fbWlncmF0aW9uc19fQUxMT1dFRF9ET01BSU5TfScKICAgICAgLSAnRk9SR0VKT19fbWlncmF0aW9uc19fQUxMT1dfTE9DQUxORVRXT1JLUz0ke0ZPUkdFSk9fX21pZ3JhdGlvbnNfX0FMTE9XX0xPQ0FMTkVUV09SS1MtZmFsc2V9JwogICAgICAtIFVTRVJfVUlEPTEwMDAKICAgICAgLSBVU0VSX0dJRD0xMDAwCiAgICAgIC0gRk9SR0VKT19fZGF0YWJhc2VfX0RCX1RZUEU9cG9zdGdyZXMKICAgICAgLSBGT1JHRUpPX19kYXRhYmFzZV9fSE9TVD1wb3N0Z3Jlc3FsCiAgICAgIC0gJ0ZPUkdFSk9fX2RhdGFiYXNlX19OQU1FPSR7UE9TVEdSRVNRTF9EQVRBQkFTRS1mb3JnZWpvfScKICAgICAgLSBGT1JHRUpPX19kYXRhYmFzZV9fVVNFUj0kU0VSVklDRV9VU0VSX1BPU1RHUkVTUUwKICAgICAgLSBGT1JHRUpPX19kYXRhYmFzZV9fUEFTU1dEPSRTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTUUwKICAgIHZvbHVtZXM6CiAgICAgIC0gJ2Zvcmdlam8tZGF0YTovZGF0YScKICAgICAgLSAnZm9yZ2Vqby10aW1lem9uZTovZXRjL3RpbWV6b25lOnJvJwogICAgICAtICdmb3JnZWpvLWxvY2FsdGltZTovZXRjL2xvY2FsdGltZTpybycKICAgIHBvcnRzOgogICAgICAtICcyMjIyMjoyMicKICAgIGRlcGVuZHNfb246CiAgICAgIHBvc3RncmVzcWw6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSBjdXJsCiAgICAgICAgLSAnLWYnCiAgICAgICAgLSAnaHR0cDovLzEyNy4wLjAuMTozMDAwJwogICAgICBpbnRlcnZhbDogMnMKICAgICAgdGltZW91dDogMTBzCiAgICAgIHJldHJpZXM6IDE1CiAgcG9zdGdyZXNxbDoKICAgIGltYWdlOiAncG9zdGdyZXM6MTYtYWxwaW5lJwogICAgdm9sdW1lczoKICAgICAgLSAnZm9yZ2Vqby1wb3N0Z3Jlc3FsLWRhdGE6L3Zhci9saWIvcG9zdGdyZXNxbC9kYXRhJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ1BPU1RHUkVTX1VTRVI9JHtTRVJWSUNFX1VTRVJfUE9TVEdSRVNRTH0nCiAgICAgIC0gJ1BPU1RHUkVTX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU1FMfScKICAgICAgLSAnUE9TVEdSRVNfREI9JHtQT1NUR1JFU1FMX0RBVEFCQVNFfScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ELVNIRUxMCiAgICAgICAgLSAncGdfaXNyZWFkeSAtVSAkJHtQT1NUR1JFU19VU0VSfSAtZCAkJHtQT1NUR1JFU19EQn0nCiAgICAgIGludGVydmFsOiA1cwogICAgICB0aW1lb3V0OiAyMHMKICAgICAgcmV0cmllczogMTAK",
|
||||
"tags": [
|
||||
"version control",
|
||||
"collaboration",
|
||||
@@ -1631,13 +1631,13 @@
|
||||
"category": "git",
|
||||
"logo": "svgs/forgejo.svg",
|
||||
"minversion": "0.0.0",
|
||||
"template_last_updated_at": "2026-02-04T17:34:52+01:00",
|
||||
"template_last_updated_at": "2026-08-10T11:35:20+02:00",
|
||||
"port": "3000"
|
||||
},
|
||||
"forgejo": {
|
||||
"documentation": "https://forgejo.org/docs?utm_source=coolify.io",
|
||||
"slogan": "Forgejo is a self-hosted lightweight software forge. Easy to install and low maintenance, it just does the job.",
|
||||
"compose": "c2VydmljZXM6CiAgZm9yZ2VqbzoKICAgIGltYWdlOiAnY29kZWJlcmcub3JnL2Zvcmdlam8vZm9yZ2Vqbzo4JwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9GUUROX0ZPUkdFSk9fMzAwMAogICAgICAtICdGT1JHRUpPX19zZXJ2ZXJfX1JPT1RfVVJMPSR7U0VSVklDRV9GUUROX0ZPUkdFSk99JwogICAgICAtICdGT1JHRUpPX19taWdyYXRpb25zX19BTExPV0VEX0RPTUFJTlM9JHtGT1JHRUpPX19taWdyYXRpb25zX19BTExPV0VEX0RPTUFJTlN9JwogICAgICAtICdGT1JHRUpPX19taWdyYXRpb25zX19BTExPV19MT0NBTE5FVFdPUktTPSR7Rk9SR0VKT19fbWlncmF0aW9uc19fQUxMT1dfTE9DQUxORVRXT1JLUy1mYWxzZX0nCiAgICAgIC0gVVNFUl9VSUQ9MTAwMAogICAgICAtIFVTRVJfR0lEPTEwMDAKICAgIHBvcnRzOgogICAgICAtICcyMjIyMjoyMicKICAgIHZvbHVtZXM6CiAgICAgIC0gJ2Zvcmdlam8tZGF0YTovZGF0YScKICAgICAgLSAnZm9yZ2Vqby10aW1lem9uZTovZXRjL3RpbWV6b25lOnJvJwogICAgICAtICdmb3JnZWpvLWxvY2FsdGltZTovZXRjL2xvY2FsdGltZTpybycKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSBjdXJsCiAgICAgICAgLSAnLWYnCiAgICAgICAgLSAnaHR0cDovLzEyNy4wLjAuMTozMDAwJwogICAgICBpbnRlcnZhbDogMnMKICAgICAgdGltZW91dDogMTBzCiAgICAgIHJldHJpZXM6IDE1Cg==",
|
||||
"compose": "c2VydmljZXM6CiAgZm9yZ2VqbzoKICAgIGltYWdlOiAnY29kZWJlcmcub3JnL2Zvcmdlam8vZm9yZ2VqbzoxNScKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9GT1JHRUpPXzMwMDAKICAgICAgLSAnRk9SR0VKT19fc2VydmVyX19ST09UX1VSTD0ke1NFUlZJQ0VfRlFETl9GT1JHRUpPfScKICAgICAgLSAnRk9SR0VKT19fbWlncmF0aW9uc19fQUxMT1dFRF9ET01BSU5TPSR7Rk9SR0VKT19fbWlncmF0aW9uc19fQUxMT1dFRF9ET01BSU5TfScKICAgICAgLSAnRk9SR0VKT19fbWlncmF0aW9uc19fQUxMT1dfTE9DQUxORVRXT1JLUz0ke0ZPUkdFSk9fX21pZ3JhdGlvbnNfX0FMTE9XX0xPQ0FMTkVUV09SS1MtZmFsc2V9JwogICAgICAtIFVTRVJfVUlEPTEwMDAKICAgICAgLSBVU0VSX0dJRD0xMDAwCiAgICBwb3J0czoKICAgICAgLSAnMjIyMjI6MjInCiAgICB2b2x1bWVzOgogICAgICAtICdmb3JnZWpvLWRhdGE6L2RhdGEnCiAgICAgIC0gJ2Zvcmdlam8tdGltZXpvbmU6L2V0Yy90aW1lem9uZTpybycKICAgICAgLSAnZm9yZ2Vqby1sb2NhbHRpbWU6L2V0Yy9sb2NhbHRpbWU6cm8nCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRAogICAgICAgIC0gY3VybAogICAgICAgIC0gJy1mJwogICAgICAgIC0gJ2h0dHA6Ly8xMjcuMC4wLjE6MzAwMCcKICAgICAgaW50ZXJ2YWw6IDJzCiAgICAgIHRpbWVvdXQ6IDEwcwogICAgICByZXRyaWVzOiAxNQo=",
|
||||
"tags": [
|
||||
"version control",
|
||||
"collaboration",
|
||||
@@ -1648,7 +1648,7 @@
|
||||
"category": "git",
|
||||
"logo": "svgs/forgejo.svg",
|
||||
"minversion": "0.0.0",
|
||||
"template_last_updated_at": "2026-02-04T17:34:52+01:00",
|
||||
"template_last_updated_at": "2026-08-10T11:35:20+02:00",
|
||||
"port": "3000"
|
||||
},
|
||||
"formbricks": {
|
||||
@@ -2385,6 +2385,24 @@
|
||||
"template_last_updated_at": "2025-12-15T17:56:33+01:00",
|
||||
"port": "8080"
|
||||
},
|
||||
"influxdb": {
|
||||
"documentation": "https://docs.influxdata.com/influxdb/?utm_source=coolify.io",
|
||||
"slogan": "Open source time series database for metrics, events, and analytics.",
|
||||
"compose": "c2VydmljZXM6CiAgaW5mbHV4ZGI6CiAgICBpbWFnZTogJ2luZmx1eGRiOjIuNy1hbHBpbmUnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTRVJWSUNFX0ZRRE5fSU5GTFVYREJfODA4NgogICAgICAtICdJTkZMVVhEQl9IVFRQX0JJTkRfQUREUkVTUz06ODA4NicKICAgICAgLSBJTkZMVVhEQl9JTklUX01PREU9c2V0dXAKICAgICAgLSBJTkZMVVhEQl9JTklUX1VTRVJOQU1FPSRTRVJWSUNFX1VTRVJfSU5GTFVYREIKICAgICAgLSBJTkZMVVhEQl9JTklUX1BBU1NXT1JEPSRTRVJWSUNFX1BBU1NXT1JEX0lORkxVWERCCiAgICAgIC0gSU5GTFVYREJfSU5JVF9PUkc9JFNFUlZJQ0VfT1JHX0lORkxVWERCCiAgICAgIC0gSU5GTFVYREJfSU5JVF9CVUNLRVQ9JFNFUlZJQ0VfQlVDS0VUX0lORkxVWERCCiAgICAgIC0gSU5GTFVYREJfSU5JVF9SRVRFTlRJT049MAogICAgICAtIElORkxVWERCX0lOSVRfQURNSU5fVE9LRU49JFNFUlZJQ0VfUEFTU1dPUkRfSU5GTFVYREJfVE9LRU4KICAgIHZvbHVtZXM6CiAgICAgIC0gJ2luZmx1eGRiLWRhdGE6L3Zhci9saWIvaW5mbHV4ZGIyJwogICAgICAtICdpbmZsdXhkYi1jb25maWc6L2V0Yy9pbmZsdXhkYjInCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRAogICAgICAgIC0gaW5mbHV4CiAgICAgICAgLSBwaW5nCiAgICAgICAgLSAnLS1ob3N0JwogICAgICAgIC0gJ2h0dHA6Ly8xMjcuMC4wLjE6ODA4NicKICAgICAgaW50ZXJ2YWw6IDEwcwogICAgICB0aW1lb3V0OiA1cwogICAgICByZXRyaWVzOiA1CiAgICAgIHN0YXJ0X3BlcmlvZDogMjBzCg==",
|
||||
"tags": [
|
||||
"influxdb",
|
||||
"time series",
|
||||
"metrics",
|
||||
"iot",
|
||||
"monitoring",
|
||||
"telegraf"
|
||||
],
|
||||
"category": "databases",
|
||||
"logo": "svgs/influxdb.svg",
|
||||
"minversion": "0.0.0",
|
||||
"template_last_updated_at": "2026-08-10T12:53:16+02:00",
|
||||
"port": "8086"
|
||||
},
|
||||
"inngest": {
|
||||
"documentation": "https://www.inngest.com/docs/self-hosting?utm_source=coolify.io",
|
||||
"slogan": "Durable workflow engine for background jobs, queues and scheduled tasks.",
|
||||
@@ -2863,7 +2881,7 @@
|
||||
"litellm": {
|
||||
"documentation": "https://docs.litellm.ai?utm_source=coolify.io",
|
||||
"slogan": "Call all LLM APIs using the OpenAI format. Use Bedrock, Azure, OpenAI, Cohere, Anthropic, Ollama, Sagemaker, HuggingFace, Replicate, Groq (100+ LLMs)",
|
||||
"compose": "c2VydmljZXM6CiAgbGl0ZWxsbToKICAgIGltYWdlOiAnZ2hjci5pby9iZXJyaWFpL2xpdGVsbG0tZGF0YWJhc2U6bWFpbi1zdGFibGUnCiAgICBkZXBlbmRzX29uOgogICAgICBwb3N0Z3JlczoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgICByZWRpczoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9GUUROX0xJVEVMTE1fNDAwMAogICAgICAtICdMSVRFTExNX0xPRz0ke0xJVEVMTE1fTE9HOi1FUlJPUn0nCiAgICAgIC0gJ0xJVEVMTE1fTU9ERT0ke0xJVEVMTE1fTU9ERTotUFJPRFVDVElPTn0nCiAgICAgIC0gJ0xJVEVMTE1fTUFTVEVSX0tFWT0ke1NFUlZJQ0VfUEFTU1dPUkRfTUFTVEVSS0VZfScKICAgICAgLSAnVUlfVVNFUk5BTUU9JHtTRVJWSUNFX1VTRVJfVUl9JwogICAgICAtICdVSV9QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfVUl9JwogICAgICAtICdEQVRBQkFTRV9VUkw9cG9zdGdyZXNxbDovLyR7U0VSVklDRV9VU0VSX1BPU1RHUkVTfToke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVN9QHBvc3RncmVzOjU0MzIvJHtQT1NUR1JFU19EQjotbGl0ZWxsbX0nCiAgICAgIC0gJ1JFRElTX0hPU1Q9JHtSRURJU19IT1NUOi1yZWRpc30nCiAgICAgIC0gJ1JFRElTX1BPUlQ9JHtSRURJU19QT1JUOi02Mzc5fScKICAgICAgLSAnUE9TVEdSRVNfVVNFUj0ke1NFUlZJQ0VfVVNFUl9QT1NUR1JFU30nCiAgICAgIC0gJ1BPU1RHUkVTX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU30nCiAgICAgIC0gJ1BPU1RHUkVTX0RCPSR7UE9TVEdSRVNfREI6LWxpdGVsbG19JwogICAgICAtICdPUEVOQUlfQVBJX0tFWT0ke09QRU5BSV9BUElfS0VZfScKICAgICAgLSAnT1BFTkFJX0FQSV9CQVNFPSR7T1BFTkFJX0FQSV9CQVNFfScKICAgICAgLSAnQU5USFJPUElDX0FQSV9LRVk9JHtBTlRIUk9QSUNfQVBJX0tFWX0nCiAgICAgIC0gJ0FOVEhST1BJQ19BUElfQkFTRT0ke0FOVEhST1BJQ19BUElfQkFTRX0nCiAgICAgIC0gJ1ZPWUFHRV9BUElfS0VZPSR7Vk9ZQUdFX0FQSV9LRVl9JwogICAgICAtICdWT1lBR0VfQVBJX0JBU0U9JHtWT1lBR0VfQVBJX0JBU0V9JwogICAgICAtICdTVE9SRV9NT0RFTF9JTl9EQj0ke1NUT1JFX01PREVMX0lOX0RCfScKICAgIHZvbHVtZXM6CiAgICAgIC0KICAgICAgICB0eXBlOiBiaW5kCiAgICAgICAgc291cmNlOiAuL2xpdGVsbG0tY29uZmlnLnlhbWwKICAgICAgICB0YXJnZXQ6IC9hcHAvY29uZmlnLnlhbWwKICAgICAgICBjb250ZW50OiAiZ2VuZXJhbF9zZXR0aW5nczpcbiAgcHJveHlfYmF0Y2hfd3JpdGVfYXQ6IDYwXG5cbnJvdXRlcl9zZXR0aW5nczpcbiAgcmVkaXNfaG9zdDogb3MuZW52aXJvbi9SRURJU19IT1NUXG4gIHJlZGlzX3BvcnQ6IG9zLmVudmlyb24vUkVESVNfUE9SVFxuICByZWRpc19wYXNzd29yZDogb3MuZW52aXJvbi9SRURJU19QQVNTV09SRFxuICBlbmFibGVfcHJlX2NhbGxfY2hlY2s6IHRydWVcblxubGl0ZWxsbV9zZXR0aW5nczpcbiAgc2V0X3ZlcmJvc2U6IGZhbHNlXG4gIGpzb25fbG9nczogdHJ1ZVxuICBsb2dfcmF3X3JlcXVlc3RfcmVzcG9uc2U6IHRydWVcbiAgIyB0dXJuX29mZl9tZXNzYWdlX2xvZ2dpbmc6IGZhbHNlXG4gICMgcmVkYWN0X3VzZXJfYXBpX2tleV9pbmZvOiBmYWxzZVxuICBzZXJ2aWNlX2NhbGxiYWNrOiBbXCJwcm9tZXRoZXVzX3N5c3RlbVwiXVxuICBkcm9wX3BhcmFtczogdHJ1ZVxuICAjIG1heF9idWRnZXQ6IDEwMFxuICAjIGJ1ZGdldF9kdXJhdGlvbjogMzBkXG4gIG51bV9yZXRyaWVzOiAzXG4gIHJlcXVlc3RfdGltZW91dDogNjAwXG4gIHRlbGVtZXRyeTogZmFsc2VcbiAgY2FjaGU6IHRydWVcbiAgY2FjaGVfcGFyYW1zOlxuICAgIHR5cGU6IHJlZGlzXG4gICAgaG9zdDogb3MuZW52aXJvbi9SRURJU19IT1NUXG4gICAgcG9ydDogb3MuZW52aXJvbi9SRURJU19QT1JUXG4gICAgcGFzc3dvcmQ6IG9zLmVudmlyb24vUkVESVNfUEFTU1dPUkRcbiAgICBuYW1lc3BhY2U6IFwibGl0ZWxsbV9jYWNoZVwiXG4gICAgdHRsOiA2MDBcbiAgc3VjY2Vzc19jYWxsYmFjazpcbiAgICAjIC0gXCJsYW5nZnVzZVwiXG4gICAgLSBcInByb21ldGhldXNcIlxuICBmYWlsdXJlX2NhbGxiYWNrOlxuICAgICMgLSBcImxhbmdmdXNlXCJcbiAgICAtIFwicHJvbWV0aGV1c1wiXG5tb2RlbF9saXN0OlxuICAjIE9wZW5BSVxuICAtIG1vZGVsX25hbWU6IGdwdC00XG4gICAgbGl0ZWxsbV9wYXJhbXM6XG4gICAgICBtb2RlbDogb3BlbmFpL2dwdC00XG4gICAgICBhcGlfa2V5OiBvcy5lbnZpcm9uL09QRU5BSV9BUElfS0VZXG4gICAgICBhcGlfYmFzZTogb3MuZW52aXJvbi9PUEVOQUlfQVBJX0JBU0VcbiAgLSBtb2RlbF9uYW1lOiBncHQtNG9cbiAgICBsaXRlbGxtX3BhcmFtczpcbiAgICAgIG1vZGVsOiBvcGVuYWkvZ3B0LTRvXG4gICAgICBhcGlfa2V5OiBvcy5lbnZpcm9uL09QRU5BSV9BUElfS0VZXG4gICAgICBhcGlfYmFzZTogb3MuZW52aXJvbi9PUEVOQUlfQVBJX0JBU0VcbiAgLSBtb2RlbF9uYW1lOiBncHQtNG8tbWluaVxuICAgIGxpdGVsbG1fcGFyYW1zOlxuICAgICAgbW9kZWw6IG9wZW5haS9ncHQtNG8tbWluaVxuICAgICAgYXBpX2tleTogb3MuZW52aXJvbi9PUEVOQUlfQVBJX0tFWVxuICAgICAgYXBpX2Jhc2U6IG9zLmVudmlyb24vT1BFTkFJX0FQSV9CQVNFXG4gICMgQW50aHJvcGljXG4gIC0gbW9kZWxfbmFtZTogY2xhdWRlLTMtaGFpa3VcbiAgICBsaXRlbGxtX3BhcmFtczpcbiAgICAgIG1vZGVsOiBjbGF1ZGUtMy1oYWlrdS0yMDI0MDMwN1xuICAgICAgYXBpX2tleTogXCJvcy5lbnZpcm9uL0FOVEhST1BJQ19BUElfS0VZXCJcbiAgICAgIGFwaV9iYXNlOiBcIm9zLmVudmlyb24vQU5USFJPUElDX0FQSV9CQVNFXCJcbiAgLSBtb2RlbF9uYW1lOiBjbGF1ZGUtMy41LXNvbm5ldFxuICAgIGxpdGVsbG1fcGFyYW1zOlxuICAgICAgbW9kZWw6IGNsYXVkZS0zLTUtc29ubmV0LTIwMjQwNjIwXG4gICAgICBhcGlfa2V5OiBcIm9zLmVudmlyb24vQU5USFJPUElDX0FQSV9LRVlcIlxuICAgICAgYXBpX2Jhc2U6IFwib3MuZW52aXJvbi9BTlRIUk9QSUNfQVBJX0JBU0VcIlxuICAjIFZveWFnZUFJXG4gIC0gbW9kZWxfbmFtZTogdm95YWdlLWxhdy0yXG4gICAgbW9kZWxfaW5mbzpcbiAgICAgIG91dHB1dF92ZWN0b3Jfc2l6ZTogMTAyNFxuICAgIGxpdGVsbG1fcGFyYW1zOlxuICAgICAgbW9kZWw6IHZveWFnZS92b3lhZ2UtbGF3LTJcbiAgICAgIGFwaV9rZXk6IFwib3MuZW52aXJvbi9WT1lBR0VfQVBJX0tFWVwiXG4gICAgICBhcGlfYmFzZTogXCJvcy5lbnZpcm9uL1ZPWUFHRV9BUElfQkFTRVwiXG4gICAgICAjIHJwbTogMzAwXG4gICAgICAjIHRwbTogMTAwMDAwMFxuICAtIG1vZGVsX25hbWU6IHZveWFnZS1tdWx0aWxpbmd1YWwtMlxuICAgIG1vZGVsX2luZm86XG4gICAgICBtb2RlOiBlbWJlZGRpbmdcbiAgICAgIG1heF90b2tlbnM6IDMyMDAwXG4gICAgICBtYXhfaW5wdXRfdG9rZW5zOiAzMjAwMFxuICAgICAgb3V0cHV0X3ZlY3Rvcl9zaXplOiAxMDI0XG4gICAgbGl0ZWxsbV9wYXJhbXM6XG4gICAgICBtb2RlbDogdm95YWdlL3ZveWFnZS1tdWx0aWxpbmd1YWwtMlxuICAgICAgYXBpX2tleTogXCJvcy5lbnZpcm9uL1ZPWUFHRV9BUElfS0VZXCJcbiAgICAgIGFwaV9iYXNlOiBcIm9zLmVudmlyb24vVk9ZQUdFX0FQSV9CQVNFXCJcbiAgICAgIGlucHV0X2Nvc3RLine truncated
|
||||
"compose": "c2VydmljZXM6CiAgbGl0ZWxsbToKICAgIGltYWdlOiAnZ2hjci5pby9iZXJyaWFpL2xpdGVsbG0tZGF0YWJhc2U6bWFpbi1zdGFibGUnCiAgICBkZXBlbmRzX29uOgogICAgICBwb3N0Z3JlczoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgICByZWRpczoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9GUUROX0xJVEVMTE1fNDAwMAogICAgICAtICdMSVRFTExNX0xPRz0ke0xJVEVMTE1fTE9HOi1FUlJPUn0nCiAgICAgIC0gJ0xJVEVMTE1fTU9ERT0ke0xJVEVMTE1fTU9ERTotUFJPRFVDVElPTn0nCiAgICAgIC0gJ0xJVEVMTE1fTUFTVEVSX0tFWT0ke1NFUlZJQ0VfUEFTU1dPUkRfTUFTVEVSS0VZfScKICAgICAgLSAnVUlfVVNFUk5BTUU9JHtTRVJWSUNFX1VTRVJfVUl9JwogICAgICAtICdVSV9QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfVUl9JwogICAgICAtICdEQVRBQkFTRV9VUkw9cG9zdGdyZXNxbDovLyR7U0VSVklDRV9VU0VSX1BPU1RHUkVTfToke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVN9QHBvc3RncmVzOjU0MzIvJHtQT1NUR1JFU19EQjotbGl0ZWxsbX0nCiAgICAgIC0gJ1JFRElTX0hPU1Q9JHtSRURJU19IT1NUOi1yZWRpc30nCiAgICAgIC0gJ1JFRElTX1BPUlQ9JHtSRURJU19QT1JUOi02Mzc5fScKICAgICAgLSAnUE9TVEdSRVNfVVNFUj0ke1NFUlZJQ0VfVVNFUl9QT1NUR1JFU30nCiAgICAgIC0gJ1BPU1RHUkVTX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU30nCiAgICAgIC0gJ1BPU1RHUkVTX0RCPSR7UE9TVEdSRVNfREI6LWxpdGVsbG19JwogICAgICAtICdPUEVOQUlfQVBJX0tFWT0ke09QRU5BSV9BUElfS0VZfScKICAgICAgLSAnT1BFTkFJX0FQSV9CQVNFPSR7T1BFTkFJX0FQSV9CQVNFfScKICAgICAgLSAnQU5USFJPUElDX0FQSV9LRVk9JHtBTlRIUk9QSUNfQVBJX0tFWX0nCiAgICAgIC0gJ0FOVEhST1BJQ19BUElfQkFTRT0ke0FOVEhST1BJQ19BUElfQkFTRX0nCiAgICAgIC0gJ1ZPWUFHRV9BUElfS0VZPSR7Vk9ZQUdFX0FQSV9LRVl9JwogICAgICAtICdWT1lBR0VfQVBJX0JBU0U9JHtWT1lBR0VfQVBJX0JBU0V9JwogICAgICAtICdTVE9SRV9NT0RFTF9JTl9EQj0ke1NUT1JFX01PREVMX0lOX0RCfScKICAgIHZvbHVtZXM6CiAgICAgIC0KICAgICAgICB0eXBlOiBiaW5kCiAgICAgICAgc291cmNlOiAuL2xpdGVsbG0tY29uZmlnLnlhbWwKICAgICAgICB0YXJnZXQ6IC9hcHAvY29uZmlnLnlhbWwKICAgICAgICBjb250ZW50OiAiZ2VuZXJhbF9zZXR0aW5nczpcbiAgcHJveHlfYmF0Y2hfd3JpdGVfYXQ6IDYwXG4gIHN0b3JlX3Byb21wdHNfaW5fc3BlbmRfbG9nczogZmFsc2Vcblxucm91dGVyX3NldHRpbmdzOlxuICByZWRpc19ob3N0OiBvcy5lbnZpcm9uL1JFRElTX0hPU1RcbiAgcmVkaXNfcG9ydDogb3MuZW52aXJvbi9SRURJU19QT1JUXG4gIHJlZGlzX3Bhc3N3b3JkOiBvcy5lbnZpcm9uL1JFRElTX1BBU1NXT1JEXG4gIGVuYWJsZV9wcmVfY2FsbF9jaGVjazogdHJ1ZVxuXG5saXRlbGxtX3NldHRpbmdzOlxuICBzZXRfdmVyYm9zZTogZmFsc2VcbiAganNvbl9sb2dzOiB0cnVlXG4gIGxvZ19yYXdfcmVxdWVzdF9yZXNwb25zZTogZmFsc2VcbiAgIyB0dXJuX29mZl9tZXNzYWdlX2xvZ2dpbmc6IGZhbHNlXG4gICMgcmVkYWN0X3VzZXJfYXBpX2tleV9pbmZvOiBmYWxzZVxuICBzZXJ2aWNlX2NhbGxiYWNrOiBbXCJwcm9tZXRoZXVzX3N5c3RlbVwiXVxuICBkcm9wX3BhcmFtczogdHJ1ZVxuICAjIG1heF9idWRnZXQ6IDEwMFxuICAjIGJ1ZGdldF9kdXJhdGlvbjogMzBkXG4gIG51bV9yZXRyaWVzOiAxXG4gIHJlcXVlc3RfdGltZW91dDogMTIwXG4gIHRlbGVtZXRyeTogZmFsc2VcbiAgY2FjaGU6IHRydWVcbiAgY2FjaGVfcGFyYW1zOlxuICAgIHR5cGU6IHJlZGlzXG4gICAgaG9zdDogb3MuZW52aXJvbi9SRURJU19IT1NUXG4gICAgcG9ydDogb3MuZW52aXJvbi9SRURJU19QT1JUXG4gICAgcGFzc3dvcmQ6IG9zLmVudmlyb24vUkVESVNfUEFTU1dPUkRcbiAgICBuYW1lc3BhY2U6IFwibGl0ZWxsbV9jYWNoZVwiXG4gICAgdHRsOiA2MDBcbiAgc3VjY2Vzc19jYWxsYmFjazpcbiAgICAjIC0gXCJsYW5nZnVzZVwiXG4gICAgLSBcInByb21ldGhldXNcIlxuICBmYWlsdXJlX2NhbGxiYWNrOlxuICAgICMgLSBcImxhbmdmdXNlXCJcbiAgICAtIFwicHJvbWV0aGV1c1wiXG5tb2RlbF9saXN0OlxuICAjIE9wZW5BSVxuICAtIG1vZGVsX25hbWU6IGdwdC00XG4gICAgbGl0ZWxsbV9wYXJhbXM6XG4gICAgICBtb2RlbDogb3BlbmFpL2dwdC00XG4gICAgICBhcGlfa2V5OiBvcy5lbnZpcm9uL09QRU5BSV9BUElfS0VZXG4gICAgICBhcGlfYmFzZTogb3MuZW52aXJvbi9PUEVOQUlfQVBJX0JBU0VcbiAgLSBtb2RlbF9uYW1lOiBncHQtNG9cbiAgICBsaXRlbGxtX3BhcmFtczpcbiAgICAgIG1vZGVsOiBvcGVuYWkvZ3B0LTRvXG4gICAgICBhcGlfa2V5OiBvcy5lbnZpcm9uL09QRU5BSV9BUElfS0VZXG4gICAgICBhcGlfYmFzZTogb3MuZW52aXJvbi9PUEVOQUlfQVBJX0JBU0VcbiAgLSBtb2RlbF9uYW1lOiBncHQtNG8tbWluaVxuICAgIGxpdGVsbG1fcGFyYW1zOlxuICAgICAgbW9kZWw6IG9wZW5haS9ncHQtNG8tbWluaVxuICAgICAgYXBpX2tleTogb3MuZW52aXJvbi9PUEVOQUlfQVBJX0tFWVxuICAgICAgYXBpX2Jhc2U6IG9zLmVudmlyb24vT1BFTkFJX0FQSV9CQVNFXG4gICMgQW50aHJvcGljXG4gIC0gbW9kZWxfbmFtZTogY2xhdWRlLTMtaGFpa3VcbiAgICBsaXRlbGxtX3BhcmFtczpcbiAgICAgIG1vZGVsOiBjbGF1ZGUtMy1oYWlrdS0yMDI0MDMwN1xuICAgICAgYXBpX2tleTogXCJvcy5lbnZpcm9uL0FOVEhST1BJQ19BUElfS0VZXCJcbiAgICAgIGFwaV9iYXNlOiBcIm9zLmVudmlyb24vQU5USFJPUElDX0FQSV9CQVNFXCJcbiAgLSBtb2RlbF9uYW1lOiBjbGF1ZGUtMy41LXNvbm5ldFxuICAgIGxpdGVsbG1fcGFyYW1zOlxuICAgICAgbW9kZWw6IGNsYXVkZS0zLTUtc29ubmV0LTIwMjQwNjIwXG4gICAgICBhcGlfa2V5OiBcIm9zLmVudmlyb24vQU5USFJPUElDX0FQSV9LRVlcIlxuICAgICAgYXBpX2Jhc2U6IFwib3MuZW52aXJvbi9BTlRIUk9QSUNfQVBJX0JBU0VcIlxuICAjIFZveWFnZUFJXG4gIC0gbW9kZWxfbmFtZTogdm95YWdlLWxhdy0yXG4gICAgbW9kZWxfaW5mbzpcbiAgICAgIG91dHB1dF92ZWN0b3Jfc2l6ZTogMTAyNFxuICAgIGxpdGVsbG1fcGFyYW1zOlxuICAgICAgbW9kZWw6IHZveWFnZS92b3lhZ2UtbGF3LTJcbiAgICAgIGFwaV9rZXk6IFwib3MuZW52aXJvbi9WT1lBR0VfQVBJX0tFWVwiXG4gICAgICBhcGlfYmFzZTogXCJvcy5lbnZpcm9uL1ZPWUFHRV9BUElfQkFTRVwiXG4gICAgICAjIHJwbTogMzAwXG4gICAgICAjIHRwbTogMTAwMDAwMFxuICAtIG1vZGVsX25hbWU6IHZveWFnZS1tdWx0aWxpbmd1YWwtMlxuICAgIG1vZGVsX2luZm86XG4gICAgICBtb2RlOiBlbWJlZGRpbmdcbiAgICAgIG1heF90b2tlbnM6IDMyMDAwXG4gICAgICBtYXhfaW5wdXRfdG9rZW5zOiAzMjAwMFxuICAgICAgb3V0cHV0X3ZlY3Rvcl9zaXplOiAxMDI0XG4gICAgbGl0ZWxsbV9wYXJhbXM6XG4gICAgICBtb2RlbDogdm95YWdlL3ZveWFnZS1tdWx0aWxpbmd1YWwtMlxuICAgICAgYXBpX2tleTogXCJvcy5lbnZpcm9uL1ZPWUFHRV9BUElfS0VZXCJcbiAgICAgIGFwaV9iYXNlOiBcIm9zLmVudmlLine truncated
|
||||
"tags": [
|
||||
"ai",
|
||||
"qdrant",
|
||||
@@ -2884,7 +2902,7 @@
|
||||
"category": "ai",
|
||||
"logo": "svgs/litellm.svg",
|
||||
"minversion": "0.0.0",
|
||||
"template_last_updated_at": "2025-12-14T21:08:27+01:00",
|
||||
"template_last_updated_at": "2026-08-10T13:08:06+02:00",
|
||||
"port": "4000"
|
||||
},
|
||||
"lobe-chat": {
|
||||
@@ -3834,7 +3852,7 @@
|
||||
"opnform": {
|
||||
"documentation": "https://docs.opnform.com/introduction?utm_source=coolify.io",
|
||||
"slogan": "OpnForm is an open-source form builder that lets you create beautiful forms and share them anywhere. It's super fast, you don't need to know how to code",
|
||||
"compose": "eC1zaGFyZWQtZW52OgogIEFQUF9OQU1FOiBPcG5Gb3JtCiAgQVBQX0VOVjogcHJvZHVjdGlvbgogIEFQUF9LRVk6ICcke1NFUlZJQ0VfQkFTRTY0X0FQSUtFWX0nCiAgQVBQX0RFQlVHOiAnJHtBUFBfREVCVUc6LWZhbHNlfScKICBBUFBfVVJMOiAnJHtTRVJWSUNFX0ZRRE5fTkdJTlh9JwogIExPR19DSEFOTkVMOiBlcnJvcmxvZwogIExPR19MRVZFTDogJyR7TE9HX0xFVkVMOi1kZWJ1Z30nCiAgRklMRVNZU1RFTV9EUklWRVI6ICcke0ZJTEVTWVNURU1fRFJJVkVSOi1sb2NhbH0nCiAgTE9DQUxfRklMRVNZU1RFTV9WSVNJQklMSVRZOiBwdWJsaWMKICBDQUNIRV9EUklWRVI6IHJlZGlzCiAgUVVFVUVfQ09OTkVDVElPTjogcmVkaXMKICBTRVNTSU9OX0RSSVZFUjogcmVkaXMKICBTRVNTSU9OX0xJRkVUSU1FOiAxMjAKICBNQUlMX01BSUxFUjogJyR7TUFJTF9NQUlMRVI6LWxvZ30nCiAgTUFJTF9IT1NUOiAnJHtNQUlMX0hPU1R9JwogIE1BSUxfUE9SVDogJyR7TUFJTF9QT1JUfScKICBNQUlMX1VTRVJOQU1FOiAnJHtNQUlMX1VTRVJOQU1FOi15b3VyQGVtYWlsLmNvbX0nCiAgTUFJTF9QQVNTV09SRDogJyR7TUFJTF9QQVNTV09SRH0nCiAgTUFJTF9FTkNSWVBUSU9OOiAnJHtNQUlMX0VOQ1JZUFRJT059JwogIE1BSUxfRlJPTV9BRERSRVNTOiAnJHtNQUlMX0ZST01fQUREUkVTUzoteW91ckBlbWFpbC5jb219JwogIE1BSUxfRlJPTV9OQU1FOiAnJHtNQUlMX0ZST01fTkFNRTotT3BuRm9ybX0nCiAgQVdTX0FDQ0VTU19LRVlfSUQ6ICcke0FXU19BQ0NFU1NfS0VZX0lEfScKICBBV1NfU0VDUkVUX0FDQ0VTU19LRVk6ICcke0FXU19TRUNSRVRfQUNDRVNTX0tFWX0nCiAgQVdTX0RFRkFVTFRfUkVHSU9OOiAnJHtBV1NfREVGQVVMVF9SRUdJT046LXVzLWVhc3QtMX0nCiAgQVdTX0JVQ0tFVDogJyR7QVdTX0JVQ0tFVH0nCiAgT1BFTl9BSV9BUElfS0VZOiAnJHtPUEVOX0FJX0FQSV9LRVl9JwogIFRFTEVHUkFNX0JPVF9JRDogJyR7VEVMRUdSQU1fQk9UX0lEfScKICBURUxFR1JBTV9CT1RfVE9LRU46ICcke1RFTEVHUkFNX0JPVF9UT0tFTn0nCiAgUkVESVNfSE9TVDogcmVkaXMKICBSRURJU19QQVNTV09SRDogJyR7U0VSVklDRV9QQVNTV09SRF82NF9SRURJU30nCiAgREJfSE9TVDogcG9zdGdyZXNxbAogIERCX0RBVEFCQVNFOiAnJHtQT1NUR1JFU1FMX0RBVEFCQVNFOi1vcG5mb3JtfScKICBEQl9VU0VSTkFNRTogJyR7U0VSVklDRV9VU0VSX1BPU1RHUkVTUUx9JwogIERCX1BBU1NXT1JEOiAnJHtTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTUUx9JwogIERCX0NPTk5FQ1RJT046IHBnc3FsCiAgUEhQX01FTU9SWV9MSU1JVDogMUcKICBQSFBfTUFYX0VYRUNVVElPTl9USU1FOiAnNjAwJwogIFBIUF9VUExPQURfTUFYX0ZJTEVTSVpFOiA2NE0KICBQSFBfUE9TVF9NQVhfU0laRTogNjRNCnNlcnZpY2VzOgogIG9wbmZvcm0tYXBpOgogICAgaW1hZ2U6ICdqaHVtYW5qL29wbmZvcm0tYXBpOjEuMTIuMScKICAgIHZvbHVtZXM6CiAgICAgIC0gJ2FwaS1zdG9yYWdlOi91c3Ivc2hhcmUvbmdpbngvaHRtbC9zdG9yYWdlJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIEFQUF9OQU1FOiBPcG5Gb3JtCiAgICAgIEFQUF9FTlY6IHByb2R1Y3Rpb24KICAgICAgQVBQX0tFWTogJyR7U0VSVklDRV9CQVNFNjRfQVBJS0VZfScKICAgICAgQVBQX0RFQlVHOiAnJHtBUFBfREVCVUc6LWZhbHNlfScKICAgICAgQVBQX1VSTDogJyR7U0VSVklDRV9GUUROX05HSU5YfScKICAgICAgTE9HX0NIQU5ORUw6IGVycm9ybG9nCiAgICAgIExPR19MRVZFTDogJyR7TE9HX0xFVkVMOi1kZWJ1Z30nCiAgICAgIEZJTEVTWVNURU1fRFJJVkVSOiAnJHtGSUxFU1lTVEVNX0RSSVZFUjotbG9jYWx9JwogICAgICBMT0NBTF9GSUxFU1lTVEVNX1ZJU0lCSUxJVFk6IHB1YmxpYwogICAgICBDQUNIRV9EUklWRVI6IHJlZGlzCiAgICAgIFFVRVVFX0NPTk5FQ1RJT046IHJlZGlzCiAgICAgIFNFU1NJT05fRFJJVkVSOiByZWRpcwogICAgICBTRVNTSU9OX0xJRkVUSU1FOiAxMjAKICAgICAgTUFJTF9NQUlMRVI6ICcke01BSUxfTUFJTEVSOi1sb2d9JwogICAgICBNQUlMX0hPU1Q6ICcke01BSUxfSE9TVH0nCiAgICAgIE1BSUxfUE9SVDogJyR7TUFJTF9QT1JUfScKICAgICAgTUFJTF9VU0VSTkFNRTogJyR7TUFJTF9VU0VSTkFNRToteW91ckBlbWFpbC5jb219JwogICAgICBNQUlMX1BBU1NXT1JEOiAnJHtNQUlMX1BBU1NXT1JEfScKICAgICAgTUFJTF9FTkNSWVBUSU9OOiAnJHtNQUlMX0VOQ1JZUFRJT059JwogICAgICBNQUlMX0ZST01fQUREUkVTUzogJyR7TUFJTF9GUk9NX0FERFJFU1M6LXlvdXJAZW1haWwuY29tfScKICAgICAgTUFJTF9GUk9NX05BTUU6ICcke01BSUxfRlJPTV9OQU1FOi1PcG5Gb3JtfScKICAgICAgQVdTX0FDQ0VTU19LRVlfSUQ6ICcke0FXU19BQ0NFU1NfS0VZX0lEfScKICAgICAgQVdTX1NFQ1JFVF9BQ0NFU1NfS0VZOiAnJHtBV1NfU0VDUkVUX0FDQ0VTU19LRVl9JwogICAgICBBV1NfREVGQVVMVF9SRUdJT046ICcke0FXU19ERUZBVUxUX1JFR0lPTjotdXMtZWFzdC0xfScKICAgICAgQVdTX0JVQ0tFVDogJyR7QVdTX0JVQ0tFVH0nCiAgICAgIE9QRU5fQUlfQVBJX0tFWTogJyR7T1BFTl9BSV9BUElfS0VZfScKICAgICAgVEVMRUdSQU1fQk9UX0lEOiAnJHtURUxFR1JBTV9CT1RfSUR9JwogICAgICBURUxFR1JBTV9CT1RfVE9LRU46ICcke1RFTEVHUkFNX0JPVF9UT0tFTn0nCiAgICAgIFJFRElTX0hPU1Q6IHJlZGlzCiAgICAgIFJFRElTX1BBU1NXT1JEOiAnJHtTRVJWSUNFX1BBU1NXT1JEXzY0X1JFRElTfScKICAgICAgREJfSE9TVDogcG9zdGdyZXNxbAogICAgICBEQl9EQVRBQkFTRTogJyR7UE9TVEdSRVNRTF9EQVRBQkFTRTotb3BuZm9ybX0nCiAgICAgIERCX1VTRVJOQU1FOiAnJHtTRVJWSUNFX1VTRVJfUE9TVEdSRVNRTH0nCiAgICAgIERCX1BBU1NXT1JEOiAnJHtTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTUUx9JwogICAgICBEQl9DT05ORUNUSU9OOiBwZ3NxbAogICAgICBQSFBfTUVNT1JZX0xJTUlUOiAxRwogICAgICBQSFBfTUFYX0VYRUNVVElPTl9USU1FOiAnNjAwJwogICAgICBQSFBfVVBMT0FEX01BWF9GSUxFU0laRTogNjRNCiAgICAgIFBIUF9QT1NUX01BWF9TSVpFOiA2NE0KICAgICAgSldUX1RUTDogJyR7SldUX1RUTDotMTQ0MH0nCiAgICAgIEpXVF9TRUNSRVQ6ICcke1NFUlZJQ0VfUEFTU1dPUkRfSldUU0VDUkVUfScKICAgICAgSldUX1NLSVBfSVBfVUFfVkFMSURBVElPTjogJyR7SldUX1NLSVBfSVBfVUFfVkFMSURBVElPTjotdHJ1ZX0nCiAgICAgIEhfQ0FQVENIQV9TSVRFX0tFWTogJyR7SF9DQVBUQ0hBX1NJVEVfS0VZfScKICAgICAgSF9DQVBUQ0hBX1NFQ1JFVF9LRVk6ICcke0hfQ0FQVENIQV9TRUNSRVRfS0VZfScKICAgICAgUkVfQ0FQVENIQV9TSVRFX0tFWTogJyR7UkVfQ0FQVENIQV9TSVRFX0tFWX0nCiAgICAgIFJFX0NBUFRDSEFfU0VDUkVUX0tFWTogJyR7UkVfQ0FQVENIQV9TRUNSRVRfS0VZfScKICAgICAgU0hPV19PRkZJQ0lBTF9URU1QTEFURVM6ICcke1NIT1dfT0ZGSUNJQUxfVEVNUExBVEVTOi10cnVlfScKICAgIGRlcGVuZHNfb246CiAgICAgIHBvc3RncmVzcWw6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgICAgcmVkaXM6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ELVNIRUxMCiAgICAgICAgLSAncGhwIC91c3Ivc2hhcmULine truncated
|
||||
"compose": "eC1zaGFyZWQtZW52OgogIEFQUF9OQU1FOiBPcG5Gb3JtCiAgQVBQX0VOVjogcHJvZHVjdGlvbgogIEFQUF9LRVk6ICcke1NFUlZJQ0VfQkFTRTY0X0FQSUtFWX0nCiAgQVBQX0RFQlVHOiAnJHtBUFBfREVCVUc6LWZhbHNlfScKICBBUFBfVVJMOiAnJHtTRVJWSUNFX0ZRRE5fTkdJTlh9JwogIExPR19DSEFOTkVMOiBlcnJvcmxvZwogIExPR19MRVZFTDogJyR7TE9HX0xFVkVMOi1kZWJ1Z30nCiAgRklMRVNZU1RFTV9EUklWRVI6ICcke0ZJTEVTWVNURU1fRFJJVkVSOi1sb2NhbH0nCiAgTE9DQUxfRklMRVNZU1RFTV9WSVNJQklMSVRZOiBwdWJsaWMKICBDQUNIRV9EUklWRVI6IHJlZGlzCiAgUVVFVUVfQ09OTkVDVElPTjogcmVkaXMKICBTRVNTSU9OX0RSSVZFUjogcmVkaXMKICBTRVNTSU9OX0xJRkVUSU1FOiAxMjAKICBNQUlMX01BSUxFUjogJyR7TUFJTF9NQUlMRVI6LWxvZ30nCiAgTUFJTF9IT1NUOiAnJHtNQUlMX0hPU1R9JwogIE1BSUxfUE9SVDogJyR7TUFJTF9QT1JUfScKICBNQUlMX1VTRVJOQU1FOiAnJHtNQUlMX1VTRVJOQU1FOi15b3VyQGVtYWlsLmNvbX0nCiAgTUFJTF9QQVNTV09SRDogJyR7TUFJTF9QQVNTV09SRH0nCiAgTUFJTF9FTkNSWVBUSU9OOiAnJHtNQUlMX0VOQ1JZUFRJT059JwogIE1BSUxfRlJPTV9BRERSRVNTOiAnJHtNQUlMX0ZST01fQUREUkVTUzoteW91ckBlbWFpbC5jb219JwogIE1BSUxfRlJPTV9OQU1FOiAnJHtNQUlMX0ZST01fTkFNRTotT3BuRm9ybX0nCiAgQVdTX0FDQ0VTU19LRVlfSUQ6ICcke0FXU19BQ0NFU1NfS0VZX0lEfScKICBBV1NfU0VDUkVUX0FDQ0VTU19LRVk6ICcke0FXU19TRUNSRVRfQUNDRVNTX0tFWX0nCiAgQVdTX0RFRkFVTFRfUkVHSU9OOiAnJHtBV1NfREVGQVVMVF9SRUdJT046LXVzLWVhc3QtMX0nCiAgQVdTX0JVQ0tFVDogJyR7QVdTX0JVQ0tFVH0nCiAgT1BFTl9BSV9BUElfS0VZOiAnJHtPUEVOX0FJX0FQSV9LRVl9JwogIFRFTEVHUkFNX0JPVF9JRDogJyR7VEVMRUdSQU1fQk9UX0lEfScKICBURUxFR1JBTV9CT1RfVE9LRU46ICcke1RFTEVHUkFNX0JPVF9UT0tFTn0nCiAgUkVESVNfSE9TVDogcmVkaXMKICBSRURJU19QQVNTV09SRDogJyR7U0VSVklDRV9QQVNTV09SRF82NF9SRURJU30nCiAgREJfSE9TVDogcG9zdGdyZXNxbAogIERCX0RBVEFCQVNFOiAnJHtQT1NUR1JFU1FMX0RBVEFCQVNFOi1vcG5mb3JtfScKICBEQl9VU0VSTkFNRTogJyR7U0VSVklDRV9VU0VSX1BPU1RHUkVTUUx9JwogIERCX1BBU1NXT1JEOiAnJHtTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTUUx9JwogIERCX0NPTk5FQ1RJT046IHBnc3FsCiAgUEhQX01FTU9SWV9MSU1JVDogMUcKICBQSFBfTUFYX0VYRUNVVElPTl9USU1FOiAnNjAwJwogIFBIUF9VUExPQURfTUFYX0ZJTEVTSVpFOiA2NE0KICBQSFBfUE9TVF9NQVhfU0laRTogNjRNCiAgRlJPTlRfVVJMOiAnJHtTRVJWSUNFX0ZRRE5fTkdJTlh9JwogIEZST05UX0FQSV9TRUNSRVQ6ICcke1NFUlZJQ0VfUEFTU1dPUkRfRlJPTlRBUElTRUNSRVR9JwogIFBVQkxJQ19VUExPQURTX1JBVEVfTElNSVRfUEVSX01JTlVURTogJyR7UFVCTElDX1VQTE9BRFNfUkFURV9MSU1JVF9QRVJfTUlOVVRFOi0zMH0nCiAgUFVCTElDX1VQTE9BRFNfUkFURV9MSU1JVF9QRVJfSE9VUjogJyR7UFVCTElDX1VQTE9BRFNfUkFURV9MSU1JVF9QRVJfSE9VUjotMzAwfScKc2VydmljZXM6CiAgb3BuZm9ybS1hcGk6CiAgICBpbWFnZTogJ2podW1hbmovb3BuZm9ybS1hcGk6Mi4yLjQnCiAgICB2b2x1bWVzOgogICAgICAtICdhcGktc3RvcmFnZTovdXNyL3NoYXJlL25naW54L2h0bWwvc3RvcmFnZScKICAgIGVudmlyb25tZW50OgogICAgICBBUFBfTkFNRTogT3BuRm9ybQogICAgICBBUFBfRU5WOiBwcm9kdWN0aW9uCiAgICAgIEFQUF9LRVk6ICcke1NFUlZJQ0VfQkFTRTY0X0FQSUtFWX0nCiAgICAgIEFQUF9ERUJVRzogJyR7QVBQX0RFQlVHOi1mYWxzZX0nCiAgICAgIEFQUF9VUkw6ICcke1NFUlZJQ0VfRlFETl9OR0lOWH0nCiAgICAgIExPR19DSEFOTkVMOiBlcnJvcmxvZwogICAgICBMT0dfTEVWRUw6ICcke0xPR19MRVZFTDotZGVidWd9JwogICAgICBGSUxFU1lTVEVNX0RSSVZFUjogJyR7RklMRVNZU1RFTV9EUklWRVI6LWxvY2FsfScKICAgICAgTE9DQUxfRklMRVNZU1RFTV9WSVNJQklMSVRZOiBwdWJsaWMKICAgICAgQ0FDSEVfRFJJVkVSOiByZWRpcwogICAgICBRVUVVRV9DT05ORUNUSU9OOiByZWRpcwogICAgICBTRVNTSU9OX0RSSVZFUjogcmVkaXMKICAgICAgU0VTU0lPTl9MSUZFVElNRTogMTIwCiAgICAgIE1BSUxfTUFJTEVSOiAnJHtNQUlMX01BSUxFUjotbG9nfScKICAgICAgTUFJTF9IT1NUOiAnJHtNQUlMX0hPU1R9JwogICAgICBNQUlMX1BPUlQ6ICcke01BSUxfUE9SVH0nCiAgICAgIE1BSUxfVVNFUk5BTUU6ICcke01BSUxfVVNFUk5BTUU6LXlvdXJAZW1haWwuY29tfScKICAgICAgTUFJTF9QQVNTV09SRDogJyR7TUFJTF9QQVNTV09SRH0nCiAgICAgIE1BSUxfRU5DUllQVElPTjogJyR7TUFJTF9FTkNSWVBUSU9OfScKICAgICAgTUFJTF9GUk9NX0FERFJFU1M6ICcke01BSUxfRlJPTV9BRERSRVNTOi15b3VyQGVtYWlsLmNvbX0nCiAgICAgIE1BSUxfRlJPTV9OQU1FOiAnJHtNQUlMX0ZST01fTkFNRTotT3BuRm9ybX0nCiAgICAgIEFXU19BQ0NFU1NfS0VZX0lEOiAnJHtBV1NfQUNDRVNTX0tFWV9JRH0nCiAgICAgIEFXU19TRUNSRVRfQUNDRVNTX0tFWTogJyR7QVdTX1NFQ1JFVF9BQ0NFU1NfS0VZfScKICAgICAgQVdTX0RFRkFVTFRfUkVHSU9OOiAnJHtBV1NfREVGQVVMVF9SRUdJT046LXVzLWVhc3QtMX0nCiAgICAgIEFXU19CVUNLRVQ6ICcke0FXU19CVUNLRVR9JwogICAgICBPUEVOX0FJX0FQSV9LRVk6ICcke09QRU5fQUlfQVBJX0tFWX0nCiAgICAgIFRFTEVHUkFNX0JPVF9JRDogJyR7VEVMRUdSQU1fQk9UX0lEfScKICAgICAgVEVMRUdSQU1fQk9UX1RPS0VOOiAnJHtURUxFR1JBTV9CT1RfVE9LRU59JwogICAgICBSRURJU19IT1NUOiByZWRpcwogICAgICBSRURJU19QQVNTV09SRDogJyR7U0VSVklDRV9QQVNTV09SRF82NF9SRURJU30nCiAgICAgIERCX0hPU1Q6IHBvc3RncmVzcWwKICAgICAgREJfREFUQUJBU0U6ICcke1BPU1RHUkVTUUxfREFUQUJBU0U6LW9wbmZvcm19JwogICAgICBEQl9VU0VSTkFNRTogJyR7U0VSVklDRV9VU0VSX1BPU1RHUkVTUUx9JwogICAgICBEQl9QQVNTV09SRDogJyR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU1FMfScKICAgICAgREJfQ09OTkVDVElPTjogcGdzcWwKICAgICAgUEhQX01FTU9SWV9MSU1JVDogMUcKICAgICAgUEhQX01BWF9FWEVDVVRJT05fVElNRTogJzYwMCcKICAgICAgUEhQX1VQTE9BRF9NQVhfRklMRVNJWkU6IDY0TQogICAgICBQSFBfUE9TVF9NQVhfU0laRTogNjRNCiAgICAgIEZST05UX1VSTDogJyR7U0VSVklDRV9GUUROX05HSU5YfScKICAgICAgRlJPTlRfQVBJX1NFQ1JFVDogJyR7U0VSVklDRV9QQVNTV09SRF9GUk9OVEFQSVNFQ1JFVH0nCiAgICAgIFBVQkxJQ19VUExPQURTX1JBVEVfTElNSVRfUEVSX01JTlVURTogJyR7UFVCTElDX1VQTE9BRFNfUkFURV9MSU1JVF9QRVJfTUlOVVRFOi0zMH0nCiAgICAgIFBVQkxJQ19VUExPQURTX1JBVEVfTElNSVRfUEVSX0hPVVI6ICcke1BVQkxJQ19VUExPQURTX1JBVEVfTElNSVRfUEVSX0hPVVI6LTMwMH0nCiAgICAgIEpXVF9UVEw6ICcke0pXVF9UVEw6LTE0NDB9JwogICAgICBKV1RfU0VDUkVUOiAnJHtTRVJWSUNFX1BBU1NXT1JEX0pXVFNFQ1JFVH0Line truncated
|
||||
"tags": [
|
||||
"opnform",
|
||||
"form",
|
||||
@@ -3849,7 +3867,7 @@
|
||||
"category": "productivity",
|
||||
"logo": "svg/opnform.svg",
|
||||
"minversion": "0.0.0",
|
||||
"template_last_updated_at": "2026-04-06T11:35:16-05:00",
|
||||
"template_last_updated_at": "2026-08-10T12:49:29+02:00",
|
||||
"port": "80"
|
||||
},
|
||||
"orangehrm": {
|
||||
@@ -4601,7 +4619,7 @@
|
||||
"seaweedfs": {
|
||||
"documentation": "https://github.com/seaweedfs/seaweedfs?utm_source=coolify.io",
|
||||
"slogan": "SeaweedFS is a simple and highly scalable distributed file system. Compatible with S3, with an admin web interface.",
|
||||
"compose": "c2VydmljZXM6CiAgc2Vhd2VlZGZzLW1hc3RlcjoKICAgIGltYWdlOiAnY2hyaXNsdXNmL3NlYXdlZWRmczo0LjEzJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9GUUROX1MzXzgzMzMKICAgICAgLSAnQVdTX0FDQ0VTU19LRVlfSUQ9JHtTRVJWSUNFX1VTRVJfUzN9JwogICAgICAtICdBV1NfU0VDUkVUX0FDQ0VTU19LRVk9JHtTRVJWSUNFX1BBU1NXT1JEX1MzfScKICAgIHZvbHVtZXM6CiAgICAgIC0gJ3NlYXdlZWRmcy1zMy1kYXRhOi9kYXRhJwogICAgICAtCiAgICAgICAgdHlwZTogYmluZAogICAgICAgIHNvdXJjZTogLi9iYXNlLWNvbmZpZy5qc29uCiAgICAgICAgdGFyZ2V0OiAvYmFzZS1jb25maWcuanNvbgogICAgICAgIGNvbnRlbnQ6ICJ7XG4gIFwiaWRlbnRpdGllc1wiOiBbXG4gICAge1xuICAgICAgXCJuYW1lXCI6IFwiYW5vbnltb3VzXCIsXG4gICAgICBcImFjdGlvbnNcIjogW1xuICAgICAgICBcIlJlYWRcIlxuICAgICAgXVxuICAgIH0sXG4gICAge1xuICAgICAgXCJuYW1lXCI6IFwiYWRtaW5cIixcbiAgICAgIFwiY3JlZGVudGlhbHNcIjogW1xuICAgICAgICB7XG4gICAgICAgICAgXCJhY2Nlc3NLZXlcIjogXCJlbnY6QVdTX0FDQ0VTU19LRVlfSURcIixcbiAgICAgICAgICBcInNlY3JldEtleVwiOiBcImVudjpBV1NfU0VDUkVUX0FDQ0VTU19LRVlcIlxuICAgICAgICB9XG4gICAgICBdLFxuICAgICAgXCJhY3Rpb25zXCI6IFtcbiAgICAgICAgXCJBZG1pblwiLFxuICAgICAgICBcIlJlYWRcIixcbiAgICAgICAgXCJSZWFkQWNwXCIsXG4gICAgICAgIFwiTGlzdFwiLFxuICAgICAgICBcIlRhZ2dpbmdcIixcbiAgICAgICAgXCJXcml0ZVwiLFxuICAgICAgICBcIldyaXRlQWNwXCJcbiAgICAgIF1cbiAgICB9XG4gIF1cbn1cbiIKICAgIGVudHJ5cG9pbnQ6ICJzaCAtYyAnXFxcbnNlZCBcInMvZW52OkFXU19BQ0NFU1NfS0VZX0lELyRBV1NfQUNDRVNTX0tFWV9JRC9nXCIgL2Jhc2UtY29uZmlnLmpzb24gPiAvYmFzZTEtY29uZmlnLmpzb247IFxcXG5zZWQgXCJzL2VudjpBV1NfU0VDUkVUX0FDQ0VTU19LRVkvJEFXU19TRUNSRVRfQUNDRVNTX0tFWS9nXCIgL2Jhc2UxLWNvbmZpZy5qc29uID4gL2NvbmZpZy5qc29uOyBcXFxud2VlZCBzZXJ2ZXIgLWRpcj0vZGF0YSAtbWFzdGVyLnBvcnQ9OTMzMyAtczMgLXMzLnBvcnQ9ODMzMyAtczMuY29uZmlnPS9jb25maWcuanNvblxcXG4nXG4iCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gJ3dnZXQgLS1zcGlkZXIgLXEgaHR0cDovLzAuMC4wLjA6ODMzMzsgWyAkJD8gLWxlIDggXScKICAgICAgaW50ZXJ2YWw6IDEwcwogICAgICB0aW1lb3V0OiA1cwogICAgICByZXRyaWVzOiAxMAogIHNlYXdlZWRmcy1hZG1pbjoKICAgIGltYWdlOiAnY2hyaXNsdXNmL3NlYXdlZWRmczo0LjEzJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9GUUROX0FETUlOXzIzNjQ2CiAgICAgIC0gJ1NFQVdFRURfVVNFUl9BRE1JTj0ke1NFUlZJQ0VfVVNFUl9BRE1JTn0nCiAgICAgIC0gJ1NFQVdFRURfUEFTU1dPUkRfQURNSU49JHtTRVJWSUNFX1BBU1NXT1JEX0FETUlOfScKICAgIGNvbW1hbmQ6CiAgICAgIC0gYWRtaW4KICAgICAgLSAnLW1hc3Rlcj1zZWF3ZWVkZnMtbWFzdGVyOjkzMzMnCiAgICAgIC0gJy1hZG1pblVzZXI9JHtTRUFXRUVEX1VTRVJfQURNSU59JwogICAgICAtICctYWRtaW5QYXNzd29yZD0ke1NFQVdFRURfUEFTU1dPUkRfQURNSU59JwogICAgICAtICctcG9ydD0yMzY0NicKICAgICAgLSAnLWRhdGFEaXI9L2RhdGEnCiAgICB2b2x1bWVzOgogICAgICAtICdzZWF3ZWVkZnMtYWRtaW4tZGF0YTovZGF0YScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ELVNIRUxMCiAgICAgICAgLSAnd2dldCAtLXNwaWRlciAtcSBodHRwOi8vMC4wLjAuMDoyMzY0NjsgWyAkJD8gLWxlIDggXScKICAgICAgaW50ZXJ2YWw6IDEwcwogICAgICB0aW1lb3V0OiA1cwogICAgICByZXRyaWVzOiAxMAogICAgZGVwZW5kc19vbjoKICAgICAgc2Vhd2VlZGZzLW1hc3RlcjoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQo=",
|
||||
"compose": "c2VydmljZXM6CiAgc2Vhd2VlZGZzLW1hc3RlcjoKICAgIGltYWdlOiAnY2hyaXNsdXNmL3NlYXdlZWRmczo0LjQxJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9GUUROX1MzXzgzMzMKICAgICAgLSAnQVdTX0FDQ0VTU19LRVlfSUQ9JHtTRVJWSUNFX1VTRVJfUzN9JwogICAgICAtICdBV1NfU0VDUkVUX0FDQ0VTU19LRVk9JHtTRVJWSUNFX1BBU1NXT1JEX1MzfScKICAgIHZvbHVtZXM6CiAgICAgIC0gJ3NlYXdlZWRmcy1zMy1kYXRhOi9kYXRhJwogICAgICAtCiAgICAgICAgdHlwZTogYmluZAogICAgICAgIHNvdXJjZTogLi9iYXNlLWNvbmZpZy5qc29uCiAgICAgICAgdGFyZ2V0OiAvYmFzZS1jb25maWcuanNvbgogICAgICAgIGNvbnRlbnQ6ICJ7XG4gIFwiaWRlbnRpdGllc1wiOiBbXG4gICAge1xuICAgICAgXCJuYW1lXCI6IFwiYW5vbnltb3VzXCIsXG4gICAgICBcImFjdGlvbnNcIjogW1xuICAgICAgICBcIlJlYWRcIlxuICAgICAgXVxuICAgIH0sXG4gICAge1xuICAgICAgXCJuYW1lXCI6IFwiYWRtaW5cIixcbiAgICAgIFwiY3JlZGVudGlhbHNcIjogW1xuICAgICAgICB7XG4gICAgICAgICAgXCJhY2Nlc3NLZXlcIjogXCJlbnY6QVdTX0FDQ0VTU19LRVlfSURcIixcbiAgICAgICAgICBcInNlY3JldEtleVwiOiBcImVudjpBV1NfU0VDUkVUX0FDQ0VTU19LRVlcIlxuICAgICAgICB9XG4gICAgICBdLFxuICAgICAgXCJhY3Rpb25zXCI6IFtcbiAgICAgICAgXCJBZG1pblwiLFxuICAgICAgICBcIlJlYWRcIixcbiAgICAgICAgXCJSZWFkQWNwXCIsXG4gICAgICAgIFwiTGlzdFwiLFxuICAgICAgICBcIlRhZ2dpbmdcIixcbiAgICAgICAgXCJXcml0ZVwiLFxuICAgICAgICBcIldyaXRlQWNwXCJcbiAgICAgIF1cbiAgICB9XG4gIF1cbn1cbiIKICAgIGVudHJ5cG9pbnQ6ICJzaCAtYyAnXFxcbnNlZCBcInMvZW52OkFXU19BQ0NFU1NfS0VZX0lELyRBV1NfQUNDRVNTX0tFWV9JRC9nXCIgL2Jhc2UtY29uZmlnLmpzb24gPiAvYmFzZTEtY29uZmlnLmpzb247IFxcXG5zZWQgXCJzL2VudjpBV1NfU0VDUkVUX0FDQ0VTU19LRVkvJEFXU19TRUNSRVRfQUNDRVNTX0tFWS9nXCIgL2Jhc2UxLWNvbmZpZy5qc29uID4gL2NvbmZpZy5qc29uOyBcXFxud2VlZCBzZXJ2ZXIgLWRpcj0vZGF0YSAtbWFzdGVyLnBvcnQ9OTMzMyAtczMgLXMzLnBvcnQ9ODMzMyAtczMuY29uZmlnPS9jb25maWcuanNvblxcXG4nXG4iCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gJ3dnZXQgLS1zcGlkZXIgLXEgaHR0cDovLzAuMC4wLjA6ODMzMzsgWyAkJD8gLWxlIDggXScKICAgICAgaW50ZXJ2YWw6IDEwcwogICAgICB0aW1lb3V0OiA1cwogICAgICByZXRyaWVzOiAxMAogIHNlYXdlZWRmcy1hZG1pbjoKICAgIGltYWdlOiAnY2hyaXNsdXNmL3NlYXdlZWRmczo0LjQxJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9GUUROX0FETUlOXzIzNjQ2CiAgICAgIC0gJ1NFQVdFRURfVVNFUl9BRE1JTj0ke1NFUlZJQ0VfVVNFUl9BRE1JTn0nCiAgICAgIC0gJ1NFQVdFRURfUEFTU1dPUkRfQURNSU49JHtTRVJWSUNFX1BBU1NXT1JEX0FETUlOfScKICAgIGNvbW1hbmQ6CiAgICAgIC0gYWRtaW4KICAgICAgLSAnLW1hc3Rlcj1zZWF3ZWVkZnMtbWFzdGVyOjkzMzMnCiAgICAgIC0gJy1hZG1pblVzZXI9JHtTRUFXRUVEX1VTRVJfQURNSU59JwogICAgICAtICctYWRtaW5QYXNzd29yZD0ke1NFQVdFRURfUEFTU1dPUkRfQURNSU59JwogICAgICAtICctcG9ydD0yMzY0NicKICAgICAgLSAnLWRhdGFEaXI9L2RhdGEnCiAgICB2b2x1bWVzOgogICAgICAtICdzZWF3ZWVkZnMtYWRtaW4tZGF0YTovZGF0YScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ELVNIRUxMCiAgICAgICAgLSAnd2dldCAtLXNwaWRlciAtcSBodHRwOi8vMC4wLjAuMDoyMzY0NjsgWyAkJD8gLWxlIDggXScKICAgICAgaW50ZXJ2YWw6IDEwcwogICAgICB0aW1lb3V0OiA1cwogICAgICByZXRyaWVzOiAxMAogICAgZGVwZW5kc19vbjoKICAgICAgc2Vhd2VlZGZzLW1hc3RlcjoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQo=",
|
||||
"tags": [
|
||||
"object",
|
||||
"storage",
|
||||
@@ -4612,7 +4630,7 @@
|
||||
"category": "storage",
|
||||
"logo": "svgs/seaweedfs.svg",
|
||||
"minversion": "0.0.0",
|
||||
"template_last_updated_at": "2026-03-02T20:04:29-03:00",
|
||||
"template_last_updated_at": "2026-08-10T11:21:26+02:00",
|
||||
"port": "8333"
|
||||
},
|
||||
"sequin": {
|
||||
@@ -4855,7 +4873,7 @@
|
||||
"sparkyfitness": {
|
||||
"documentation": "https://codewithcj.github.io/SparkyFitness/?utm_source=coolify.io",
|
||||
"slogan": "SparkyFitness is a comprehensive fitness tracking and management application designed to help users monitor their nutrition, exercise, and body measurements. It provides tools for daily progress tracking, goal setting, and insightful reports to support a healthy lifestyle.",
|
||||
"compose": "c2VydmljZXM6CiAgc3Bhcmt5Zml0bmVzcy1mcm9udGVuZDoKICAgIGltYWdlOiAnY29kZXdpdGhjai9zcGFya3lmaXRuZXNzOnYwLjE1LjcuMycKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9TUEFSS1lGSVRORVNTXzgwCiAgICBkZXBlbmRzX29uOgogICAgICAtIHNwYXJreWZpdG5lc3Mtc2VydmVyCiAgc3Bhcmt5Zml0bmVzcy1zZXJ2ZXI6CiAgICBpbWFnZTogJ2NvZGV3aXRoY2ovc3Bhcmt5Zml0bmVzc19zZXJ2ZXI6djAuMTUuNy4zJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ1NQQVJLWV9GSVRORVNTX0xPR19MRVZFTD0ke1NQQVJLWV9GSVRORVNTX0xPR19MRVZFTDotaW5mb30nCiAgICAgIC0gJ1NQQVJLWV9GSVRORVNTX0RCX1VTRVI9JHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9JwogICAgICAtIFNQQVJLWV9GSVRORVNTX0RCX0hPU1Q9c3Bhcmt5Zml0bmVzcy1kYgogICAgICAtICdTUEFSS1lfRklUTkVTU19EQl9OQU1FPSR7U1BBUktZX0ZJVE5FU1NfREJfTkFNRTotc3Bhcmt5Zml0bmVzc30nCiAgICAgIC0gJ1NQQVJLWV9GSVRORVNTX0RCX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU30nCiAgICAgIC0gJ1NQQVJLWV9GSVRORVNTX0RCX1BPUlQ9JHtTUEFSS1lfRklUTkVTU19EQl9QT1JUOi01NDMyfScKICAgICAgLSAnU1BBUktZX0ZJVE5FU1NfQVBJX0VOQ1JZUFRJT05fS0VZPSR7U0VSVklDRV9QQVNTV09SRF82NF9TRVJWRVJBUElFTkNSWVBUSU9OS0VZfScKICAgICAgLSAnSldUX1NFQ1JFVD0ke1NFUlZJQ0VfUEFTU1dPUkRfNjRfU0VSVkVSSldUU0VDUkVUfScKICAgICAgLSAnU1BBUktZX0ZJVE5FU1NfRlJPTlRFTkRfVVJMPSR7U0VSVklDRV9GUUROX1NQQVJLWUZJVE5FU1NfODB9JwogICAgICAtICdTUEFSS1lfRklUTkVTU19ESVNBQkxFX1NJR05VUD0ke1NQQVJLWV9GSVRORVNTX0RJU0FCTEVfU0lHTlVQOi1mYWxzZX0nCiAgICAgIC0gJ1NQQVJLWV9GSVRORVNTX0FETUlOX0VNQUlMPSR7U1BBUktZX0ZJVE5FU1NfQURNSU5fRU1BSUw6LWFkbWluQGV4YW1wbGUuY29tfScKICAgICAgLSAnU1BBUktZX0ZJVE5FU1NfRU1BSUxfSE9TVD0ke1NQQVJLWV9GSVRORVNTX0VNQUlMX0hPU1Q6LXNtdHAuZ21haWwuY29tfScKICAgICAgLSAnU1BBUktZX0ZJVE5FU1NfRU1BSUxfUE9SVD0ke1NQQVJLWV9GSVRORVNTX0VNQUlMX1BPUlQ6LTU4N30nCiAgICAgIC0gJ1NQQVJLWV9GSVRORVNTX0VNQUlMX1NFQ1VSRT0ke1NQQVJLWV9GSVRORVNTX0VNQUlMX1NFQ1VSRTotZmFsc2V9JwogICAgICAtICdTUEFSS1lfRklUTkVTU19FTUFJTF9VU0VSPSR7U1BBUktZX0ZJVE5FU1NfRU1BSUxfVVNFUn0nCiAgICAgIC0gJ1NQQVJLWV9GSVRORVNTX0VNQUlMX1BBU1M9JHtTUEFSS1lfRklUTkVTU19FTUFJTF9QQVNTfScKICAgICAgLSAnU1BBUktZX0ZJVE5FU1NfRU1BSUxfRlJPTT0ke1NQQVJLWV9GSVRORVNTX0VNQUlMX0ZST006LSJTcGFya3kgRml0bmVzcyA8bm9yZXBseUBzcGFya3lmaXRuZXNzLmNvbT4ifScKICAgIGRlcGVuZHNfb246CiAgICAgIC0gc3Bhcmt5Zml0bmVzcy1kYgogICAgdm9sdW1lczoKICAgICAgLSAnc3Bhcmt5Zml0bmVzcy1zZXJ2ZXItYmFja3VwOi9hcHAvU3Bhcmt5Rml0bmVzc1NlcnZlci9iYWNrdXAnCiAgICAgIC0gJ3NwYXJreWZpdG5lc3Mtc2VydmVyLXVwbG9hZHM6L2FwcC9TcGFya3lGaXRuZXNzU2VydmVyL3VwbG9hZHMnCiAgc3Bhcmt5Zml0bmVzcy1kYjoKICAgIGltYWdlOiAncG9zdGdyZXM6MTUtYWxwaW5lJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ1BPU1RHUkVTX0RCPSR7U1BBUktZX0ZJVE5FU1NfREJfTkFNRTotc3Bhcmt5Zml0bmVzc30nCiAgICAgIC0gJ1BPU1RHUkVTX1VTRVI9JHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9JwogICAgICAtICdQT1NUR1JFU19QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVN9JwogICAgICAtICdQT1NUR1JFU19QT1JUPSR7U1BBUktZX0ZJVE5FU1NfREJfUE9SVDotNTQzMn0nCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gJ3BnX2lzcmVhZHkgLVUgJCR7UE9TVEdSRVNfVVNFUn0gLWQgJCR7UE9TVEdSRVNfREJ9JwogICAgICBpbnRlcnZhbDogNXMKICAgICAgdGltZW91dDogMjBzCiAgICAgIHJldHJpZXM6IDEwCiAgICB2b2x1bWVzOgogICAgICAtICdzcGFya3lmaXRuZXNzLWRiLXBvc3RncmVzcWw6L3Zhci9saWIvcG9zdGdyZXNxbC9kYXRhJwo=",
|
||||
"compose": "c2VydmljZXM6CiAgc3Bhcmt5Zml0bmVzcy1mcm9udGVuZDoKICAgIGltYWdlOiAnY29kZXdpdGhjai9zcGFya3lmaXRuZXNzOnYxLjYuMScKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9TUEFSS1lGSVRORVNTXzgwCiAgICAgIC0gJ1NQQVJLWV9GSVRORVNTX0ZST05URU5EX1VSTD0ke1NFUlZJQ0VfRlFETl9TUEFSS1lGSVRORVNTXzgwfScKICAgICAgLSBTUEFSS1lfRklUTkVTU19TRVJWRVJfSE9TVD1zcGFya3lmaXRuZXNzLXNlcnZlcgogICAgICAtIFNQQVJLWV9GSVRORVNTX1NFUlZFUl9QT1JUPTMwMTAKICAgIGRlcGVuZHNfb246CiAgICAgIC0gc3Bhcmt5Zml0bmVzcy1zZXJ2ZXIKICBzcGFya3lmaXRuZXNzLXNlcnZlcjoKICAgIGltYWdlOiAnY29kZXdpdGhjai9zcGFya3lmaXRuZXNzX3NlcnZlcjp2MS42LjEnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSAnU1BBUktZX0ZJVE5FU1NfTE9HX0xFVkVMPSR7U1BBUktZX0ZJVE5FU1NfTE9HX0xFVkVMOi1pbmZvfScKICAgICAgLSAnTk9ERV9FTlY9JHtOT0RFX0VOVjotcHJvZHVjdGlvbn0nCiAgICAgIC0gJ1RaPSR7VFo6LUV0Yy9VVEN9JwogICAgICAtICdTUEFSS1lfRklUTkVTU19EQl9VU0VSPSR7U0VSVklDRV9VU0VSX1BPU1RHUkVTfScKICAgICAgLSBTUEFSS1lfRklUTkVTU19EQl9IT1NUPXNwYXJreWZpdG5lc3MtZGIKICAgICAgLSAnU1BBUktZX0ZJVE5FU1NfREJfTkFNRT0ke1NQQVJLWV9GSVRORVNTX0RCX05BTUU6LXNwYXJreWZpdG5lc3N9JwogICAgICAtICdTUEFSS1lfRklUTkVTU19EQl9QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVN9JwogICAgICAtICdTUEFSS1lfRklUTkVTU19EQl9QT1JUPSR7U1BBUktZX0ZJVE5FU1NfREJfUE9SVDotNTQzMn0nCiAgICAgIC0gJ1NQQVJLWV9GSVRORVNTX0FQUF9EQl9VU0VSPSR7U1BBUktZX0ZJVE5FU1NfQVBQX0RCX1VTRVI6LXNwYXJreWFwcH0nCiAgICAgIC0gJ1NQQVJLWV9GSVRORVNTX0FQUF9EQl9QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfNjRfQVBQREJQQVNTV09SRH0nCiAgICAgIC0gJ1NQQVJLWV9GSVRORVNTX0FQSV9FTkNSWVBUSU9OX0tFWT0ke1NFUlZJQ0VfUEFTU1dPUkRfNjRfU0VSVkVSQVBJRU5DUllQVElPTktFWX0nCiAgICAgIC0gJ0JFVFRFUl9BVVRIX1NFQ1JFVD0ke1NFUlZJQ0VfUEFTU1dPUkRfNjRfQkVUVEVSQVVUSFNFQ1JFVH0nCiAgICAgIC0gJ1NQQVJLWV9GSVRORVNTX0ZST05URU5EX1VSTD0ke1NFUlZJQ0VfRlFETl9TUEFSS1lGSVRORVNTXzgwfScKICAgICAgLSAnQUxMT1dfUFJJVkFURV9ORVRXT1JLX0NPUlM9JHtBTExPV19QUklWQVRFX05FVFdPUktfQ09SUzotZmFsc2V9JwogICAgICAtICdTUEFSS1lfRklUTkVTU19FWFRSQV9UUlVTVEVEX09SSUdJTlM9JHtTUEFSS1lfRklUTkVTU19FWFRSQV9UUlVTVEVEX09SSUdJTlM6LX0nCiAgICAgIC0gJ1NQQVJLWV9GSVRORVNTX0RJU0FCTEVfU0lHTlVQPSR7U1BBUktZX0ZJVE5FU1NfRElTQUJMRV9TSUdOVVA6LWZhbHNlfScKICAgICAgLSAnU1BBUktZX0ZJVE5FU1NfRk9SQ0VfRU1BSUxfTE9HSU49JHtTUEFSS1lfRklUTkVTU19GT1JDRV9FTUFJTF9MT0dJTjotdHJ1ZX0nCiAgICAgIC0gJ1NQQVJLWV9GSVRORVNTX0FETUlOX0VNQUlMPSR7U1BBUktZX0ZJVE5FU1NfQURNSU5fRU1BSUw6LWFkbWluQGV4YW1wbGUuY29tfScKICAgICAgLSAnU1BBUktZX0ZJVE5FU1NfRU1BSUxfSE9TVD0ke1NQQVJLWV9GSVRORVNTX0VNQUlMX0hPU1Q6LXNtdHAuZ21haWwuY29tfScKICAgICAgLSAnU1BBUktZX0ZJVE5FU1NfRU1BSUxfUE9SVD0ke1NQQVJLWV9GSVRORVNTX0VNQUlMX1BPUlQ6LTU4N30nCiAgICAgIC0gJ1NQQVJLWV9GSVRORVNTX0VNQUlMX1NFQ1VSRT0ke1NQQVJLWV9GSVRORVNTX0VNQUlMX1NFQ1VSRTotZmFsc2V9JwogICAgICAtICdTUEFSS1lfRklUTkVTU19FTUFJTF9VU0VSPSR7U1BBUktZX0ZJVE5FU1NfRU1BSUxfVVNFUn0nCiAgICAgIC0gJ1NQQVJLWV9GSVRORVNTX0VNQUlMX1BBU1M9JHtTUEFSS1lfRklUTkVTU19FTUFJTF9QQVNTfScKICAgICAgLSAnU1BBUktZX0ZJVE5FU1NfRU1BSUxfRlJPTT0ke1NQQVJLWV9GSVRORVNTX0VNQUlMX0ZST006LSJTcGFya3kgRml0bmVzcyA8bm9yZXBseUBzcGFya3lmaXRuZXNzLmNvbT4ifScKICAgIGRlcGVuZHNfb246CiAgICAgIC0gc3Bhcmt5Zml0bmVzcy1kYgogICAgdm9sdW1lczoKICAgICAgLSAnc3Bhcmt5Zml0bmVzcy1zZXJ2ZXItYmFja3VwOi9hcHAvU3Bhcmt5Rml0bmVzc1NlcnZlci9iYWNrdXAnCiAgICAgIC0gJ3NwYXJreWZpdG5lc3Mtc2VydmVyLXVwbG9hZHM6L2FwcC9TcGFya3lGaXRuZXNzU2VydmVyL3VwbG9hZHMnCiAgc3Bhcmt5Zml0bmVzcy1kYjoKICAgIGltYWdlOiAncG9zdGdyZXM6MTgtYWxwaW5lJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ1BPU1RHUkVTX0RCPSR7U1BBUktZX0ZJVE5FU1NfREJfTkFNRTotc3Bhcmt5Zml0bmVzc30nCiAgICAgIC0gJ1BPU1RHUkVTX1VTRVI9JHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9JwogICAgICAtICdQT1NUR1JFU19QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVN9JwogICAgICAtICdQT1NUR1JFU19QT1JUPSR7U1BBUktZX0ZJVE5FU1NfREJfUE9SVDotNTQzMn0nCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gJ3BnX2lzcmVhZHkgLVUgJCR7UE9TVEdSRVNfVVNFUn0gLWQgJCR7UE9TVEdSRVNfREJ9JwogICAgICBpbnRlcnZhbDogNXMKICAgICAgdGltZW91dDogMjBzCiAgICAgIHJldHJpZXM6IDEwCiAgICB2b2x1bWVzOgogICAgICAtICdzcGFya3lmaXRuZXNzLWRiLXBvc3RncmVzcWw6L3Zhci9saWIvcG9zdGdyZXNxbCcK",
|
||||
"tags": [
|
||||
"sparkyfitness",
|
||||
"fitness",
|
||||
@@ -4867,9 +4885,29 @@
|
||||
"category": "health",
|
||||
"logo": "svgs/sparkyfitness.svg",
|
||||
"minversion": "0.0.0",
|
||||
"template_last_updated_at": "2025-10-22T07:08:46+07:00",
|
||||
"template_last_updated_at": "2026-08-10T13:18:10+02:00",
|
||||
"port": "80"
|
||||
},
|
||||
"stalwart": {
|
||||
"documentation": "https://stalw.art/docs/?utm_source=coolify.io",
|
||||
"slogan": "Modern mail server platform",
|
||||
"compose": "c2VydmljZXM6CiAgc3RhbHdhcnQ6CiAgICBpbWFnZTogJ3N0YWx3YXJ0bGFicy9zdGFsd2FydDp2MC4xNi4xMycKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9TVEFMV0FSVF84MDgwCiAgICBleHBvc2U6CiAgICAgIC0gJzgwODAnCiAgICBwb3J0czoKICAgICAgLSAnMjU6MjUnCiAgICAgIC0gJzQ2NTo0NjUnCiAgICAgIC0gJzU4Nzo1ODcnCiAgICAgIC0gJzk5Mzo5OTMnCiAgICAgIC0gJzk5NTo5OTUnCiAgICAgIC0gJzE0MzoxNDMnCiAgICAgIC0gJzExMDoxMTAnCiAgICAgIC0gJzQxOTA6NDE5MCcKICAgIHZvbHVtZXM6CiAgICAgIC0gJ3N0YWx3YXJ0LW1haWw6L2V0Yy9zdGFsd2FydCcKICAgICAgLSAnc3RhbHdhcnQtZGF0YTovdmFyL2xpYi9zdGFsd2FydCcKICAgICAgLSAnL2V0Yy9sb2NhbHRpbWU6L2V0Yy9sb2NhbHRpbWU6cm8nCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRAogICAgICAgIC0gY3VybAogICAgICAgIC0gJy1mJwogICAgICAgIC0gJ2h0dHA6Ly9sb2NhbGhvc3Q6ODA4MC8nCiAgICAgIGludGVydmFsOiAzMHMKICAgICAgdGltZW91dDogMTBzCiAgICAgIHJldHJpZXM6IDMK",
|
||||
"tags": [
|
||||
"mail",
|
||||
"smtp",
|
||||
"imap",
|
||||
"pop3",
|
||||
"jmap",
|
||||
"email",
|
||||
"sieve",
|
||||
"messaging"
|
||||
],
|
||||
"category": "Mail",
|
||||
"logo": "svgs/stalwart.svg",
|
||||
"minversion": "0.0.0",
|
||||
"template_last_updated_at": "2026-08-10T12:58:58+02:00",
|
||||
"port": "8080"
|
||||
},
|
||||
"statusnook": {
|
||||
"documentation": "https://statusnook.com?utm_source=coolify.io",
|
||||
"slogan": "Effortlessly deploy a status page and start monitoring endpoints in minutes",
|
||||
@@ -5087,6 +5125,25 @@
|
||||
"template_last_updated_at": "2025-08-17T18:23:57+02:00",
|
||||
"port": "3000"
|
||||
},
|
||||
"termix": {
|
||||
"documentation": "https://docs.termix.site/install/server/docker?utm_source=coolify.io",
|
||||
"slogan": "All-in-One SSH & Remote Desktop management app.",
|
||||
"compose": "c2VydmljZXM6CiAgdGVybWl4OgogICAgaW1hZ2U6ICdnaGNyLmlvL2x1a2VndXMvdGVybWl4OjIuNi4xJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9GUUROX1RFUk1JWF84MDgwCiAgICAgIC0gUE9SVD04MDgwCiAgICAgIC0gJ0xPR19MRVZFTD0ke0xPR19MRVZFTDotaW5mb30nCiAgICAgIC0gR1VBQ0RfSE9TVD1ndWFjZAogICAgICAtIEdVQUNEX1JFQ09SRElOR19QQVRIPS90ZXJtaXgtZGF0YS9zZXNzaW9uX3JlY29yZGluZ3MvZ3VhY2Ftb2xlCiAgICBkZXBlbmRzX29uOgogICAgICAtIGd1YWNkCiAgICB2b2x1bWVzOgogICAgICAtICd0ZXJtaXgtZGF0YTovYXBwL2RhdGEnCiAgZ3VhY2Q6CiAgICBpbWFnZTogJ2d1YWNhbW9sZS9ndWFjZDoxLjYuMCcK",
|
||||
"tags": [
|
||||
"ssh",
|
||||
"terminal",
|
||||
"remote-desktop",
|
||||
"rdp",
|
||||
"vnc",
|
||||
"server-management",
|
||||
"remote-access"
|
||||
],
|
||||
"category": "developer-tools",
|
||||
"logo": "svgs/termix.svg",
|
||||
"minversion": "0.0.0",
|
||||
"template_last_updated_at": "2026-08-10T11:46:48+02:00",
|
||||
"port": "8080"
|
||||
},
|
||||
"terraria-server": {
|
||||
"documentation": "https://github.com/hexlo/terraria-server-docker?utm_source=coolify.io",
|
||||
"slogan": "Docker multi-arch Image for Terraria Server.",
|
||||
|
||||
@@ -14,12 +14,18 @@ test('custom color theme is available and applied across theme controls', functi
|
||||
->toContain("['value' => 'custom', 'label' => 'Custom'")
|
||||
->toContain('type="color"')
|
||||
->toContain('absolute inset-0 z-10 h-full w-full cursor-pointer opacity-0')
|
||||
->toContain("localStorage.setItem('themeColor', this.themeColor)")
|
||||
->toContain('requestAnimationFrame(() =>')
|
||||
->toContain('@input="previewThemeColor($event.target.value)"')
|
||||
->toContain('@change="saveThemeColor($event.target.value)"')
|
||||
->toContain("localStorage.setItem('themeColor', color)")
|
||||
->toContain("this.theme === 'custom'")
|
||||
->and($accountMenu)
|
||||
->toContain("['value' => 'custom', 'label' => 'Custom']")
|
||||
->toContain('aria-label="Custom theme color"')
|
||||
->toContain("localStorage.setItem('themeColor', this.themeColor)")
|
||||
->toContain('requestAnimationFrame(() =>')
|
||||
->toContain('@input="previewThemeColor($event.target.value)"')
|
||||
->toContain('@change="saveThemeColor($event.target.value)"')
|
||||
->toContain("localStorage.setItem('themeColor', color)")
|
||||
->toContain('absolute inset-0 z-10 h-full w-full cursor-pointer opacity-0')
|
||||
->and($layout)
|
||||
->toContain("t === 'custom'")
|
||||
|
||||
@@ -53,6 +53,17 @@ function createDashboardDeployment(array $overrides = []): ApplicationDeployment
|
||||
], $overrides));
|
||||
}
|
||||
|
||||
it('shows a visible yellow inset focus state on deployment rows', function () {
|
||||
$view = file_get_contents(resource_path('views/livewire/dashboard/active-deployments.blade.php'));
|
||||
|
||||
expect(substr_count($view, 'focus-visible:bg-warning/10'))->toBe(4)
|
||||
->and(substr_count($view, 'focus-visible:ring-1'))->toBe(2)
|
||||
->and(substr_count($view, 'focus-visible:ring-inset'))->toBe(2)
|
||||
->and(substr_count($view, 'focus-visible:ring-warning'))->toBe(2)
|
||||
->and(substr_count($view, 'focus-visible:ring-offset-0'))->toBe(2)
|
||||
->and(substr_count($view, 'dark:focus-visible:bg-warning/10'))->toBe(2);
|
||||
});
|
||||
|
||||
it('hides the deployments section when there is nothing to show', function () {
|
||||
Livewire::test(ActiveDeployments::class)
|
||||
->assertDontSee('Active and recent deployment activity')
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
use App\Livewire\Dashboard;
|
||||
use App\Models\InstanceSettings;
|
||||
use App\Models\PrivateKey;
|
||||
use App\Models\Server;
|
||||
use App\Models\Team;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\Queue;
|
||||
use Livewire\Livewire;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
beforeEach(function () {
|
||||
Queue::fake();
|
||||
InstanceSettings::unguarded(fn () => InstanceSettings::query()->create(['id' => 0]));
|
||||
|
||||
$user = User::factory()->create();
|
||||
$team = Team::factory()->create();
|
||||
$user->teams()->attach($team, ['role' => 'owner']);
|
||||
|
||||
$this->actingAs($user);
|
||||
session(['currentTeam' => $team]);
|
||||
|
||||
$this->privateKey = PrivateKey::factory()->create(['team_id' => $team->id]);
|
||||
$this->team = $team;
|
||||
});
|
||||
|
||||
it('renders a metrics chart only for servers with metrics enabled', function () {
|
||||
$enabledServer = Server::factory()->create([
|
||||
'team_id' => $this->team->id,
|
||||
'private_key_id' => $this->privateKey->id,
|
||||
]);
|
||||
$enabledServer->settings->update(['is_metrics_enabled' => true]);
|
||||
|
||||
$disabledServer = Server::factory()->create([
|
||||
'team_id' => $this->team->id,
|
||||
'private_key_id' => $this->privateKey->id,
|
||||
]);
|
||||
$disabledServer->settings->update(['is_metrics_enabled' => false]);
|
||||
|
||||
Livewire::test(Dashboard::class)
|
||||
->assertSeeHtml("dashboard-server-metrics-{$enabledServer->uuid}")
|
||||
->assertDontSeeHtml("dashboard-server-metrics-{$disabledServer->uuid}");
|
||||
});
|
||||
|
||||
it('configures the dashboard chart as a ten minute cpu and memory sparkline with hover details', function () {
|
||||
$chart = file_get_contents(resource_path('views/livewire/dashboard/server-metrics-chart.blade.php'));
|
||||
$component = file_get_contents(app_path('Livewire/Dashboard/ServerMetricsChart.php'));
|
||||
|
||||
expect($component)
|
||||
->toContain('$this->server->getCpuMetrics(10)')
|
||||
->toContain('$this->server->getMemoryMetrics(10)');
|
||||
expect($chart)
|
||||
->toContain('new ApexCharts')
|
||||
->toContain('sparkline: { enabled: true }')
|
||||
->toContain('absolute right-0 bottom-0 h-2/3 w-full')
|
||||
->toContain('[&_.apexcharts-svg]:overflow-hidden')
|
||||
->not->toContain('w-full overflow-hidden rounded-b-xl')
|
||||
->toContain('CPU:')
|
||||
->toContain('Memory:')
|
||||
->toContain('formatTimestamp(timestamp)')
|
||||
->toContain("min: 0,\n max: 100,")
|
||||
->toContain('labels: { show: false }');
|
||||
});
|
||||
|
||||
it('refreshes dashboard metrics every minute while visible and after returning from the background', function () {
|
||||
$chart = file_get_contents(resource_path('views/livewire/dashboard/server-metrics-chart.blade.php'));
|
||||
|
||||
expect($chart)
|
||||
->toContain('window.setInterval')
|
||||
->toContain('60000')
|
||||
->toContain('document.hidden')
|
||||
->toContain("document.addEventListener('visibilitychange'")
|
||||
->toContain('Date.now() - this.hiddenAt >= 60000')
|
||||
->toContain('$wire.loadData()')
|
||||
->toContain('window.clearInterval')
|
||||
->toContain("document.removeEventListener('visibilitychange'");
|
||||
});
|
||||
|
||||
it('keeps the status badge only on server cards without metrics', function () {
|
||||
$dashboard = file_get_contents(resource_path('views/livewire/dashboard.blade.php'));
|
||||
|
||||
expect($dashboard)->toContain('@unless ($server->isMetricsEnabled())');
|
||||
});
|
||||
@@ -11,11 +11,15 @@ test('active deployment log controls use a coollabs background and white icon',
|
||||
|
||||
test('deployment logs use light surfaces in light mode and dark surfaces in dark mode', function () {
|
||||
$view = file_get_contents(resource_path('views/livewire/project/application/deployment/show.blade.php'));
|
||||
$styles = file_get_contents(resource_path('css/app.css'));
|
||||
|
||||
expect($view)
|
||||
->toContain('bg-white text-neutral-800')
|
||||
->toContain('dark:bg-[#0d0d0d] dark:text-neutral-100')
|
||||
->toContain('border-neutral-200 shadow-sm dark:border-neutral-800')
|
||||
->toContain('dark:bg-log dark:text-neutral-100')
|
||||
->toContain('border-neutral-200 shadow-sm dark:border-coolgray-200')
|
||||
->toContain('border-neutral-200! bg-white!')
|
||||
->toContain('dark:border-white/[0.08]! dark:bg-white/[0.05]!');
|
||||
->toContain('dark:border-white/[0.08]! dark:bg-white/[0.05]!')
|
||||
->and($styles)
|
||||
->toMatch('/\.logs-viewer\s*\{[^}]*background:\s*#fff;[^}]*color:\s*#262626;/s')
|
||||
->toMatch('/\.dark \.logs-viewer\s*\{[^}]*background:\s*var\(--color-log\);/s');
|
||||
});
|
||||
@@ -117,6 +117,8 @@ it('uses a mobile-friendly stacked logs toolbar markup', function () {
|
||||
->toContain('.logs-viewer-actions')
|
||||
->toContain('.logs-viewer-deployment-actions')
|
||||
->toContain('.logs-settings-section')
|
||||
->toContain('padding: 0.5rem 0.75rem 2rem;')
|
||||
->toContain('padding: 0.5rem 1rem 2rem;')
|
||||
->toContain('flex-direction: column')
|
||||
->toContain('@media (min-width: 640px)');
|
||||
|
||||
|
||||
@@ -7,10 +7,31 @@ it('uses the custom tooltip for icon actions across layouts', function () {
|
||||
expect($baseLayout)->toContain('<x-icon-tooltip />')
|
||||
->and($tooltip)
|
||||
->toContain("closest('button, a, [data-tooltip]')")
|
||||
->toContain("target.querySelector('svg')")
|
||||
->toContain("target.matches('[data-tooltip], .icon-button')")
|
||||
->toContain("target.hasAttribute('aria-label')")
|
||||
->toContain('target.childElementCount === 1')
|
||||
->toContain("target.firstElementChild?.matches('svg')")
|
||||
->not->toContain("target.querySelector('svg')")
|
||||
->toContain("target.matches('[data-icon-tooltip-ignore]')")
|
||||
->toContain("target.removeAttribute('title')")
|
||||
->toContain('role="tooltip"')
|
||||
->toContain('aria-label')
|
||||
->toContain('fixed z-[100]');
|
||||
});
|
||||
|
||||
it('does not reposition an already active tooltip during nested mouseover events', function () {
|
||||
$tooltip = file_get_contents(resource_path('views/components/icon-tooltip.blade.php'));
|
||||
|
||||
expect($tooltip)
|
||||
->toContain('if (target === this.activeTarget && this.visible) return;');
|
||||
});
|
||||
|
||||
it('keeps a tooltip hidden until its measured position is applied', function () {
|
||||
$tooltip = file_get_contents(resource_path('views/components/icon-tooltip.blade.php'));
|
||||
|
||||
expect($tooltip)
|
||||
->toContain('positioned: false')
|
||||
->toContain('this.positioned = false;')
|
||||
->toContain('this.$nextTick(() => this.positioned = true);')
|
||||
->toContain("positioned ? 'visible' : 'invisible'");
|
||||
});
|
||||
@@ -19,7 +19,7 @@ it('uses a single Alpine result renderer for every command palette result type',
|
||||
expect($view)
|
||||
->not->toContain('Create mode (server-rendered path)')
|
||||
->not->toContain('!$wire.isCreateMode')
|
||||
->toContain("<!-- Command palette -->\n <div x-show=\"modalOpen\"")
|
||||
->toContain("<!-- Command palette -->\n <div x-cloak")
|
||||
->not->toContain("<!-- Command palette -->\n <template x-teleport=\"body\">")
|
||||
->toContain("<div wire:ignore>\n <template x-if=\"searchQuery.length")
|
||||
->toContain('x-for="(result, index) in searchResults"')
|
||||
@@ -32,3 +32,29 @@ it('skips hidden command palette results during keyboard navigation', function (
|
||||
expect($view)
|
||||
->toContain('filter(item => item.offsetParent !== null)');
|
||||
});
|
||||
|
||||
it('opens the command palette without changing page scrollbar visibility', function () {
|
||||
$view = file_get_contents(resource_path('views/livewire/global-search.blade.php'));
|
||||
|
||||
expect($view)
|
||||
->not->toContain("document.body.style.overflow = value ? 'hidden' : ''")
|
||||
->not->toContain("document.body.style.overflow = ''");
|
||||
});
|
||||
|
||||
it('animates the command palette with tw animate utilities', function () {
|
||||
$view = file_get_contents(resource_path('views/livewire/global-search.blade.php'));
|
||||
|
||||
expect($view)
|
||||
->toContain('<div x-show="modalOpen" @click="closeModal()"')
|
||||
->toContain('x-transition:enter="animate-in fade-in-0 zoom-in-95 slide-in-from-top-2 duration-150"')
|
||||
->toContain('x-transition:leave="animate-out fade-out-0 zoom-out-95 slide-out-to-top-2 duration-100"')
|
||||
->not->toContain('<div x-show="modalOpen" x-cloak\n class="fixed inset-0');
|
||||
});
|
||||
|
||||
it('closes the client-side command palette without a Livewire request', function () {
|
||||
$view = file_get_contents(resource_path('views/livewire/global-search.blade.php'));
|
||||
|
||||
expect($view)
|
||||
->not->toContain('$wire.closeSearchModal()')
|
||||
->not->toContain('closeTimer');
|
||||
});
|
||||
@@ -10,7 +10,7 @@ test('highlighted buttons use the shared coollabs style in every color scheme',
|
||||
|
||||
expect($utilities)
|
||||
->toContain('@utility button-highlighted')
|
||||
->toContain('@apply border-2 text-coollabs-200 dark:text-white bg-coollabs-50 dark:bg-coollabs/20 border-coollabs dark:border-coollabs-100 hover:bg-coollabs hover:text-white dark:hover:bg-coollabs-100 dark:hover:text-white;')
|
||||
->toContain('@apply border-coollabs-200 bg-linear-to-b from-coollabs-100 to-coollabs-200 text-white! hover:from-coollabs-100 hover:to-coollabs hover:text-white!;')
|
||||
->and($appStyles)
|
||||
->toContain('button[isHighlighted]:not(:disabled)')
|
||||
->toContain('@apply button-highlighted;')
|
||||
|
||||
@@ -1,25 +1,20 @@
|
||||
<?php
|
||||
|
||||
test('loading indicators use yellow throughout dark mode', function () {
|
||||
test('loading indicators use coollabs purple throughout dark mode', function () {
|
||||
$utilities = file_get_contents(resource_path('css/utilities.css'));
|
||||
$appCss = file_get_contents(resource_path('css/app.css'));
|
||||
$loading = file_get_contents(resource_path('views/components/loading.blade.php'));
|
||||
$pageLoading = file_get_contents(resource_path('views/components/page-loading.blade.php'));
|
||||
$views = collect(new RecursiveIteratorIterator(new RecursiveDirectoryIterator(resource_path('views'))))
|
||||
->filter(fn (SplFileInfo $file): bool => $file->isFile() && $file->getExtension() === 'php')
|
||||
->map(fn (SplFileInfo $file): string => file_get_contents($file->getPathname()))
|
||||
->implode("\n");
|
||||
|
||||
expect($utilities)
|
||||
->toContain('@utility loading-indicator')
|
||||
->toContain('@apply text-coollabs dark:text-warning;')
|
||||
->toContain('@apply text-coollabs dark:text-coollabs;')
|
||||
->and($loading)->toContain('loading-indicator')
|
||||
->and($pageLoading)->toContain('loading-indicator')
|
||||
->and($appCss)->toContain('.dark .animate-spin')
|
||||
->toContain('color: var(--color-warning) !important;')
|
||||
->toContain('color: var(--color-coollabs) !important;')
|
||||
->toContain('.dark #nprogress .bar')
|
||||
->toContain('background: var(--color-warning) !important;')
|
||||
->and($views)->not->toMatch('/animate-spin[^"\n]*dark:text-coollabs|dark:text-coollabs[^"\n]*animate-spin/');
|
||||
->toContain('background: var(--color-coollabs) !important;')
|
||||
->not->toContain('color: var(--color-warning) !important;');
|
||||
});
|
||||
|
||||
test('livewire navigation progress bar uses coollabs purple', function () {
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
it('keeps horizontal space around sidebar items for focus rings', function () {
|
||||
$navbar = file_get_contents(resource_path('views/components/navbar.blade.php'));
|
||||
|
||||
expect($navbar)
|
||||
->toContain('class="-mx-1 flex min-h-0 flex-1 flex-col gap-y-0.5 overflow-y-auto px-1 pb-2 scrollbar"');
|
||||
});
|
||||
@@ -155,6 +155,19 @@ it('starts the global terminal only once when a target is selected', function ()
|
||||
->toMatch('/public function updatedSelectedUuid\(\).*?\$this->connectToContainer\(\);/s');
|
||||
});
|
||||
|
||||
it('groups global terminal targets by type with labelled sections', function () {
|
||||
$view = file_get_contents(resource_path('views/livewire/terminal/index.blade.php'));
|
||||
|
||||
expect($view)
|
||||
->toContain('get filteredTargetGroups()')
|
||||
->toContain("label: 'Servers'")
|
||||
->toContain("label: 'Containers'")
|
||||
->toContain('x-for="group in filteredTargetGroups"')
|
||||
->toContain('x-text="group.label"')
|
||||
->toContain('x-for="target in group.targets"')
|
||||
->not->toContain('x-for="target in filteredTargets"');
|
||||
});
|
||||
|
||||
it('uses the redesigned terminal canvas and controls on resource terminal pages', function () {
|
||||
$view = file_get_contents(resource_path('views/livewire/project/shared/execute-container-command.blade.php'));
|
||||
|
||||
|
||||
@@ -177,19 +177,20 @@ it('moves application terminal and logs from the top tabs into the settings side
|
||||
->not->toContain("'label' => 'Runtime'")
|
||||
->and($sidebar)
|
||||
->toContain("'label' => 'Terminal'")
|
||||
->toContain("'label' => 'Deployment'")
|
||||
->toContain("'label' => 'Runtime'")
|
||||
->toContain("'Logs' => ['Deployment', 'Runtime']")
|
||||
->toContain("'Operations' => ['Terminal', 'Rollback', 'Resource Limits'");
|
||||
->toContain("'label' => 'Deployment Logs'")
|
||||
->toContain("'label' => 'Runtime Logs'")
|
||||
->toContain("'Observe & troubleshoot' => ['Runtime Logs', 'Deployment Logs', 'Terminal', 'Metrics']")
|
||||
->toContain("'Operations' => ['Resource Operations', 'Resource Limits', 'Rollback'");
|
||||
});
|
||||
|
||||
it('groups application automation pages separately from build and deploy', function () {
|
||||
$sidebar = file_get_contents(resource_path('views/components/application/configuration-sidebar.blade.php'));
|
||||
|
||||
expect($sidebar)
|
||||
->toContain("'Build & deploy' => ['Git Source', 'Servers', 'Healthcheck']")
|
||||
->toContain("'Automation' => ['Scheduled Tasks', 'Webhooks', 'Preview Deployments']")
|
||||
->toContain("'Operations' => ['Terminal', 'Rollback', 'Resource Limits'");
|
||||
->toContain("'Settings' => ['General', 'Domains', 'Environment Variables', 'Persistent Storage', 'Advanced', 'Swarm', 'Healthcheck']")
|
||||
->toContain("'Deploy' => ['Git Source', 'Servers', 'Preview Deployments']")
|
||||
->toContain("'Automation' => ['Scheduled Tasks', 'Webhooks', 'Backups']")
|
||||
->toContain("'Operations' => ['Resource Operations', 'Resource Limits', 'Rollback'");
|
||||
});
|
||||
|
||||
it('centers the rollback image loading state across the card', function () {
|
||||
@@ -291,7 +292,7 @@ it('removes desktop top spacing from the deployment log viewer', function () {
|
||||
it('uses a distinct runtime log icon in the sidebar', function () {
|
||||
$sidebar = file_get_contents(resource_path('views/components/application/configuration-sidebar.blade.php'));
|
||||
|
||||
expect($sidebar)->toContain("'Runtime' => 'unordered-list'");
|
||||
expect($sidebar)->toContain("'Runtime Logs' => 'unordered-list'");
|
||||
});
|
||||
|
||||
it('shows deployment history above the selected deployment logs', function () {
|
||||
|
||||
@@ -47,6 +47,25 @@ test('unsaved bar saves with enter and shows the shortcut on the save button', f
|
||||
->toContain('Enter</kbd>');
|
||||
});
|
||||
|
||||
test('unsaved bar keyboard shortcut remains visible in light mode', function () {
|
||||
$contents = file_get_contents(resource_path('views/components/unsaved-bar.blade.php'));
|
||||
|
||||
expect($contents)
|
||||
->toContain('border-coollabs/20 bg-coollabs/10')
|
||||
->toContain('text-coollabs-200')
|
||||
->toContain('dark:border-white/20 dark:bg-white/10 dark:text-white/75');
|
||||
});
|
||||
|
||||
test('unsaved bar uses a light surface in light mode', function () {
|
||||
$contents = file_get_contents(resource_path('views/components/unsaved-bar.blade.php'));
|
||||
|
||||
expect($contents)
|
||||
->toContain('border-neutral-200 bg-white')
|
||||
->toContain('text-neutral-800 dark:text-fg')
|
||||
->toContain('bg-neutral-100')
|
||||
->toContain('dark:bg-white/[0.07]');
|
||||
});
|
||||
|
||||
test('unsaved bar stays above floating notifications so save actions remain accessible', function () {
|
||||
$unsavedBar = file_get_contents(resource_path('views/components/unsaved-bar.blade.php'));
|
||||
$popup = file_get_contents(resource_path('views/components/popup-small.blade.php'));
|
||||
|
||||
@@ -18,3 +18,42 @@ test('provider pages only show the token action in the account panel', function
|
||||
->not->toContain('new-server-token-')
|
||||
->not->toContain('tokenProviderName');
|
||||
});
|
||||
|
||||
test('server selection separates existing servers from cloud provisioning', function (string $viewPath) {
|
||||
$view = file_get_contents(resource_path($viewPath));
|
||||
|
||||
expect($view)
|
||||
->toContain('Add a server')
|
||||
->toContain('IP address or domain')
|
||||
->toContain('Provision a server')
|
||||
->and(strpos($view, 'Add a server'))->toBeLessThan(strpos($view, 'Provision a server'));
|
||||
})->with([
|
||||
'new server page' => 'views/livewire/server/create.blade.php',
|
||||
'onboarding' => 'views/livewire/boarding/index.blade.php',
|
||||
]);
|
||||
|
||||
test('new server sections have vertical spacing', function () {
|
||||
$view = file_get_contents(resource_path('views/livewire/server/create.blade.php'));
|
||||
|
||||
expect($view)->toContain('<div class="application-settings-form flex flex-col gap-6">');
|
||||
});
|
||||
|
||||
test('server selection uses the provider logos', function () {
|
||||
$newServerView = file_get_contents(resource_path('views/livewire/server/create.blade.php'));
|
||||
$onboardingView = file_get_contents(resource_path('views/livewire/boarding/index.blade.php'));
|
||||
|
||||
expect($newServerView)
|
||||
->toContain('src="https://www.vultr.com/media/logo_ondark.svg"')
|
||||
->toContain("src=\"{{ asset('svgs/hetzner.svg') }}\"")
|
||||
->and($onboardingView)
|
||||
->toContain('src="https://www.vultr.com/media/logo_ondark.svg"')
|
||||
->toContain("src=\"{{ asset('svgs/hetzner.svg') }}\"");
|
||||
});
|
||||
|
||||
test('new server cards do not show method badges', function () {
|
||||
$view = file_get_contents(resource_path('views/livewire/server/create.blade.php'));
|
||||
|
||||
expect($view)
|
||||
->not->toContain("\n Manual\n")
|
||||
->not->toContain("\n Provider\n");
|
||||
});
|
||||
@@ -6,7 +6,11 @@ test('server creation keeps private key actions together and advanced options co
|
||||
expect($view)
|
||||
->toContain('class="flex items-end gap-3"')
|
||||
->toContain('<x-forms.collapsible class="mt-5 border-t border-neutral-200 pt-4 dark:border-white/[0.08]"')
|
||||
->toContain('<x-forms.select id="is_build_server"')
|
||||
->toContain('label="Use as a dedicated build server"')
|
||||
->toContain('<option value="0">No</option>')
|
||||
->toContain('<option value="1">Yes</option>')
|
||||
->not->toContain('<x-forms.checkbox id="is_build_server"')
|
||||
->toContain('helper="Build servers compile applications but do not host deployments. Enabling this makes the server build-only."');
|
||||
});
|
||||
|
||||
|
||||
@@ -8,17 +8,21 @@ test('view switchers use the shared coollabs selected state on every page', func
|
||||
resource_path('views/livewire/project/resource/index.blade.php'),
|
||||
resource_path('views/livewire/project/service/configuration.blade.php'),
|
||||
resource_path('views/livewire/tags/show.blade.php'),
|
||||
resource_path('views/livewire/shared/list-search-controls.blade.php'),
|
||||
resource_path('views/components/shared-variables/view-controls.blade.php'),
|
||||
])->map(fn (string $path): string => file_get_contents($path));
|
||||
$utilities = file_get_contents(resource_path('css/utilities.css'));
|
||||
|
||||
expect($views->every(fn (string $view): bool => str_contains($view, "viewMode === 'table'")
|
||||
expect($views->every(fn (string $view): bool => (str_contains($view, "viewMode === 'table'") || str_contains($view, "viewMode === 'list'"))
|
||||
&& str_contains($view, "viewMode === 'grid'")
|
||||
&& str_contains($view, 'control-selected')))
|
||||
->toBeTrue()
|
||||
->and($views->every(fn (string $view): bool => str_contains($view, 'flex h-9')
|
||||
&& str_contains($view, 'size-7.5')))->toBeTrue()
|
||||
->and($views->implode("\n"))->not->toContain('dark:bg-warning/15 dark:text-warning')
|
||||
->and($utilities)
|
||||
->toContain('@utility control-selected')
|
||||
->toContain('@apply bg-coollabs text-white dark:bg-coollabs dark:text-white;');
|
||||
->toContain('@apply bg-linear-to-b from-coollabs-100 to-coollabs-200 text-white;');
|
||||
});
|
||||
|
||||
test('server index does not expose server IP addresses', function () {
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
test('server cards use icon borders instead of ready badges', function () {
|
||||
$dashboard = file_get_contents(resource_path('views/livewire/dashboard.blade.php'));
|
||||
$serverIndex = file_get_contents(resource_path('views/livewire/server/index.blade.php'));
|
||||
|
||||
expect($dashboard)
|
||||
->not->toContain('<x-status-badge :status="$serverStatus"')
|
||||
->toContain("'border-emerald-500/70' => \$serverStatusType === 'success'")
|
||||
->toContain("'border-amber-500/70' => \$serverStatusType === 'warning'")
|
||||
->toContain("'border-red-500/70' => \$serverStatusType === 'error'")
|
||||
->toContain('title="{{ $serverStatus }}"')
|
||||
->toContain('aria-label="Server status: {{ $serverStatus }}"');
|
||||
|
||||
expect(substr_count($serverIndex, '<x-status-badge'))->toBe(1)
|
||||
->and($serverIndex)
|
||||
->toContain("\$isReady => 'success'")
|
||||
->toContain("\$isTransferredAway || \$server->settings->force_disabled => 'error'")
|
||||
->toContain("default => 'warning'")
|
||||
->toContain("server.statusType === 'success' ? 'border-emerald-500/70'")
|
||||
->toContain("server.statusType === 'warning' ? 'border-amber-500/70'")
|
||||
->toContain("'border-red-500/70'")
|
||||
->toContain(':title="server.status"')
|
||||
->toContain(':aria-label="`Server status: ${server.status}`"');
|
||||
});
|
||||
|
||||
test('server table keeps status text without a badge', function () {
|
||||
$serverIndex = file_get_contents(resource_path('views/livewire/server/index.blade.php'));
|
||||
|
||||
expect($serverIndex)
|
||||
->toContain('<span x-text="server.status"></span>')
|
||||
->toContain('text-[11px] font-medium')
|
||||
->not->toContain('<x-status-badge dynamic>');
|
||||
});
|
||||
@@ -10,11 +10,11 @@ it('moves service and database page navigation into their sidebars', function ()
|
||||
->and($databaseHeading)->not->toContain('<x-resource-heading-tabs')
|
||||
->and($serviceConfiguration)
|
||||
->toContain("['label' => 'Backups'")
|
||||
->toContain("['label' => 'Runtime'")
|
||||
->toContain("['label' => 'Runtime Logs'")
|
||||
->toContain("['label' => 'Terminal'")
|
||||
->and($databaseSidebar)
|
||||
->toContain("['label' => 'Backups'")
|
||||
->toContain("['label' => 'Runtime'")
|
||||
->toContain("['label' => 'Runtime Logs'")
|
||||
->toContain("['label' => 'Terminal'");
|
||||
});
|
||||
|
||||
@@ -41,21 +41,38 @@ it('matches application action bar behavior for services and databases', functio
|
||||
->and($database)->toContain('id="database-desktop-actions"');
|
||||
});
|
||||
|
||||
it('keeps database and service sidebar sections in the application sequence', function () {
|
||||
it('groups database and service navigation by user workflow', function () {
|
||||
$database = file_get_contents(resource_path('views/components/database/configuration-sidebar.blade.php'));
|
||||
$service = file_get_contents(resource_path('views/livewire/project/service/configuration.blade.php'));
|
||||
$serviceSidebars = [
|
||||
file_get_contents(resource_path('views/components/service/configuration-sidebar.blade.php')),
|
||||
file_get_contents(resource_path('views/livewire/project/service/configuration.blade.php')),
|
||||
];
|
||||
|
||||
expect($database)
|
||||
->toContain("'Settings' => ['General', 'Environment Variables', 'Persistent Storage', 'Backups', 'Import Backup', 'Servers']")
|
||||
->toContain("'Automation' => ['Webhooks', 'Healthcheck']")
|
||||
->toContain("'Logs' => ['Runtime']")
|
||||
->toContain("'Operations' => ['Terminal', 'Resource Limits', 'Resource Operations', 'Metrics', 'Tags', 'Danger Zone']");
|
||||
->toContain("'Settings' => ['General', 'Environment Variables', 'Persistent Storage', 'Healthcheck']")
|
||||
->toContain("'Observe & troubleshoot' => ['Runtime Logs', 'Terminal', 'Metrics']")
|
||||
->toContain("'Deploy' => ['Servers']")
|
||||
->toContain("'Automation' => ['Webhooks', 'Backups', 'Import Backup']")
|
||||
->toContain("'Operations' => ['Resource Operations', 'Resource Limits', 'Tags', 'Danger Zone']");
|
||||
|
||||
expect($service)
|
||||
->toContain("'Settings' => ['General', 'Domains', 'Environment Variables', 'Persistent Storage', 'Backups']")
|
||||
->toContain("'Automation' => ['Scheduled Tasks', 'Webhooks']")
|
||||
->toContain("'Logs' => ['Runtime']")
|
||||
->toContain("'Operations' => ['Terminal', 'Resource Operations', 'Tags', 'Danger Zone']");
|
||||
foreach ($serviceSidebars as $serviceSidebar) {
|
||||
expect($serviceSidebar)
|
||||
->toContain("'Settings' => ['General', 'Domains', 'Environment Variables', 'Persistent Storage']")
|
||||
->toContain("'Observe & troubleshoot' => ['Runtime Logs', 'Terminal']")
|
||||
->toContain("'Automation' => ['Scheduled Tasks', 'Webhooks', 'Backups']")
|
||||
->toContain("'Operations' => ['Resource Operations', 'Tags', 'Danger Zone']");
|
||||
}
|
||||
});
|
||||
|
||||
it('groups application navigation by user workflow', function () {
|
||||
$application = file_get_contents(resource_path('views/components/application/configuration-sidebar.blade.php'));
|
||||
|
||||
expect($application)
|
||||
->toContain("'Settings' => ['General', 'Domains', 'Environment Variables', 'Persistent Storage', 'Advanced', 'Swarm', 'Healthcheck']")
|
||||
->toContain("'Observe & troubleshoot' => ['Runtime Logs', 'Deployment Logs', 'Terminal', 'Metrics']")
|
||||
->toContain("'Deploy' => ['Git Source', 'Servers', 'Preview Deployments']")
|
||||
->toContain("'Automation' => ['Scheduled Tasks', 'Webhooks', 'Backups']")
|
||||
->toContain("'Operations' => ['Resource Operations', 'Resource Limits', 'Rollback', 'Tags', 'Danger Zone']");
|
||||
});
|
||||
|
||||
it('shows the database sidebar on backup pages', function () {
|
||||
@@ -155,6 +172,6 @@ it('shows the service sidebar on runtime logs and terminal pages', function () {
|
||||
->toContain("in_array(\$type, ['application', 'database', 'service', 'server'], true)")
|
||||
->toContain('<x-service.configuration-sidebar :service="$resource" current-route="project.service.command"')
|
||||
->and($sidebar)
|
||||
->toContain("'Logs' => ['Runtime']")
|
||||
->toContain("'Operations' => ['Terminal', 'Resource Operations', 'Tags', 'Danger Zone']");
|
||||
->toContain("'Observe & troubleshoot' => ['Runtime Logs', 'Terminal']")
|
||||
->toContain("'Operations' => ['Resource Operations', 'Tags', 'Danger Zone']");
|
||||
});
|
||||
@@ -2,8 +2,10 @@
|
||||
|
||||
use App\Livewire\Storage\Resources as StorageResources;
|
||||
use App\Models\InstanceSettings;
|
||||
use App\Models\LocalPersistentVolume;
|
||||
use App\Models\S3Storage;
|
||||
use App\Models\ScheduledDatabaseBackup;
|
||||
use App\Models\ScheduledVolumeBackup;
|
||||
use App\Models\Team;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
@@ -75,6 +77,57 @@ beforeEach(function () {
|
||||
});
|
||||
|
||||
describe('Storage/Resources team-scoped backup access', function () {
|
||||
test('lists and manages volume backup schedules using this storage', function () {
|
||||
$volume = LocalPersistentVolume::create([
|
||||
'name' => 'minio-volume-data',
|
||||
'mount_path' => '/data',
|
||||
'resource_id' => 999,
|
||||
'resource_type' => 'App\\Models\\Application',
|
||||
]);
|
||||
$backup = ScheduledVolumeBackup::create([
|
||||
'uuid' => fake()->uuid(),
|
||||
'backupable_type' => $volume->getMorphClass(),
|
||||
'backupable_id' => $volume->id,
|
||||
'team_id' => $this->teamA->id,
|
||||
's3_storage_id' => $this->storageA->id,
|
||||
'frequency' => 'daily',
|
||||
'enabled' => true,
|
||||
'save_s3' => true,
|
||||
]);
|
||||
$destination = S3Storage::unguarded(fn () => S3Storage::create([
|
||||
'uuid' => fake()->uuid(),
|
||||
'name' => 'volume-backup-destination',
|
||||
'region' => 'us-east-1',
|
||||
'key' => 'key-c',
|
||||
'secret' => 'secret-c',
|
||||
'bucket' => 'bucket-c',
|
||||
'endpoint' => 'https://s3.example.com',
|
||||
'team_id' => $this->teamA->id,
|
||||
'is_usable' => true,
|
||||
]));
|
||||
|
||||
Livewire::test(StorageResources::class, ['storage' => $this->storageA])
|
||||
->assertSee('minio-volume-data')
|
||||
->assertSee('Volume')
|
||||
->assertSeeHtml('class="listbox-trigger"')
|
||||
->assertSeeHtml('x-teleport="body"')
|
||||
->assertSeeHtml('requestAnimationFrame')
|
||||
->assertSeeHtml('-panel"')
|
||||
->assertSeeHtml("visibility: positioned ? 'visible' : 'hidden'")
|
||||
->assertSeeHtml('positionPanel($el)')
|
||||
->assertSeeHtml('class="flex items-center"')
|
||||
->set("selectedVolumeStorages.{$backup->id}", $destination->id)
|
||||
->call('moveVolumeBackup', $backup->id);
|
||||
|
||||
expect($backup->refresh()->s3_storage_id)->toBe($destination->id);
|
||||
|
||||
Livewire::test(StorageResources::class, ['storage' => $destination])
|
||||
->call('disableVolumeS3', $backup->id);
|
||||
|
||||
expect($backup->refresh()->save_s3)->toBeFalse()
|
||||
->and($backup->s3_storage_id)->toBeNull();
|
||||
});
|
||||
|
||||
test('disableS3 on other team backup throws and leaves row unchanged', function () {
|
||||
expect(fn () => Livewire::test(StorageResources::class, ['storage' => $this->storageA])
|
||||
->call('disableS3', $this->backupB->id))
|
||||
|
||||
@@ -19,6 +19,18 @@ it('still shows the user name and email inside the dropdown panel', function ()
|
||||
->toContain('{{ $userEmail }}');
|
||||
});
|
||||
|
||||
it('animates the dropdown panel when the user menu opens', function () {
|
||||
$menu = file_get_contents(resource_path('views/components/top-user-menu.blade.php'));
|
||||
$stylesheet = file_get_contents(resource_path('css/app.css'));
|
||||
|
||||
expect($menu)
|
||||
->toContain('animate-in fade-in zoom-in-95 duration-150')
|
||||
->toContain("'origin-bottom-left' => \$sidebar")
|
||||
->toContain("'origin-top-right' => ! \$sidebar");
|
||||
|
||||
expect($stylesheet)->toContain('@import "tw-animate-css";');
|
||||
});
|
||||
|
||||
it('changes appearance from a submenu instead of navigating to a separate page', function () {
|
||||
$menu = file_get_contents(resource_path('views/components/top-user-menu.blade.php'));
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
it('uses a thin warning yellow focus ring in dark mode', function () {
|
||||
$appStyles = file_get_contents(dirname(__DIR__, 2).'/resources/css/app.css');
|
||||
$v5Styles = file_get_contents(dirname(__DIR__, 2).'/resources/css/v5/app.css');
|
||||
|
||||
expect($appStyles)
|
||||
->toContain('ring-2 ring-coollabs dark:ring-1 dark:ring-warning')
|
||||
->and($v5Styles)
|
||||
->toMatch('/\.dark\s*\{[^}]*--ring:\s*var\(--warning\);/s')
|
||||
->toContain('ring-2 dark:ring-1 ring-ring');
|
||||
});
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
it('uses coollabs purple for scrollbars in dark mode', function () {
|
||||
$utilities = file_get_contents(dirname(__DIR__, 2).'/resources/css/utilities.css');
|
||||
|
||||
expect($utilities)
|
||||
->toContain('dark:scrollbar-thumb-coollabs-100')
|
||||
->not->toContain('dark:scrollbar-thumb-warning');
|
||||
});
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
"version": "1.0.14"
|
||||
},
|
||||
"realtime": {
|
||||
"version": "1.0.16"
|
||||
"version": "1.0.17"
|
||||
},
|
||||
"sentinel": {
|
||||
"version": "0.0.22"
|
||||
|
||||
+7
-1
@@ -16,6 +16,11 @@ export default defineConfig(({ mode }) => {
|
||||
viteHost
|
||||
).trim();
|
||||
const vitePort = Number(process.env.VITE_PORT || env.VITE_PORT || 5173);
|
||||
const viteProtocol = (
|
||||
process.env.VITE_PROTOCOL ||
|
||||
env.VITE_PROTOCOL ||
|
||||
"http"
|
||||
).trim();
|
||||
|
||||
return {
|
||||
resolve: {
|
||||
@@ -34,10 +39,11 @@ export default defineConfig(({ mode }) => {
|
||||
allowedHosts: true,
|
||||
// App (:8000) and Vite (:5173) are different origins; allow any host in dev
|
||||
cors: true,
|
||||
origin: `http://${viteHost}:${vitePort}`,
|
||||
origin: `${viteProtocol}://${viteHost}:${vitePort}`,
|
||||
hmr: {
|
||||
host: viteHmrHost,
|
||||
clientPort: vitePort,
|
||||
protocol: viteProtocol === "https" ? "wss" : "ws",
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
|
||||
Reference in new issue
Block a user