Merge pull request #4887 from coollabsio/next

v4.0.0-beta.385
This commit is contained in:
Andras Bacsai
2025-01-21 20:06:44 +01:00
committed by GitHub
18 changed files with 440 additions and 135 deletions

View File

@@ -25,7 +25,7 @@ class PullTemplatesFromCDN implements ShouldBeEncrypted, ShouldQueue
public function handle(): void
{
try {
if (isDev() || isCloud()) {
if (isDev()) {
return;
}
$response = Http::retry(3, 1000)->get(config('constants.services.official'));

View File

@@ -442,6 +442,7 @@ class General extends Component
{
$config = GenerateConfig::run($this->application, true);
$fileName = str($this->application->name)->slug()->append('_config.json');
dd($config);
return response()->streamDownload(function () use ($config) {
echo $config;

View File

@@ -27,6 +27,8 @@ class ExecuteContainerCommand extends Component
public Collection $servers;
public bool $hasShell = true;
protected $rules = [
'server' => 'required',
'container' => 'required',
@@ -141,6 +143,16 @@ class ExecuteContainerCommand extends Component
}
}
private function checkShellAvailability(Server $server, string $container): bool
{
$escapedContainer = escapeshellarg($container);
$result = instant_remote_process([
"docker exec {$escapedContainer} which bash || docker exec {$escapedContainer} which sh",
], $server, false);
return ! empty($result);
}
#[On('connectToServer')]
public function connectToServer()
{
@@ -148,6 +160,7 @@ class ExecuteContainerCommand extends Component
if ($this->server->isForceDisabled()) {
throw new \RuntimeException('Server is disabled.');
}
$this->hasShell = true;
$this->dispatch(
'send-terminal-command',
false,
@@ -201,6 +214,11 @@ class ExecuteContainerCommand extends Component
throw new \RuntimeException('Server ownership verification failed.');
}
$this->hasShell = $this->checkShellAvailability($server, data_get($container, 'container.Names'));
if (! $this->hasShell) {
return;
}
$this->dispatch(
'send-terminal-command',
true,

View File

@@ -3,6 +3,8 @@
namespace App\Models;
use App\Enums\ApplicationDeploymentStatus;
use App\Services\ConfigurationGenerator;
use App\Traits\HasConfiguration;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\HasMany;
@@ -105,7 +107,7 @@ use Visus\Cuid2\Cuid2;
class Application extends BaseModel
{
use HasFactory, SoftDeletes;
use HasConfiguration, HasFactory, SoftDeletes;
private static $parserVersion = '4';
@@ -1640,35 +1642,28 @@ class Application extends BaseModel
}
}
public function getLimits(): array
{
return [
'limits_memory' => $this->limits_memory,
'limits_memory_swap' => $this->limits_memory_swap,
'limits_memory_swappiness' => $this->limits_memory_swappiness,
'limits_memory_reservation' => $this->limits_memory_reservation,
'limits_cpus' => $this->limits_cpus,
'limits_cpuset' => $this->limits_cpuset,
'limits_cpu_shares' => $this->limits_cpu_shares,
];
}
public function generateConfig($is_json = false)
{
$config = collect([]);
if ($this->build_pack = 'nixpacks') {
$config = collect([
'build_pack' => 'nixpacks',
'docker_registry_image_name' => $this->docker_registry_image_name,
'docker_registry_image_tag' => $this->docker_registry_image_tag,
'install_command' => $this->install_command,
'build_command' => $this->build_command,
'start_command' => $this->start_command,
'base_directory' => $this->base_directory,
'publish_directory' => $this->publish_directory,
'custom_docker_run_options' => $this->custom_docker_run_options,
'ports_exposes' => $this->ports_exposes,
'ports_mappings' => $this->ports_mapping,
'settings' => collect([
'is_static' => $this->settings->is_static,
]),
]);
}
$config = $config->filter(function ($value) {
return str($value)->isNotEmpty();
});
$generator = new ConfigurationGenerator($this);
if ($is_json) {
return json_encode($config, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
return $generator->toJson();
}
return $config;
return $generator->toArray();
}
public function setConfig($config)

View File

@@ -53,6 +53,7 @@ class EmailChannel
if (! $type) {
throw new Exception('No email settings found.');
}
config()->set('mail.default', $type);
return;
}

View File

@@ -0,0 +1,194 @@
<?php
namespace App\Services;
use App\Models\Application;
use Symfony\Component\Yaml\Yaml;
class ConfigurationGenerator
{
protected array $config = [];
public function __construct(protected Application $resource)
{
$this->generateConfig();
}
protected function generateConfig(): void
{
if ($this->resource instanceof Application) {
$this->config = [
'id' => $this->resource->id,
'name' => $this->resource->name,
'uuid' => $this->resource->uuid,
'description' => $this->resource->description,
'coolify_details' => [
'project_uuid' => $this->resource->project()->uuid,
'environment_uuid' => $this->resource->environment->uuid,
'destination_type' => $this->resource->destination_type,
'destination_id' => $this->resource->destination_id,
'source_type' => $this->resource->source_type,
'source_id' => $this->resource->source_id,
'private_key_id' => $this->resource->private_key_id,
],
'post_deployment_command' => $this->resource->post_deployment_command,
'post_deployment_command_container' => $this->resource->post_deployment_command_container,
'pre_deployment_command' => $this->resource->pre_deployment_command,
'pre_deployment_command_container' => $this->resource->pre_deployment_command_container,
'build' => [
'type' => $this->resource->build_pack,
'static_image' => $this->resource->static_image,
'base_directory' => $this->resource->base_directory,
'publish_directory' => $this->resource->publish_directory,
'dockerfile' => $this->resource->dockerfile,
'dockerfile_location' => $this->resource->dockerfile_location,
'dockerfile_target_build' => $this->resource->dockerfile_target_build,
'custom_docker_run_options' => $this->resource->custom_docker_options,
'compose_parsing_version' => $this->resource->compose_parsing_version,
'docker_compose' => $this->resource->docker_compose,
'docker_compose_location' => $this->resource->docker_compose_location,
'docker_compose_raw' => $this->resource->docker_compose_raw,
'docker_compose_domains' => $this->resource->docker_compose_domains,
'docker_compose_custom_start_command' => $this->resource->docker_compose_custom_start_command,
'docker_compose_custom_build_command' => $this->resource->docker_compose_custom_build_command,
'install_command' => $this->resource->install_command,
'build_command' => $this->resource->build_command,
'start_command' => $this->resource->start_command,
'watch_paths' => $this->resource->watch_paths,
],
'source' => [
'git_repository' => $this->resource->git_repository,
'git_branch' => $this->resource->git_branch,
'git_commit_sha' => $this->resource->git_commit_sha,
'repository_project_id' => $this->resource->repository_project_id,
],
'docker_registry_image' => $this->getDockerRegistryImage(),
'domains' => [
'fqdn' => $this->resource->fqdn,
'ports_exposes' => $this->resource->ports_exposes,
'ports_mappings' => $this->resource->ports_mappings,
'redirect' => $this->resource->redirect,
'custom_nginx_configuration' => $this->resource->custom_nginx_configuration,
],
'environment_variables' => [
'production' => $this->getEnvironmentVariables(),
'preview' => $this->getPreviewEnvironmentVariables(),
],
'settings' => $this->getApplicationSettings(),
'preview' => $this->getPreview(),
'limits' => $this->resource->getLimits(),
'health_check' => [
'health_check_path' => $this->resource->health_check_path,
'health_check_port' => $this->resource->health_check_port,
'health_check_host' => $this->resource->health_check_host,
'health_check_method' => $this->resource->health_check_method,
'health_check_return_code' => $this->resource->health_check_return_code,
'health_check_scheme' => $this->resource->health_check_scheme,
'health_check_response_text' => $this->resource->health_check_response_text,
'health_check_interval' => $this->resource->health_check_interval,
'health_check_timeout' => $this->resource->health_check_timeout,
'health_check_retries' => $this->resource->health_check_retries,
'health_check_start_period' => $this->resource->health_check_start_period,
'health_check_enabled' => $this->resource->health_check_enabled,
],
'webhooks_secrets' => [
'manual_webhook_secret_github' => $this->resource->manual_webhook_secret_github,
'manual_webhook_secret_gitlab' => $this->resource->manual_webhook_secret_gitlab,
'manual_webhook_secret_bitbucket' => $this->resource->manual_webhook_secret_bitbucket,
'manual_webhook_secret_gitea' => $this->resource->manual_webhook_secret_gitea,
],
'swarm' => [
'swarm_replicas' => $this->resource->swarm_replicas,
'swarm_placement_constraints' => $this->resource->swarm_placement_constraints,
],
];
}
}
protected function getPreview(): array
{
return [
'preview_url_template' => $this->resource->preview_url_template,
];
}
protected function getDockerRegistryImage(): array
{
return [
'image' => $this->resource->docker_registry_image_name,
'tag' => $this->resource->docker_registry_image_tag,
];
}
protected function getEnvironmentVariables(): array
{
$variables = collect([]);
foreach ($this->resource->environment_variables as $env) {
$variables->push([
'key' => $env->key,
'value' => $env->value,
'is_build_time' => $env->is_build_time,
'is_preview' => $env->is_preview,
'is_multiline' => $env->is_multiline,
]);
}
return $variables->toArray();
}
protected function getPreviewEnvironmentVariables(): array
{
$variables = collect([]);
foreach ($this->resource->environment_variables_preview as $env) {
$variables->push([
'key' => $env->key,
'value' => $env->value,
'is_build_time' => $env->is_build_time,
'is_preview' => $env->is_preview,
'is_multiline' => $env->is_multiline,
]);
}
return $variables->toArray();
}
protected function getApplicationSettings(): array
{
$removedKeys = ['id', 'application_id', 'created_at', 'updated_at'];
$settings = $this->resource->settings->attributesToArray();
$settings = collect($settings)->filter(function ($value, $key) use ($removedKeys) {
return ! in_array($key, $removedKeys);
})->sortBy(function ($value, $key) {
return $key;
})->toArray();
return $settings;
}
public function saveJson(string $path): void
{
file_put_contents($path, json_encode($this->config, JSON_PRETTY_PRINT));
}
public function saveYaml(string $path): void
{
file_put_contents($path, Yaml::dump($this->config, 6, 2));
}
public function toArray(): array
{
return $this->config;
}
public function toJson(): string
{
return json_encode($this->config, JSON_PRETTY_PRINT);
}
public function toYaml(): string
{
return Yaml::dump($this->config, 6, 2);
}
}

View File

@@ -43,7 +43,11 @@ class DockerImageParser
public function getFullImageNameWithoutTag(): string
{
return $this->registryUrl.'/'.$this->imageName;
if ($this->registryUrl) {
return $this->registryUrl.'/'.$this->imageName;
}
return $this->imageName;
}
public function getRegistryUrl(): string

View File

@@ -0,0 +1,42 @@
<?php
namespace App\Traits;
use App\Services\ConfigurationGenerator;
trait HasConfiguration
{
public function generateConfigurationFiles(): void
{
$generator = new ConfigurationGenerator($this);
$configDir = base_configuration_dir()."/{$this->uuid}";
if (! is_dir($configDir)) {
mkdir($configDir, 0755, true);
}
$generator->saveJson($configDir.'/coolify.json');
$generator->saveYaml($configDir.'/coolify.yaml');
// Generate a README file with basic information
file_put_contents(
$configDir.'/README.md',
generate_readme_file($this->name, now()->toIso8601String())
);
}
public function getConfigurationAsJson(): string
{
return (new ConfigurationGenerator($this))->toJson();
}
public function getConfigurationAsYaml(): string
{
return (new ConfigurationGenerator($this))->toYaml();
}
public function getConfigurationAsArray(): array
{
return (new ConfigurationGenerator($this))->toArray();
}
}

View File

@@ -2872,7 +2872,6 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
data_forget($service, 'volumes.*.is_directory');
data_forget($service, 'exclude_from_hc');
data_set($service, 'environment', $serviceVariables->toArray());
updateCompose($service);
return $service;
});

View File

@@ -2,7 +2,7 @@
return [
'coolify' => [
'version' => '4.0.0-beta.384',
'version' => '4.0.0-beta.385',
'self_hosted' => env('SELF_HOSTED', true),
'autoupdate' => env('AUTOUPDATE'),
'base_config_path' => env('BASE_CONFIG_PATH', '/data/coolify'),

View File

@@ -0,0 +1,37 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
try {
DB::table('application_deployment_queues')
->whereNull('finished_at')
->update(['finished_at' => DB::raw('updated_at')]);
} catch (\Exception $e) {
\Log::error('Failed to update not set finished_at timestamps for application_deployment_queues: '.$e->getMessage());
}
try {
DB::table('scheduled_database_backup_executions')
->whereNull('finished_at')
->update(['finished_at' => DB::raw('updated_at')]);
} catch (\Exception $e) {
\Log::error('Failed to update not set finished_at timestamps for scheduled_database_backup_executions: '.$e->getMessage());
}
try {
DB::table('scheduled_task_executions')
->whereNull('finished_at')
->update(['finished_at' => DB::raw('updated_at')]);
} catch (\Exception $e) {
\Log::error('Failed to update not set finished_at timestamps for scheduled_task_executions: '.$e->getMessage());
}
}
};

View File

@@ -5,13 +5,14 @@
<x-forms.button type="submit">
Save
</x-forms.button>
{{--
<x-forms.button wire:click="downloadConfig">
{{-- <x-forms.button wire:click="downloadConfig">
Download Config
<x-modal-input buttonTitle="Upload Config" title="Upload Config" :closeOutside="false">
</x-forms.button> --}}
{{-- <x-modal-input buttonTitle="Upload Config" title="Upload Config" :closeOutside="false">
<livewire:project.shared.upload-config :applicationId="$application->id" />
</x-modal-input>
--}}
</x-modal-input> --}}
</div>
<div>General configuration for your application.</div>
<div class="flex flex-col gap-2 py-4">

View File

@@ -55,10 +55,10 @@
<h3>Preview Deployments Environment Variables</h3>
<div>Environment (secrets) variables for Preview Deployments.</div>
</div>
{{-- @foreach ($resource->environment_variables_preview as $env)
@foreach ($resource->environment_variables_preview as $env)
<livewire:project.shared.environment-variable.show wire:key="environment-{{ $env->id }}"
:env="$env" :type="$resource->type()" />
@endforeach --}}
@endforeach
@endif
@else
<form wire:submit.prevent='submit' class="flex flex-col gap-2">

View File

@@ -16,43 +16,58 @@
@elseif ($type === 'server')
<x-server.navbar :server="$server" :parameters="$parameters" />
@endif
@if ($type === 'server')
<form class="w-full" wire:submit="$dispatchSelf('connectToServer')" wire:init="$dispatchSelf('connectToServer')">
<x-forms.button class="w-full" type="submit">Reconnect</x-forms.button>
</form>
<div class="mx-auto w-full">
<livewire:project.shared.terminal />
@if(!$hasShell)
<div class="flex items-center justify-center w-full py-4 mx-auto">
<div class="p-4 w-full rounded border dark:bg-coolgray-100 dark:border-coolgray-300">
<div class="flex flex-col items-center justify-center space-y-4">
<svg class="w-12 h-12 text-red-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"/>
</svg>
<div class="text-center">
<h3 class="text-lg font-medium">Terminal Not Available</h3>
<p class="mt-2 text-sm text-gray-500">No shell (bash/sh) is available in this container. Please ensure either bash or sh is installed to use the terminal.</p>
</div>
</div>
</div>
</div>
@else
@if (count($containers) > 0)
@if (count($containers) === 1)
<form class="w-full pt-4" wire:submit="$dispatchSelf('connectToContainer')"
wire:init="$dispatchSelf('connectToContainer')">
<x-forms.button class="w-full" type="submit">Reconnect</x-forms.button>
</form>
@else
<form class="w-full pt-4 flex gap-2 flex-col" wire:submit="$dispatchSelf('connectToContainer')">
<x-forms.select label="Container" id="container" required wire:model="selected_container">
@foreach ($containers as $container)
@if ($loop->first)
<option disabled value="default">Select a container</option>
@endif
<option value="{{ data_get($container, 'container.Names') }}">
{{ data_get($container, 'container.Names') }}
({{ data_get($container, 'server.name') }})
</option>
@endforeach
</x-forms.select>
<x-forms.button class="w-full" type="submit">
Connect
</x-forms.button>
</form>
@endif
@if ($type === 'server')
<form class="w-full" wire:submit="$dispatchSelf('connectToServer')" wire:init="$dispatchSelf('connectToServer')">
<x-forms.button class="w-full" type="submit">Reconnect</x-forms.button>
</form>
<div class="mx-auto w-full">
<livewire:project.shared.terminal />
</div>
@else
<div class="pt-4">No containers are running.</div>
@if (count($containers) === 0)
<div class="pt-4">No containers are running.</div>
@else
@if (count($containers) === 1)
<form class="w-full pt-4" wire:submit="$dispatchSelf('connectToContainer')"
wire:init="$dispatchSelf('connectToContainer')">
<x-forms.button class="w-full" type="submit">Reconnect</x-forms.button>
</form>
@else
<form class="w-full pt-4 flex gap-2 flex-col" wire:submit="$dispatchSelf('connectToContainer')">
<x-forms.select label="Container" id="container" required wire:model="selected_container">
@foreach ($containers as $container)
@if ($loop->first)
<option disabled value="default">Select a container</option>
@endif
<option value="{{ data_get($container, 'container.Names') }}">
{{ data_get($container, 'container.Names') }}
({{ data_get($container, 'server.name') }})
</option>
@endforeach
</x-forms.select>
<x-forms.button class="w-full" type="submit">Connect</x-forms.button>
</form>
@endif
<div class="mx-auto w-full">
<livewire:project.shared.terminal />
</div>
@endif
@endif
@endif
</div>

View File

@@ -1,9 +1,4 @@
<div id="terminal-container" x-data="terminalData()">
{{-- <div x-show="!terminalActive" class="flex items-center justify-center w-full py-4 mx-auto h-[510px]">
<div class="p-1 w-full h-full rounded border dark:bg-coolgray-100 dark:border-coolgray-300">
<span class="font-mono text-sm text-gray-500" x-text="message"></span>
</div>
</div> --}}
<div x-ref="terminalWrapper"
:class="fullscreen ? 'fullscreen' : 'relative w-full h-full py-4 mx-auto max-h-[510px]'">
<div id="terminal" wire:ignore></div>

View File

@@ -6,72 +6,75 @@
<div x-data="{ activeTab: window.location.hash ? window.location.hash.substring(1) : 'general' }" class="flex flex-col h-full gap-8 sm:flex-row">
<x-server.sidebar :server="$server" activeMenu="docker-cleanup" />
<div class="w-full">
<div>
<div class="flex items-center gap-2">
<h2>Docker Cleanup</h2>
<form wire:submit='submit'>
<div>
<div class="flex items-center gap-2">
<h2>Docker Cleanup</h2>
<x-forms.button type="submit">Save</x-forms.button>
</div>
<div class="mt-3 mb-4">Configure Docker cleanup settings for your server.</div>
</div>
<div class="mt-3 mb-4">Configure Docker cleanup settings for your server.</div>
</div>
<div class="flex flex-col gap-2">
<div class="flex gap-4">
<h3>Docker Cleanup</h3>
<x-modal-confirmation title="Confirm Docker Cleanup?" buttonTitle="Trigger Manual Cleanup"
isHighlightedButton submitAction="manualCleanup" :actions="[
'Permanently deletes all stopped containers managed by Coolify (as containers are non-persistent, no data will be lost)',
'Permanently deletes all unused images',
'Clears build cache',
'Removes old versions of the Coolify helper image',
'Optionally permanently deletes all unused volumes (if enabled in advanced options).',
'Optionally permanently deletes all unused networks (if enabled in advanced options).',
]" :confirmWithText="false"
:confirmWithPassword="false" step2ButtonText="Trigger Docker Cleanup" />
</div>
<div class="flex flex-wrap items-center gap-4">
<x-forms.input placeholder="*/10 * * * *" id="dockerCleanupFrequency"
label="Docker cleanup frequency" required
helper="Cron expression for Docker Cleanup.<br>You can use every_minute, hourly, daily, weekly, monthly, yearly.<br><br>Default is every night at midnight." />
@if (!$forceDockerCleanup)
<x-forms.input id="dockerCleanupThreshold" label="Docker cleanup threshold (%)" required
helper="The Docker cleanup tasks will run when the disk usage exceeds this threshold." />
@endif
<div class="flex flex-col gap-2">
<div class="flex gap-4">
<h3>Docker Cleanup</h3>
<x-modal-confirmation title="Confirm Docker Cleanup?" buttonTitle="Trigger Manual Cleanup"
isHighlightedButton submitAction="manualCleanup" :actions="[
'Permanently deletes all stopped containers managed by Coolify (as containers are non-persistent, no data will be lost)',
'Permanently deletes all unused images',
'Clears build cache',
'Removes old versions of the Coolify helper image',
'Optionally permanently deletes all unused volumes (if enabled in advanced options).',
'Optionally permanently deletes all unused networks (if enabled in advanced options).',
]" :confirmWithText="false"
:confirmWithPassword="false" step2ButtonText="Trigger Docker Cleanup" />
</div>
<div class="flex flex-wrap items-center gap-4">
<x-forms.input placeholder="*/10 * * * *" id="dockerCleanupFrequency"
label="Docker cleanup frequency" required
helper="Cron expression for Docker Cleanup.<br>You can use every_minute, hourly, daily, weekly, monthly, yearly.<br><br>Default is every night at midnight." />
@if (!$forceDockerCleanup)
<x-forms.input id="dockerCleanupThreshold" label="Docker cleanup threshold (%)" required
helper="The Docker cleanup tasks will run when the disk usage exceeds this threshold." />
@endif
<div class="w-96">
<x-forms.checkbox
helper="Enabling Force Docker Cleanup or manually triggering a cleanup will perform the following actions:
<ul class='list-disc pl-4 mt-2'>
<li>Removes stopped containers managed by Coolify (as containers are none persistent, no data will be lost).</li>
<li>Deletes unused images.</li>
<li>Clears build cache.</li>
<li>Removes old versions of the Coolify helper image.</li>
<li>Optionally delete unused volumes (if enabled in advanced options).</li>
<li>Optionally remove unused networks (if enabled in advanced options).</li>
</ul>"
instantSave id="forceDockerCleanup" label="Force Docker Cleanup" />
</div>
</div>
<p class="text-sm text-gray-600 dark:text-gray-400 mb-2">
<span class="dark:text-warning font-bold">Warning: Enable these
options only if you fully understand their implications and
consequences!</span><br>Improper use will result in data loss and could cause
functional issues.
</p>
<div class="w-96">
<x-forms.checkbox
helper="Enabling Force Docker Cleanup or manually triggering a cleanup will perform the following actions:
<x-forms.checkbox instantSave id="deleteUnusedVolumes" label="Delete Unused Volumes"
helper="This option will remove all unused Docker volumes during cleanup.<br><br><strong>Warning: Data form stopped containers will be lost!</strong><br><br>Consequences include:<br>
<ul class='list-disc pl-4 mt-2'>
<li>Removes stopped containers managed by Coolify (as containers are none persistent, no data will be lost).</li>
<li>Deletes unused images.</li>
<li>Clears build cache.</li>
<li>Removes old versions of the Coolify helper image.</li>
<li>Optionally delete unused volumes (if enabled in advanced options).</li>
<li>Optionally remove unused networks (if enabled in advanced options).</li>
</ul>"
instantSave id="forceDockerCleanup" label="Force Docker Cleanup" />
<li>Volumes not attached to running containers will be deleted and data will be permanently lost (stopped containers are affected).</li>
<li>Data from stopped containers volumes will be permanently lost.</li>
<li>No way to recover deleted volume data.</li>
</ul>" />
<x-forms.checkbox instantSave id="deleteUnusedNetworks" label="Delete Unused Networks"
helper="This option will remove all unused Docker networks during cleanup.<br><br><strong>Warning: Functionality may be lost and containers may not be able to communicate with each other!</strong><br><br>Consequences include:<br>
<ul class='list-disc pl-4 mt-2'>
<li>Networks not attached to running containers will be permanently deleted (stopped containers are affected).</li>
<li>Custom networks for stopped containers will be permanently deleted.</li>
<li>Functionality may be lost and containers may not be able to communicate with each other.</li>
</ul>" />
</div>
</div>
<p class="text-sm text-gray-600 dark:text-gray-400 mb-2">
<span class="dark:text-warning font-bold">Warning: Enable these
options only if you fully understand their implications and
consequences!</span><br>Improper use will result in data loss and could cause
functional issues.
</p>
<div class="w-96">
<x-forms.checkbox instantSave id="deleteUnusedVolumes" label="Delete Unused Volumes"
helper="This option will remove all unused Docker volumes during cleanup.<br><br><strong>Warning: Data form stopped containers will be lost!</strong><br><br>Consequences include:<br>
<ul class='list-disc pl-4 mt-2'>
<li>Volumes not attached to running containers will be deleted and data will be permanently lost (stopped containers are affected).</li>
<li>Data from stopped containers volumes will be permanently lost.</li>
<li>No way to recover deleted volume data.</li>
</ul>" />
<x-forms.checkbox instantSave id="deleteUnusedNetworks" label="Delete Unused Networks"
helper="This option will remove all unused Docker networks during cleanup.<br><br><strong>Warning: Functionality may be lost and containers may not be able to communicate with each other!</strong><br><br>Consequences include:<br>
<ul class='list-disc pl-4 mt-2'>
<li>Networks not attached to running containers will be permanently deleted (stopped containers are affected).</li>
<li>Custom networks for stopped containers will be permanently deleted.</li>
<li>Functionality may be lost and containers may not be able to communicate with each other.</li>
</ul>" />
</div>
</div>
</form>
<div class="mt-8">
<h3 class="mb-4">Recent executions <span class="text-xs text-neutral-500">(click to check output)</span></h3>

View File

@@ -449,7 +449,7 @@
"cloudflared": {
"documentation": "https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/?utm_source=coolify.io",
"slogan": "Client for Cloudflare Tunnel, a daemon that exposes private services through the Cloudflare edge.",
"compose": "c2VydmljZXM6CiAgY2xvdWRmbGFyZWQ6CiAgICBjb250YWluZXJfbmFtZTogY2xvdWRmbGFyZS10dW5uZWwKICAgIGltYWdlOiAnY2xvdWRmbGFyZS9jbG91ZGZsYXJlZDpsYXRlc3QnCiAgICByZXN0YXJ0OiB1bmxlc3Mtc3RvcHBlZAogICAgbmV0d29ya19tb2RlOiBob3N0CiAgICBjb21tYW5kOiAndHVubmVsIC0tbm8tYXV0b3VwZGF0ZSBydW4nCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSAnVFVOTkVMX1RPS0VOPSR7Q0xPVURGTEFSRV9UVU5ORUxfVE9LRU59Jwo=",
"compose": "c2VydmljZXM6CiAgY2xvdWRmbGFyZWQ6CiAgICBjb250YWluZXJfbmFtZTogY2xvdWRmbGFyZS10dW5uZWwKICAgIGltYWdlOiAnY2xvdWRmbGFyZS9jbG91ZGZsYXJlZDpsYXRlc3QnCiAgICByZXN0YXJ0OiB1bmxlc3Mtc3RvcHBlZAogICAgbmV0d29ya19tb2RlOiBob3N0CiAgICBjb21tYW5kOiAndHVubmVsIC0tbm8tYXV0b3VwZGF0ZSBydW4nCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSAnVFVOTkVMX1RPS0VOPSR7Q0xPVURGTEFSRV9UVU5ORUxfVE9LRU59JwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIGNsb3VkZmxhcmVkCiAgICAgICAgLSAnLS12ZXJzaW9uJwogICAgICBpbnRlcnZhbDogNXMKICAgICAgdGltZW91dDogMjBzCiAgICAgIHJldHJpZXM6IDEwCg==",
"tags": null,
"logo": "svgs/cloudflared.svg",
"minversion": "0.0.0"

View File

@@ -1,10 +1,10 @@
{
"coolify": {
"v4": {
"version": "4.0.0-beta.384"
"version": "4.0.0-beta.385"
},
"nightly": {
"version": "4.0.0-beta.385"
"version": "4.0.0-beta.386"
},
"helper": {
"version": "1.0.4"