@@ -8,6 +8,7 @@ use App\Models\StandalonePostgresql;
|
|||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
|
|
||||||
use function Laravel\Prompts\confirm;
|
use function Laravel\Prompts\confirm;
|
||||||
|
use function Laravel\Prompts\multiselect;
|
||||||
use function Laravel\Prompts\select;
|
use function Laravel\Prompts\select;
|
||||||
|
|
||||||
class ResourcesDelete extends Command
|
class ResourcesDelete extends Command
|
||||||
@@ -50,16 +51,18 @@ class ResourcesDelete extends Command
|
|||||||
$this->error('There are no applications to delete.');
|
$this->error('There are no applications to delete.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$application = select(
|
$applicationsToDelete = multiselect(
|
||||||
'What application do you want to delete?',
|
'What application do you want to delete?',
|
||||||
$applications->pluck('name')->toArray(),
|
$applications->pluck('name')->toArray(),
|
||||||
);
|
);
|
||||||
$application = $applications->where('name', $application)->first();
|
$confirmed = confirm("Are you sure you want to delete all selected resources?");
|
||||||
$confirmed = confirm("Are you sure you want to delete {$application->name}?");
|
|
||||||
if (!$confirmed) {
|
if (!$confirmed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$application->delete();
|
foreach ($applicationsToDelete as $application) {
|
||||||
|
$toDelete = $applications->where('name', $application)->first();
|
||||||
|
$toDelete->delete();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
private function deleteDatabase()
|
private function deleteDatabase()
|
||||||
{
|
{
|
||||||
@@ -68,16 +71,19 @@ class ResourcesDelete extends Command
|
|||||||
$this->error('There are no databases to delete.');
|
$this->error('There are no databases to delete.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$database = select(
|
$databasesToDelete = multiselect(
|
||||||
'What database do you want to delete?',
|
'What database do you want to delete?',
|
||||||
$databases->pluck('name')->toArray(),
|
$databases->pluck('name')->toArray(),
|
||||||
);
|
);
|
||||||
$database = $databases->where('name', $database)->first();
|
$confirmed = confirm("Are you sure you want to delete all selected resources?");
|
||||||
$confirmed = confirm("Are you sure you want to delete {$database->name}?");
|
|
||||||
if (!$confirmed) {
|
if (!$confirmed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$database->delete();
|
foreach ($databasesToDelete as $database) {
|
||||||
|
$toDelete = $databases->where('name', $database)->first();
|
||||||
|
$toDelete->delete();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
private function deleteService()
|
private function deleteService()
|
||||||
{
|
{
|
||||||
@@ -86,15 +92,17 @@ class ResourcesDelete extends Command
|
|||||||
$this->error('There are no services to delete.');
|
$this->error('There are no services to delete.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$service = select(
|
$servicesToDelete = multiselect(
|
||||||
'What service do you want to delete?',
|
'What service do you want to delete?',
|
||||||
$services->pluck('name')->toArray(),
|
$services->pluck('name')->toArray(),
|
||||||
);
|
);
|
||||||
$service = $services->where('name', $service)->first();
|
$confirmed = confirm("Are you sure you want to delete all selected resources?");
|
||||||
$confirmed = confirm("Are you sure you want to delete {$service->name}?");
|
|
||||||
if (!$confirmed) {
|
if (!$confirmed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$service->delete();
|
foreach ($servicesToDelete as $service) {
|
||||||
|
$toDelete = $services->where('name', $service)->first();
|
||||||
|
$toDelete->delete();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,7 +76,6 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
|
|||||||
Team::find(currentTeam()->id)->update([
|
Team::find(currentTeam()->id)->update([
|
||||||
'show_boarding' => false
|
'show_boarding' => false
|
||||||
]);
|
]);
|
||||||
ray(currentTeam());
|
|
||||||
refreshSession();
|
refreshSession();
|
||||||
return redirect()->route('dashboard');
|
return redirect()->route('dashboard');
|
||||||
}
|
}
|
||||||
|
|||||||
28
app/Http/Livewire/Dev/Compose.php
Normal file
28
app/Http/Livewire/Dev/Compose.php
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Livewire\Dev;
|
||||||
|
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
class Compose extends Component
|
||||||
|
{
|
||||||
|
public string $compose = '';
|
||||||
|
public string $base64 = '';
|
||||||
|
public $services;
|
||||||
|
public function mount() {
|
||||||
|
$this->services = getServiceTemplates();
|
||||||
|
}
|
||||||
|
public function setService(string $selected) {
|
||||||
|
$this->base64 = data_get($this->services, $selected . '.compose');
|
||||||
|
if ($this->base64) {
|
||||||
|
$this->compose = base64_decode($this->base64);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public function updatedCompose($value) {
|
||||||
|
$this->base64 = base64_encode($value);
|
||||||
|
}
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return view('livewire.dev.compose');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,7 +22,7 @@ class Project extends BaseModel
|
|||||||
'project_id' => $project->id,
|
'project_id' => $project->id,
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
static::deleted(function ($project) {
|
static::deleting(function ($project) {
|
||||||
$project->environments()->delete();
|
$project->environments()->delete();
|
||||||
$project->settings()->delete();
|
$project->settings()->delete();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ class Service extends BaseModel
|
|||||||
|
|
||||||
protected static function booted()
|
protected static function booted()
|
||||||
{
|
{
|
||||||
static::deleted(function ($service) {
|
static::deleting(function ($service) {
|
||||||
$storagesToDelete = collect([]);
|
$storagesToDelete = collect([]);
|
||||||
foreach ($service->applications()->get() as $application) {
|
foreach ($service->applications()->get() as $application) {
|
||||||
instant_remote_process(["docker rm -f {$application->name}-{$service->uuid}"], $service->server, false);
|
instant_remote_process(["docker rm -f {$application->name}-{$service->uuid}"], $service->server, false);
|
||||||
@@ -266,7 +266,7 @@ class Service extends BaseModel
|
|||||||
|
|
||||||
// Collect/create/update volumes
|
// Collect/create/update volumes
|
||||||
if ($serviceVolumes->count() > 0) {
|
if ($serviceVolumes->count() > 0) {
|
||||||
$serviceVolumes = $serviceVolumes->map(function ($volume) use ($savedService, $topLevelVolumes, $isNew) {
|
$serviceVolumes = $serviceVolumes->map(function ($volume) use ($savedService, $topLevelVolumes) {
|
||||||
$type = null;
|
$type = null;
|
||||||
$source = null;
|
$source = null;
|
||||||
$target = null;
|
$target = null;
|
||||||
@@ -384,9 +384,20 @@ class Service extends BaseModel
|
|||||||
$value = Str::of($variable);
|
$value = Str::of($variable);
|
||||||
}
|
}
|
||||||
if ($key->startsWith('SERVICE_FQDN')) {
|
if ($key->startsWith('SERVICE_FQDN')) {
|
||||||
if (is_null(data_get($savedService, 'fqdn'))) {
|
if ($isNew) {
|
||||||
$fqdn = generateFqdn($this->server, $containerName);
|
$name = $key->after('SERVICE_FQDN_')->beforeLast('_')->lower();
|
||||||
if (substr_count($key->value(), '_') === 2) {
|
$fqdn = generateFqdn($this->server, "{$name->value()}-{$this->uuid}");
|
||||||
|
if (substr_count($key->value(), '_') === 3) {
|
||||||
|
// SERVICE_FQDN_UMAMI_1000
|
||||||
|
$port = $key->afterLast('_');
|
||||||
|
} else {
|
||||||
|
// SERVICE_FQDN_UMAMI
|
||||||
|
$port = null;
|
||||||
|
}
|
||||||
|
if ($port) {
|
||||||
|
$fqdn = "$fqdn:$port";
|
||||||
|
}
|
||||||
|
if (substr_count($key->value(), '_') >= 2) {
|
||||||
if (is_null($value)) {
|
if (is_null($value)) {
|
||||||
$value = Str::of('/');
|
$value = Str::of('/');
|
||||||
}
|
}
|
||||||
@@ -403,11 +414,22 @@ class Service extends BaseModel
|
|||||||
}
|
}
|
||||||
$fqdn = "$fqdn$path";
|
$fqdn = "$fqdn$path";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$isDatabase) {
|
if (!$isDatabase) {
|
||||||
|
if ($savedService->fqdn) {
|
||||||
|
$fqdn = $savedService->fqdn . ',' . $fqdn;
|
||||||
|
} else {
|
||||||
|
$fqdn = $fqdn;
|
||||||
|
}
|
||||||
$savedService->fqdn = $fqdn;
|
$savedService->fqdn = $fqdn;
|
||||||
$savedService->save();
|
$savedService->save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// data_forget($service, "environment.$variableName");
|
||||||
|
// $yaml = data_forget($yaml, "services.$serviceName.environment.$variableName");
|
||||||
|
// if (count(data_get($yaml, 'services.' . $serviceName . '.environment')) === 0) {
|
||||||
|
// $yaml = data_forget($yaml, "services.$serviceName.environment");
|
||||||
|
// }
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ($value?->startsWith('$')) {
|
if ($value?->startsWith('$')) {
|
||||||
@@ -422,10 +444,17 @@ class Service extends BaseModel
|
|||||||
$forService = $value->afterLast('_');
|
$forService = $value->afterLast('_');
|
||||||
$generatedValue = null;
|
$generatedValue = null;
|
||||||
if ($command->value() === 'FQDN' || $command->value() === 'URL') {
|
if ($command->value() === 'FQDN' || $command->value() === 'URL') {
|
||||||
|
if (Str::lower($forService) === $serviceName) {
|
||||||
$fqdn = generateFqdn($this->server, $containerName);
|
$fqdn = generateFqdn($this->server, $containerName);
|
||||||
|
} else {
|
||||||
|
$fqdn = generateFqdn($this->server, Str::lower($forService) . '-' . $this->uuid);
|
||||||
|
}
|
||||||
if ($foundEnv) {
|
if ($foundEnv) {
|
||||||
$fqdn = data_get($foundEnv, 'value');
|
$fqdn = data_get($foundEnv, 'value');
|
||||||
} else {
|
} else {
|
||||||
|
if ($command->value() === 'URL') {
|
||||||
|
$fqdn = Str::of($fqdn)->after('://')->value();
|
||||||
|
}
|
||||||
EnvironmentVariable::create([
|
EnvironmentVariable::create([
|
||||||
'key' => $key,
|
'key' => $key,
|
||||||
'value' => $fqdn,
|
'value' => $fqdn,
|
||||||
@@ -434,11 +463,12 @@ class Service extends BaseModel
|
|||||||
'is_preview' => false,
|
'is_preview' => false,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$isDatabase) {
|
if (!$isDatabase) {
|
||||||
|
if ($command->value() === 'FQDN') {
|
||||||
$savedService->fqdn = $fqdn;
|
$savedService->fqdn = $fqdn;
|
||||||
$savedService->save();
|
$savedService->save();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
switch ($command) {
|
switch ($command) {
|
||||||
case 'PASSWORD':
|
case 'PASSWORD':
|
||||||
@@ -513,19 +543,19 @@ class Service extends BaseModel
|
|||||||
$serviceLabels = $serviceLabels->merge(fqdnLabelsForTraefik($fqdns, $containerName, true));
|
$serviceLabels = $serviceLabels->merge(fqdnLabelsForTraefik($fqdns, $containerName, true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data_set($service, 'labels', $serviceLabels->toArray());
|
data_set($service, 'labels', $serviceLabels->toArray());
|
||||||
data_forget($service, 'is_database');
|
data_forget($service, 'is_database');
|
||||||
data_set($service, 'restart', RESTART_MODE);
|
data_set($service, 'restart', RESTART_MODE);
|
||||||
data_set($service, 'container_name', $containerName);
|
data_set($service, 'container_name', $containerName);
|
||||||
data_forget($service, 'volumes.*.content');
|
data_forget($service, 'volumes.*.content');
|
||||||
data_forget($service, 'volumes.*.isDirectory');
|
data_forget($service, 'volumes.*.isDirectory');
|
||||||
|
|
||||||
// Remove unnecessary variables from service.environment
|
// Remove unnecessary variables from service.environment
|
||||||
$withoutServiceEnvs = collect([]);
|
$withoutServiceEnvs = collect([]);
|
||||||
collect(data_get($service, 'environment'))->each(function ($value, $key) use ($withoutServiceEnvs) {
|
collect(data_get($service, 'environment'))->each(function ($value, $key) use ($withoutServiceEnvs) {
|
||||||
if (!Str::of($key)->startsWith('$SERVICE_')) {
|
if (!Str::of($key)->startsWith('$SERVICE_') && !Str::of($value)->startsWith('SERVICE_')) {
|
||||||
$withoutServiceEnvs->put($key, $value);
|
$k = Str::of($value)->before("=");
|
||||||
|
$v = Str::of($value)->after("=");
|
||||||
|
$withoutServiceEnvs->put($k->value(), $v->value());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
data_set($service, 'environment', $withoutServiceEnvs->toArray());
|
data_set($service, 'environment', $withoutServiceEnvs->toArray());
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ class StandalonePostgresql extends BaseModel
|
|||||||
'is_readonly' => true
|
'is_readonly' => true
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
static::deleted(function ($database) {
|
static::deleting(function ($database) {
|
||||||
// Stop Container
|
// Stop Container
|
||||||
instant_remote_process(
|
instant_remote_process(
|
||||||
["docker rm -f {$database->uuid}"],
|
["docker rm -f {$database->uuid}"],
|
||||||
|
|||||||
@@ -157,11 +157,13 @@ function fqdnLabelsForTraefik(Collection $domains, $container_name, $is_force_ht
|
|||||||
$path = $url->getPath();
|
$path = $url->getPath();
|
||||||
$schema = $url->getScheme();
|
$schema = $url->getScheme();
|
||||||
$port = $url->getPort();
|
$port = $url->getPort();
|
||||||
$slug = Str::slug($host . $path);
|
|
||||||
|
|
||||||
$http_label = "{$container_name}-{$slug}-http";
|
|
||||||
$https_label = "{$container_name}-{$slug}-https";
|
|
||||||
|
|
||||||
|
$http_label = "{$container_name}-http";
|
||||||
|
$https_label = "{$container_name}-https";
|
||||||
|
if ($port) {
|
||||||
|
$http_label = "{$http_label}-{$port}";
|
||||||
|
$https_label = "{$https_label}-{$port}";
|
||||||
|
}
|
||||||
if ($schema === 'https') {
|
if ($schema === 'https') {
|
||||||
// Set labels for https
|
// Set labels for https
|
||||||
$labels->push("traefik.http.routers.{$https_label}.rule=Host(`{$host}`) && PathPrefix(`{$path}`)");
|
$labels->push("traefik.http.routers.{$https_label}.rule=Host(`{$host}`) && PathPrefix(`{$path}`)");
|
||||||
|
|||||||
@@ -137,13 +137,18 @@ function updateCompose($resource)
|
|||||||
|
|
||||||
// Update FQDN
|
// Update FQDN
|
||||||
$variableName = "SERVICE_FQDN_" . Str::of($resource->name)->upper();
|
$variableName = "SERVICE_FQDN_" . Str::of($resource->name)->upper();
|
||||||
ray($variableName);
|
|
||||||
$generatedEnv = EnvironmentVariable::where('service_id', $resource->service_id)->where('key', $variableName)->first();
|
$generatedEnv = EnvironmentVariable::where('service_id', $resource->service_id)->where('key', $variableName)->first();
|
||||||
if ($generatedEnv) {
|
if ($generatedEnv) {
|
||||||
$generatedEnv->value = $resource->fqdn;
|
$generatedEnv->value = $resource->fqdn;
|
||||||
$generatedEnv->save();
|
$generatedEnv->save();
|
||||||
}
|
}
|
||||||
|
$variableName = "SERVICE_URL_" . Str::of($resource->name)->upper();
|
||||||
|
$generatedEnv = EnvironmentVariable::where('service_id', $resource->service_id)->where('key', $variableName)->first();
|
||||||
|
if ($generatedEnv) {
|
||||||
|
$url = Str::of($resource->fqdn)->after('://');
|
||||||
|
$generatedEnv->value = $url;
|
||||||
|
$generatedEnv->save();
|
||||||
|
}
|
||||||
|
|
||||||
$dockerComposeRaw = Yaml::dump($dockerCompose, 10, 2);
|
$dockerComposeRaw = Yaml::dump($dockerCompose, 10, 2);
|
||||||
$resource->service->docker_compose_raw = $dockerComposeRaw;
|
$resource->service->docker_compose_raw = $dockerComposeRaw;
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ use Illuminate\Mail\Message;
|
|||||||
use Illuminate\Notifications\Messages\MailMessage;
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Facades\Cache;
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
use Illuminate\Support\Facades\File;
|
||||||
use Illuminate\Support\Facades\Http;
|
use Illuminate\Support\Facades\Http;
|
||||||
use Illuminate\Support\Facades\Mail;
|
use Illuminate\Support\Facades\Mail;
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
@@ -425,6 +426,16 @@ function getServiceTemplates()
|
|||||||
if (isDev()) {
|
if (isDev()) {
|
||||||
$services = File::get(base_path('templates/service-templates.json'));
|
$services = File::get(base_path('templates/service-templates.json'));
|
||||||
$services = collect(json_decode($services))->sortKeys();
|
$services = collect(json_decode($services))->sortKeys();
|
||||||
|
$deprecated = File::get(base_path('templates/deprecated.json'));
|
||||||
|
$deprecated = collect(json_decode($deprecated))->sortKeys();
|
||||||
|
$services = $services->merge($deprecated);
|
||||||
|
$version = config('version');
|
||||||
|
$services = $services->map(function ($service) use ($version) {
|
||||||
|
if (version_compare($version, data_get($service,'minVersion', '0.0.0'), '<')) {
|
||||||
|
$service->disabled = true;
|
||||||
|
}
|
||||||
|
return $service;
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
$services = Http::get(config('constants.services.official'));
|
$services = Http::get(config('constants.services.official'));
|
||||||
if ($services->failed()) {
|
if ($services->failed()) {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ return [
|
|||||||
|
|
||||||
// The release version of your application
|
// The release version of your application
|
||||||
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
|
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
|
||||||
'release' => '4.0.0-beta.64',
|
'release' => '4.0.0-beta.65',
|
||||||
// When left empty or `null` the Laravel environment will be used
|
// When left empty or `null` the Laravel environment will be used
|
||||||
'environment' => config('app.env'),
|
'environment' => config('app.env'),
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
return '4.0.0-beta.64';
|
return '4.0.0-beta.65';
|
||||||
|
|||||||
@@ -34,14 +34,14 @@ services:
|
|||||||
POSTGRES_DB: "${DB_DATABASE:-coolify}"
|
POSTGRES_DB: "${DB_DATABASE:-coolify}"
|
||||||
POSTGRES_HOST_AUTH_METHOD: "trust"
|
POSTGRES_HOST_AUTH_METHOD: "trust"
|
||||||
volumes:
|
volumes:
|
||||||
- /data/coolify/_volumes/database/:/var/lib/postgresql/data
|
- coolify-pg-data-dev:/var/lib/postgresql/data
|
||||||
redis:
|
redis:
|
||||||
ports:
|
ports:
|
||||||
- "${FORWARD_REDIS_PORT:-6379}:6379"
|
- "${FORWARD_REDIS_PORT:-6379}:6379"
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
volumes:
|
volumes:
|
||||||
- /data/coolify/_volumes/redis/:/data
|
- coolify-redis-data-dev:/data
|
||||||
vite:
|
vite:
|
||||||
image: node:19
|
image: node:19
|
||||||
working_dir: /var/www/html
|
working_dir: /var/www/html
|
||||||
@@ -56,7 +56,7 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- /:/host
|
- /:/host
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
- /data/coolify/:/data/coolify
|
- coolify-data-dev:/data/coolify
|
||||||
mailpit:
|
mailpit:
|
||||||
image: "axllent/mailpit:latest"
|
image: "axllent/mailpit:latest"
|
||||||
container_name: coolify-mail
|
container_name: coolify-mail
|
||||||
@@ -76,6 +76,12 @@ services:
|
|||||||
MINIO_ACCESS_KEY: "${MINIO_ACCESS_KEY:-minioadmin}"
|
MINIO_ACCESS_KEY: "${MINIO_ACCESS_KEY:-minioadmin}"
|
||||||
MINIO_SECRET_KEY: "${MINIO_SECRET_KEY:-minioadmin}"
|
MINIO_SECRET_KEY: "${MINIO_SECRET_KEY:-minioadmin}"
|
||||||
volumes:
|
volumes:
|
||||||
- /data/coolify/_volumes/minio/:/data
|
- coolify-minio-data-dev:/data
|
||||||
networks:
|
networks:
|
||||||
- coolify
|
- coolify
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
coolify-data-dev:
|
||||||
|
coolify-pg-data-dev:
|
||||||
|
coolify-redis-data-dev:
|
||||||
|
coolify-minio-data-dev:
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ services:
|
|||||||
- database__connection__password=$SERVICE_PASSWORD_MYSQL
|
- database__connection__password=$SERVICE_PASSWORD_MYSQL
|
||||||
- database__connection__database=${MYSQL_DATABASE-ghost}
|
- database__connection__database=${MYSQL_DATABASE-ghost}
|
||||||
depends_on:
|
depends_on:
|
||||||
- mysql
|
mysql:
|
||||||
|
condition: service_healthy
|
||||||
mysql:
|
mysql:
|
||||||
image: mysql:8.0
|
image: mysql:8.0
|
||||||
volumes:
|
volumes:
|
||||||
@@ -20,4 +21,9 @@ services:
|
|||||||
- MYSQL_USER=${SERVICE_USER_MYSQL}
|
- MYSQL_USER=${SERVICE_USER_MYSQL}
|
||||||
- MYSQL_PASSWORD=${SERVICE_PASSWORD_MYSQL}
|
- MYSQL_PASSWORD=${SERVICE_PASSWORD_MYSQL}
|
||||||
- MYSQL_DATABASE=${MYSQL_DATABASE}
|
- MYSQL_DATABASE=${MYSQL_DATABASE}
|
||||||
- MYSQL_ROOT_PASSWORD=${SERVICE_PASSWORD_MYSQL_ROOT}
|
- MYSQL_ROOT_PASSWORD=${SERVICE_PASSWORD_MYSQLROOT}
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 10
|
||||||
16
examples/compose/minio.yaml
Normal file
16
examples/compose/minio.yaml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
services:
|
||||||
|
minio:
|
||||||
|
image: quay.io/minio/minio:RELEASE.2023-09-30T07-02-29Z
|
||||||
|
command: server /data --console-address ":9001"
|
||||||
|
environment:
|
||||||
|
SERVICE_FQDN_MINIO_9000:
|
||||||
|
SERVICE_FQDN_CONSOLE_9001:
|
||||||
|
MINIO_ROOT_USER: $SERVICE_USER_MINIO
|
||||||
|
MINIO_ROOT_PASSWORD: $SERVICE_PASSWORD_MINIO
|
||||||
|
volumes:
|
||||||
|
- minio-data:/data
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 20s
|
||||||
|
retries: 10
|
||||||
@@ -55,6 +55,9 @@ a {
|
|||||||
.box {
|
.box {
|
||||||
@apply flex items-center p-2 transition-colors cursor-pointer min-h-16 bg-coolgray-200 hover:bg-coollabs-100 hover:text-white hover:no-underline min-w-[24rem];
|
@apply flex items-center p-2 transition-colors cursor-pointer min-h-16 bg-coolgray-200 hover:bg-coollabs-100 hover:text-white hover:no-underline min-w-[24rem];
|
||||||
}
|
}
|
||||||
|
.box-without-bg {
|
||||||
|
@apply flex items-center p-2 transition-colors min-h-16 hover:text-white hover:no-underline min-w-[24rem];
|
||||||
|
}
|
||||||
|
|
||||||
.lds-heart {
|
.lds-heart {
|
||||||
animation: lds-heart 1.2s infinite cubic-bezier(0.215, 0.61, 0.355, 1);
|
animation: lds-heart 1.2s infinite cubic-bezier(0.215, 0.61, 0.355, 1);
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
<a {{ $attributes->merge(['class' => 'text-xs cursor-pointer opacity-20 hover:opacity-100 hover:text-white z-50']) }}
|
<a {{ $attributes->merge(['class' => 'text-xs cursor-pointer opacity-60 hover:opacity-100 hover:text-white z-50']) }}
|
||||||
href="https://github.com/coollabsio/coolify/releases/tag/v{{ config('version') }}">v{{ config('version') }}</a>
|
href="https://github.com/coollabsio/coolify/releases/tag/v{{ config('version') }}">v{{ config('version') }}</a>
|
||||||
|
|||||||
13
resources/views/livewire/dev/compose.blade.php
Normal file
13
resources/views/livewire/dev/compose.blade.php
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<div class="pb-10" x-data>
|
||||||
|
<h1>Compose</h1>
|
||||||
|
<div>All kinds of compose files.</div>
|
||||||
|
<h3 class="pt-4">Services</h3>
|
||||||
|
@foreach ($services as $serviceName => $value)
|
||||||
|
<x-forms.button wire:click="setService('{{ $serviceName }}')">{{ Str::headline($serviceName) }}</x-forms.button>
|
||||||
|
@endforeach
|
||||||
|
<h3 class="pt-4">Base64 En/Decode</h3>
|
||||||
|
<x-forms.button x-on:click="copyToClipboard('{{ $base64 }}')">Copy Base64 Compose</x-forms.button>
|
||||||
|
<div class="pt-4">
|
||||||
|
<x-forms.textarea realtimeValidation rows="40" id="compose"></x-forms.textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -95,8 +95,19 @@
|
|||||||
<span class="loading loading-xs loading-spinner"></span>
|
<span class="loading loading-xs loading-spinner"></span>
|
||||||
@else
|
@else
|
||||||
@foreach ($services as $serviceName => $service)
|
@foreach ($services as $serviceName => $service)
|
||||||
<button class="text-left box group"
|
@if (data_get($service, 'disabled'))
|
||||||
wire:loading.attr="disabled" wire:click="setType('one-click-service-{{ $serviceName }}')">
|
<button class="text-left bg-black cursor-not-allowed bg-coolgray-200/20 box-without-bg"
|
||||||
|
disabled>
|
||||||
|
<div class="flex flex-col mx-6">
|
||||||
|
<div class="font-bold text-coolgray-500">
|
||||||
|
{{ Str::headline($serviceName) }}
|
||||||
|
</div>
|
||||||
|
You need to upgrade to {{ data_get($service, 'minVersion') }} to use this service.
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
@else
|
||||||
|
<button class="text-left box group" wire:loading.attr="disabled"
|
||||||
|
wire:click="setType('one-click-service-{{ $serviceName }}')">
|
||||||
<div class="flex flex-col mx-6">
|
<div class="flex flex-col mx-6">
|
||||||
<div class="font-bold text-white group-hover:text-white">
|
<div class="font-bold text-white group-hover:text-white">
|
||||||
{{ Str::headline($serviceName) }}
|
{{ Str::headline($serviceName) }}
|
||||||
@@ -108,6 +119,7 @@
|
|||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
|
@endif
|
||||||
@endforeach
|
@endforeach
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ use App\Http\Controllers\ServerController;
|
|||||||
use App\Http\Livewire\Boarding\Index as BoardingIndex;
|
use App\Http\Livewire\Boarding\Index as BoardingIndex;
|
||||||
use App\Http\Livewire\Project\Service\Index as ServiceIndex;
|
use App\Http\Livewire\Project\Service\Index as ServiceIndex;
|
||||||
use App\Http\Livewire\Project\Service\Show as ServiceShow;
|
use App\Http\Livewire\Project\Service\Show as ServiceShow;
|
||||||
|
use App\Http\Livewire\Dev\Compose as Compose;
|
||||||
use App\Http\Livewire\Dashboard;
|
use App\Http\Livewire\Dashboard;
|
||||||
use App\Http\Livewire\Project\Shared\Logs;
|
use App\Http\Livewire\Project\Shared\Logs;
|
||||||
use App\Http\Livewire\Server\All;
|
use App\Http\Livewire\Server\All;
|
||||||
@@ -29,6 +30,9 @@ use Laravel\Fortify\Contracts\FailedPasswordResetLinkRequestResponse;
|
|||||||
use Laravel\Fortify\Contracts\SuccessfulPasswordResetLinkRequestResponse;
|
use Laravel\Fortify\Contracts\SuccessfulPasswordResetLinkRequestResponse;
|
||||||
use Laravel\Fortify\Fortify;
|
use Laravel\Fortify\Fortify;
|
||||||
|
|
||||||
|
if (isDev()) {
|
||||||
|
Route::get('/dev/compose', Compose::class)->name('dev.compose');
|
||||||
|
}
|
||||||
Route::post('/forgot-password', function (Request $request) {
|
Route::post('/forgot-password', function (Request $request) {
|
||||||
if (is_transactional_emails_active()) {
|
if (is_transactional_emails_active()) {
|
||||||
$arrayOfRequest = $request->only(Fortify::email());
|
$arrayOfRequest = $request->only(Fortify::email());
|
||||||
@@ -94,7 +98,6 @@ Route::middleware(['auth'])->group(function () {
|
|||||||
Route::get('/project/{project_uuid}/{environment_name}/service/{service_uuid}', ServiceIndex::class)->name('project.service');
|
Route::get('/project/{project_uuid}/{environment_name}/service/{service_uuid}', ServiceIndex::class)->name('project.service');
|
||||||
Route::get('/project/{project_uuid}/{environment_name}/service/{service_uuid}/{service_name}', ServiceShow::class)->name('project.service.show');
|
Route::get('/project/{project_uuid}/{environment_name}/service/{service_uuid}/{service_name}', ServiceShow::class)->name('project.service.show');
|
||||||
Route::get('/project/{project_uuid}/{environment_name}/service/{service_uuid}/{service_name}/logs', Logs::class)->name('project.service.logs');
|
Route::get('/project/{project_uuid}/{environment_name}/service/{service_uuid}/{service_name}/logs', Logs::class)->name('project.service.logs');
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::middleware(['auth'])->group(function () {
|
Route::middleware(['auth'])->group(function () {
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ function help {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setup:dev {
|
function setup:dev {
|
||||||
docker exec coolify bash -c "composer install"
|
|
||||||
docker exec coolify bash -c "php artisan key:generate"
|
docker exec coolify bash -c "php artisan key:generate"
|
||||||
|
docker exec coolify bash -c "composer install"
|
||||||
docker exec coolify bash -c "php artisan migrate:fresh --seed"
|
docker exec coolify bash -c "php artisan migrate:fresh --seed"
|
||||||
}
|
}
|
||||||
function sync:v3 {
|
function sync:v3 {
|
||||||
|
|||||||
@@ -3,5 +3,5 @@
|
|||||||
"documentation": "https://plausible.io/docs",
|
"documentation": "https://plausible.io/docs",
|
||||||
"slogan": "A lighweight and open-source website analytics tool.",
|
"slogan": "A lighweight and open-source website analytics tool.",
|
||||||
"compose": "dmVyc2lvbjogJzMuMycKc2VydmljZXM6CiAgcGxhdXNpYmxlX2RiOgogICAgaW1hZ2U6ICdwb3N0Z3JlczoxNC1hbHBpbmUnCiAgICByZXN0YXJ0OiBhbHdheXMKICAgIHZvbHVtZXM6CiAgICAgIC0gJy9ldGMvZGF0YS9wbGF1c2libGUvZGItZGF0YTovdmFyL2xpYi9wb3N0Z3Jlc3FsL2RhdGEnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBQT1NUR1JFU19QQVNTV09SRD0kUE9TVEdSRVNfUEFTU1dPUkQKICBwbGF1c2libGVfZXZlbnRzX2RiOgogICAgaW1hZ2U6ICdjbGlja2hvdXNlL2NsaWNraG91c2Utc2VydmVyOjIzLjMuNy41LWFscGluZScKICAgIHJlc3RhcnQ6IGFsd2F5cwogICAgdm9sdW1lczoKICAgICAgLSAnL2V0Yy9kYXRhL3BsYXVzaWJsZS9ldmVudC1kYXRhOi92YXIvbGliL2NsaWNraG91c2UnCiAgICAgIC0gdHlwZTogYmluZAogICAgICAgIHNvdXJjZTogL2V0Yy9kYXRhL3BsYXVzaWJsZS9jbGlja2hvdXNlL2NsaWNraG91c2UtY29uZmlnLnhtbAogICAgICAgIHRhcmdldDogL2V0Yy9jbGlja2hvdXNlLXNlcnZlci9jb25maWcuZC9sb2dnaW5nLnhtbAogICAgICAgIHJlYWRfb25seTogdHJ1ZQogICAgICAgIGNvbnRlbnQ6ID4tCiAgICAgICAgICA8Y2xpY2tob3VzZT48cHJvZmlsZXM+PGRlZmF1bHQ+PGxvZ19xdWVyaWVzPjA8L2xvZ19xdWVyaWVzPjxsb2dfcXVlcnlfdGhyZWFkcz4wPC9sb2dfcXVlcnlfdGhyZWFkcz48L2RlZmF1bHQ+PC9wcm9maWxlcz48L2NsaWNraG91c2U+CiAgICAgIC0gdHlwZTogYmluZAogICAgICAgIHNvdXJjZTogL2V0Yy9kYXRhL3BsYXVzaWJsZS9jbGlja2hvdXNlL2NsaWNraG91c2UtdXNlci1jb25maWcueG1sCiAgICAgICAgdGFyZ2V0OiAvZXRjL2NsaWNraG91c2Utc2VydmVyL3VzZXJzLmQvbG9nZ2luZy54bWwKICAgICAgICByZWFkX29ubHk6IHRydWUKICAgICAgICBjb250ZW50OiA+LQogICAgICAgICAgPGNsaWNraG91c2U+PGxvZ2dlcj48bGV2ZWw+d2FybmluZzwvbGV2ZWw+PGNvbnNvbGU+dHJ1ZTwvY29uc29sZT48L2xvZ2dlcj48cXVlcnlfdGhyZWFkX2xvZwogICAgICAgICAgcmVtb3ZlPSJyZW1vdmUiLz48cXVlcnlfbG9nIHJlbW92ZT0icmVtb3ZlIi8+PHRleHRfbG9nCiAgICAgICAgICByZW1vdmU9InJlbW92ZSIvPjx0cmFjZV9sb2cgcmVtb3ZlPSJyZW1vdmUiLz48bWV0cmljX2xvZwogICAgICAgICAgcmVtb3ZlPSJyZW1vdmUiLz48YXN5bmNocm9ub3VzX21ldHJpY19sb2cKICAgICAgICAgIHJlbW92ZT0icmVtb3ZlIi8+PHNlc3Npb25fbG9nIHJlbW92ZT0icmVtb3ZlIi8+PHBhcnRfbG9nCiAgICAgICAgICByZW1vdmU9InJlbW92ZSIvPjwvY2xpY2tob3VzZT4KICAgIHVsaW1pdHM6CiAgICAgICAgbm9maWxlOgogICAgICAgICAgc29mdDogMjYyMTQ0CiAgICAgICAgICBoYXJkOiAyNjIxNDQKICBwbGF1c2libGU6CiAgICBpbWFnZTogJ3BsYXVzaWJsZS9hbmFseXRpY3M6djIuMCcKICAgIHJlc3RhcnQ6IGFsd2F5cwogICAgY29tbWFuZDogJ3NoIC1jICJzbGVlcCAxMCAmJiAvZW50cnlwb2ludC5zaCBkYiBjcmVhdGVkYiAmJiAvZW50cnlwb2ludC5zaCBkYiBtaWdyYXRlICYmIC9lbnRyeXBvaW50LnNoIHJ1biInCiAgICBkZXBlbmRzX29uOgogICAgICAtIHBsYXVzaWJsZV9kYgogICAgICAtIHBsYXVzaWJsZV9ldmVudHNfZGIKICAgIHBvcnRzOgogICAgICAtICc4MDAwOjgwMDAnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTRUNSRVRfS0VZX0JBU0U9JFNFQ1JFVF9LRVlfQkFTRQogICAgICAtIERBVEFCQVNFX1VSTD0kREFUQUJBU0VfVVJMCiAgICAgIC0gJ0NMSUNLSE9VU0VfREFUQUJBU0VfVVJMPWh0dHA6Ly9wbGF1c2libGVfZXZlbnRzX2RiOjgxMjMvcGxhdXNpYmxlX2V2ZW50c19kYicKICAgICAgLSBNQUlMRVJfQURBUFRFUj0kTUFJTEVSX0FEQVBURVIKICAgICAgLSBTRU5ER1JJRF9BUElfS0VZPSRTRU5ER1JJRF9BUElfS0VZCiAgICAgIC0gR09PR0xFX0NMSUVOVF9JRD0kR09PR0xFX0NMSUVOVF9JRAogICAgICAtIEdPT0dMRV9DTElFTlRfU0VDUkVUPSRHT09HTEVfQ0xJRU5UX1NFQ1JFVAogICAgICAtIERJU0FCTEVfUkVHSVNUUkFUSU9OPSRESVNBQkxFX1JFR0lTVFJBVElPTgogICAgICAtIEJBU0VfVVJMPSRCQVNFX1VSTAogICAgICAtIExPR19GQUlMRURfTE9HSU5fQVRURU1QVFM9JExPR19GQUlMRURfTE9HSU5fQVRURU1QVFMK"
|
"compose": "dmVyc2lvbjogJzMuMycKc2VydmljZXM6CiAgcGxhdXNpYmxlX2RiOgogICAgaW1hZ2U6ICdwb3N0Z3JlczoxNC1hbHBpbmUnCiAgICByZXN0YXJ0OiBhbHdheXMKICAgIHZvbHVtZXM6CiAgICAgIC0gJy9ldGMvZGF0YS9wbGF1c2libGUvZGItZGF0YTovdmFyL2xpYi9wb3N0Z3Jlc3FsL2RhdGEnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBQT1NUR1JFU19QQVNTV09SRD0kUE9TVEdSRVNfUEFTU1dPUkQKICBwbGF1c2libGVfZXZlbnRzX2RiOgogICAgaW1hZ2U6ICdjbGlja2hvdXNlL2NsaWNraG91c2Utc2VydmVyOjIzLjMuNy41LWFscGluZScKICAgIHJlc3RhcnQ6IGFsd2F5cwogICAgdm9sdW1lczoKICAgICAgLSAnL2V0Yy9kYXRhL3BsYXVzaWJsZS9ldmVudC1kYXRhOi92YXIvbGliL2NsaWNraG91c2UnCiAgICAgIC0gdHlwZTogYmluZAogICAgICAgIHNvdXJjZTogL2V0Yy9kYXRhL3BsYXVzaWJsZS9jbGlja2hvdXNlL2NsaWNraG91c2UtY29uZmlnLnhtbAogICAgICAgIHRhcmdldDogL2V0Yy9jbGlja2hvdXNlLXNlcnZlci9jb25maWcuZC9sb2dnaW5nLnhtbAogICAgICAgIHJlYWRfb25seTogdHJ1ZQogICAgICAgIGNvbnRlbnQ6ID4tCiAgICAgICAgICA8Y2xpY2tob3VzZT48cHJvZmlsZXM+PGRlZmF1bHQ+PGxvZ19xdWVyaWVzPjA8L2xvZ19xdWVyaWVzPjxsb2dfcXVlcnlfdGhyZWFkcz4wPC9sb2dfcXVlcnlfdGhyZWFkcz48L2RlZmF1bHQ+PC9wcm9maWxlcz48L2NsaWNraG91c2U+CiAgICAgIC0gdHlwZTogYmluZAogICAgICAgIHNvdXJjZTogL2V0Yy9kYXRhL3BsYXVzaWJsZS9jbGlja2hvdXNlL2NsaWNraG91c2UtdXNlci1jb25maWcueG1sCiAgICAgICAgdGFyZ2V0OiAvZXRjL2NsaWNraG91c2Utc2VydmVyL3VzZXJzLmQvbG9nZ2luZy54bWwKICAgICAgICByZWFkX29ubHk6IHRydWUKICAgICAgICBjb250ZW50OiA+LQogICAgICAgICAgPGNsaWNraG91c2U+PGxvZ2dlcj48bGV2ZWw+d2FybmluZzwvbGV2ZWw+PGNvbnNvbGU+dHJ1ZTwvY29uc29sZT48L2xvZ2dlcj48cXVlcnlfdGhyZWFkX2xvZwogICAgICAgICAgcmVtb3ZlPSJyZW1vdmUiLz48cXVlcnlfbG9nIHJlbW92ZT0icmVtb3ZlIi8+PHRleHRfbG9nCiAgICAgICAgICByZW1vdmU9InJlbW92ZSIvPjx0cmFjZV9sb2cgcmVtb3ZlPSJyZW1vdmUiLz48bWV0cmljX2xvZwogICAgICAgICAgcmVtb3ZlPSJyZW1vdmUiLz48YXN5bmNocm9ub3VzX21ldHJpY19sb2cKICAgICAgICAgIHJlbW92ZT0icmVtb3ZlIi8+PHNlc3Npb25fbG9nIHJlbW92ZT0icmVtb3ZlIi8+PHBhcnRfbG9nCiAgICAgICAgICByZW1vdmU9InJlbW92ZSIvPjwvY2xpY2tob3VzZT4KICAgIHVsaW1pdHM6CiAgICAgICAgbm9maWxlOgogICAgICAgICAgc29mdDogMjYyMTQ0CiAgICAgICAgICBoYXJkOiAyNjIxNDQKICBwbGF1c2libGU6CiAgICBpbWFnZTogJ3BsYXVzaWJsZS9hbmFseXRpY3M6djIuMCcKICAgIHJlc3RhcnQ6IGFsd2F5cwogICAgY29tbWFuZDogJ3NoIC1jICJzbGVlcCAxMCAmJiAvZW50cnlwb2ludC5zaCBkYiBjcmVhdGVkYiAmJiAvZW50cnlwb2ludC5zaCBkYiBtaWdyYXRlICYmIC9lbnRyeXBvaW50LnNoIHJ1biInCiAgICBkZXBlbmRzX29uOgogICAgICAtIHBsYXVzaWJsZV9kYgogICAgICAtIHBsYXVzaWJsZV9ldmVudHNfZGIKICAgIHBvcnRzOgogICAgICAtICc4MDAwOjgwMDAnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTRUNSRVRfS0VZX0JBU0U9JFNFQ1JFVF9LRVlfQkFTRQogICAgICAtIERBVEFCQVNFX1VSTD0kREFUQUJBU0VfVVJMCiAgICAgIC0gJ0NMSUNLSE9VU0VfREFUQUJBU0VfVVJMPWh0dHA6Ly9wbGF1c2libGVfZXZlbnRzX2RiOjgxMjMvcGxhdXNpYmxlX2V2ZW50c19kYicKICAgICAgLSBNQUlMRVJfQURBUFRFUj0kTUFJTEVSX0FEQVBURVIKICAgICAgLSBTRU5ER1JJRF9BUElfS0VZPSRTRU5ER1JJRF9BUElfS0VZCiAgICAgIC0gR09PR0xFX0NMSUVOVF9JRD0kR09PR0xFX0NMSUVOVF9JRAogICAgICAtIEdPT0dMRV9DTElFTlRfU0VDUkVUPSRHT09HTEVfQ0xJRU5UX1NFQ1JFVAogICAgICAtIERJU0FCTEVfUkVHSVNUUkFUSU9OPSRESVNBQkxFX1JFR0lTVFJBVElPTgogICAgICAtIEJBU0VfVVJMPSRCQVNFX1VSTAogICAgICAtIExPR19GQUlMRURfTE9HSU5fQVRURU1QVFM9JExPR19GQUlMRURfTE9HSU5fQVRURU1QVFMK"
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"version": "3.12.36"
|
"version": "3.12.36"
|
||||||
},
|
},
|
||||||
"v4": {
|
"v4": {
|
||||||
"version": "4.0.0-beta.64"
|
"version": "4.0.0-beta.65"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user