From 0ef386b4a870ea244048ab47b76d620c2373007c Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Sat, 14 Oct 2023 14:22:07 +0200 Subject: [PATCH] fix: stopping a resource is now job based ui: show status on project --- app/Actions/Application/StopApplication.php | 30 ++++++ app/Actions/Database/StartDatabaseProxy.php | 93 +++++++++++++++++++ app/Actions/Database/StartPostgresql.php | 5 +- app/Actions/Database/StopDatabase.php | 27 ++++++ app/Actions/Database/StopDatabaseProxy.php | 19 ++++ app/Actions/Service/StopService.php | 3 + .../Livewire/Project/Application/Heading.php | 20 +--- .../Livewire/Project/Database/Heading.php | 14 +-- .../Project/Database/Postgresql/General.php | 6 +- .../Project/Database/Redis/General.php | 6 +- app/Http/Livewire/Project/Shared/Danger.php | 20 +--- app/Jobs/StopResourceJob.php | 54 +++++++++++ app/Models/Application.php | 10 +- app/Models/Service.php | 2 - app/Models/StandalonePostgresql.php | 14 +-- app/Models/StandaloneRedis.php | 16 +--- .../Application/StatusChanged.php | 32 +++---- bootstrap/helpers/proxy.php | 86 ----------------- config/sentry.php | 2 +- config/version.php | 2 +- resources/views/project/resources.blade.php | 32 +++++-- versions.json | 2 +- 22 files changed, 300 insertions(+), 195 deletions(-) create mode 100644 app/Actions/Application/StopApplication.php create mode 100644 app/Actions/Database/StartDatabaseProxy.php create mode 100644 app/Actions/Database/StopDatabase.php create mode 100644 app/Actions/Database/StopDatabaseProxy.php create mode 100644 app/Jobs/StopResourceJob.php diff --git a/app/Actions/Application/StopApplication.php b/app/Actions/Application/StopApplication.php new file mode 100644 index 000000000..8ecebeda3 --- /dev/null +++ b/app/Actions/Application/StopApplication.php @@ -0,0 +1,30 @@ +destination->server; + $containers = getCurrentApplicationContainerStatus($server, $application->id); + if ($containers->count() > 0) { + foreach ($containers as $container) { + $containerName = data_get($container, 'Names'); + if ($containerName) { + instant_remote_process( + ["docker rm -f {$containerName}"], + $server + ); + } + } + // TODO: make notification for application + // $application->environment->project->team->notify(new StatusChanged($application)); + } + } +} diff --git a/app/Actions/Database/StartDatabaseProxy.php b/app/Actions/Database/StartDatabaseProxy.php new file mode 100644 index 000000000..922099b4c --- /dev/null +++ b/app/Actions/Database/StartDatabaseProxy.php @@ -0,0 +1,93 @@ +getMorphClass()=== 'App\Models\StandaloneRedis') { + $internalPort = 6379; + } else if ($database->getMorphClass()=== 'App\Models\StandalonePostgresql') { + $internalPort = 5432; + } + $containerName = "{$database->uuid}-proxy"; + $configuration_dir = database_proxy_dir($database->uuid); + $nginxconf = <<public_port; + proxy_pass $database->uuid:$internalPort; + } + } + EOF; + $dockerfile = <<< EOF + FROM nginx:stable-alpine + + COPY nginx.conf /etc/nginx/nginx.conf + EOF; + $docker_compose = [ + 'version' => '3.8', + 'services' => [ + $containerName => [ + 'build' => [ + 'context' => $configuration_dir, + 'dockerfile' => 'Dockerfile', + ], + 'image' => "nginx:stable-alpine", + 'container_name' => $containerName, + 'restart' => RESTART_MODE, + 'ports' => [ + "$database->public_port:$database->public_port", + ], + 'networks' => [ + $database->destination->network, + ], + 'healthcheck' => [ + 'test' => [ + 'CMD-SHELL', + 'stat /etc/nginx/nginx.conf || exit 1', + ], + 'interval' => '5s', + 'timeout' => '5s', + 'retries' => 3, + 'start_period' => '1s' + ], + ] + ], + 'networks' => [ + $database->destination->network => [ + 'external' => true, + 'name' => $database->destination->network, + 'attachable' => true, + ] + ] + ]; + $dockercompose_base64 = base64_encode(Yaml::dump($docker_compose, 4, 2)); + $nginxconf_base64 = base64_encode($nginxconf); + $dockerfile_base64 = base64_encode($dockerfile); + instant_remote_process([ + "mkdir -p $configuration_dir", + "echo '{$dockerfile_base64}' | base64 -d > $configuration_dir/Dockerfile", + "echo '{$nginxconf_base64}' | base64 -d > $configuration_dir/nginx.conf", + "echo '{$dockercompose_base64}' | base64 -d > $configuration_dir/docker-compose.yaml", + "docker compose --project-directory {$configuration_dir} up --build -d >/dev/null", + ], $database->destination->server); + } +} diff --git a/app/Actions/Database/StartPostgresql.php b/app/Actions/Database/StartPostgresql.php index 506b2d5a4..50d8b8541 100644 --- a/app/Actions/Database/StartPostgresql.php +++ b/app/Actions/Database/StartPostgresql.php @@ -6,15 +6,18 @@ use App\Models\Server; use App\Models\StandalonePostgresql; use Illuminate\Support\Str; use Symfony\Component\Yaml\Yaml; +use Lorisleiva\Actions\Concerns\AsAction; class StartPostgresql { + use AsAction; + public StandalonePostgresql $database; public array $commands = []; public array $init_scripts = []; public string $configuration_dir; - public function __invoke(Server $server, StandalonePostgresql $database) + public function handle(Server $server, StandalonePostgresql $database) { $this->database = $database; $container_name = $this->database->uuid; diff --git a/app/Actions/Database/StopDatabase.php b/app/Actions/Database/StopDatabase.php new file mode 100644 index 000000000..ee1913f06 --- /dev/null +++ b/app/Actions/Database/StopDatabase.php @@ -0,0 +1,27 @@ +destination->server; + instant_remote_process( + ["docker rm -f {$database->uuid}"], + $server + ); + if ($database->is_public) { + StopDatabaseProxy::run($database); + } + // TODO: make notification for services + // $database->environment->project->team->notify(new StatusChanged($database)); + } +} diff --git a/app/Actions/Database/StopDatabaseProxy.php b/app/Actions/Database/StopDatabaseProxy.php new file mode 100644 index 000000000..ba836ec3a --- /dev/null +++ b/app/Actions/Database/StopDatabaseProxy.php @@ -0,0 +1,19 @@ +uuid}-proxy"], $database->destination->server); + $database->is_public = false; + $database->save(); + } +} diff --git a/app/Actions/Service/StopService.php b/app/Actions/Service/StopService.php index 82128f47d..b2516eefb 100644 --- a/app/Actions/Service/StopService.php +++ b/app/Actions/Service/StopService.php @@ -4,6 +4,7 @@ namespace App\Actions\Service; use Lorisleiva\Actions\Concerns\AsAction; use App\Models\Service; +use App\Notifications\Application\StatusChanged; class StopService { @@ -22,5 +23,7 @@ class StopService } instant_remote_process(["docker network disconnect {$service->uuid} coolify-proxy 2>/dev/null"], $service->server, false); instant_remote_process(["docker network rm {$service->uuid} 2>/dev/null"], $service->server, false); + // TODO: make notification for databases + // $service->environment->project->team->notify(new StatusChanged($service)); } } diff --git a/app/Http/Livewire/Project/Application/Heading.php b/app/Http/Livewire/Project/Application/Heading.php index bf4c96cdd..0cb25b172 100644 --- a/app/Http/Livewire/Project/Application/Heading.php +++ b/app/Http/Livewire/Project/Application/Heading.php @@ -2,6 +2,7 @@ namespace App\Http\Livewire\Project\Application; +use App\Actions\Application\StopApplication; use App\Jobs\ContainerStatusJob; use App\Models\Application; use Livewire\Component; @@ -59,22 +60,9 @@ class Heading extends Component public function stop() { - $containers = getCurrentApplicationContainerStatus($this->application->destination->server, $this->application->id); - if ($containers->count() === 0) { - return; - } - foreach ($containers as $container) { - $containerName = data_get($container, 'Names'); - if ($containerName) { - instant_remote_process( - ["docker rm -f {$containerName}"], - $this->application->destination->server - ); - $this->application->status = 'exited'; - $this->application->save(); - // $this->application->environment->project->team->notify(new StatusChanged($this->application)); - } - } + StopApplication::run($this->application); + $this->application->status = 'exited'; + $this->application->save(); $this->application->refresh(); } } diff --git a/app/Http/Livewire/Project/Database/Heading.php b/app/Http/Livewire/Project/Database/Heading.php index 2c739f087..7b2796c85 100644 --- a/app/Http/Livewire/Project/Database/Heading.php +++ b/app/Http/Livewire/Project/Database/Heading.php @@ -4,7 +4,9 @@ namespace App\Http\Livewire\Project\Database; use App\Actions\Database\StartPostgresql; use App\Actions\Database\StartRedis; +use App\Actions\Database\StopDatabase; use App\Jobs\ContainerStatusJob; +use App\Notifications\Application\StatusChanged; use Livewire\Component; class Heading extends Component @@ -37,24 +39,16 @@ class Heading extends Component public function stop() { - instant_remote_process( - ["docker rm -f {$this->database->uuid}"], - $this->database->destination->server - ); - if ($this->database->is_public) { - stopDatabaseProxy($this->database); - $this->database->is_public = false; - } + StopDatabase::run($this->database); $this->database->status = 'exited'; $this->database->save(); $this->check_status(); - // $this->database->environment->project->team->notify(new StatusChanged($this->database)); } public function start() { if ($this->database->type() === 'standalone-postgresql') { - $activity = resolve(StartPostgresql::class)($this->database->destination->server, $this->database); + $activity = StartPostgresql::run($this->database->destination->server, $this->database); $this->emit('newMonitorActivity', $activity->id); } if ($this->database->type() === 'standalone-redis') { diff --git a/app/Http/Livewire/Project/Database/Postgresql/General.php b/app/Http/Livewire/Project/Database/Postgresql/General.php index bbd1de0ff..8c2867e7f 100644 --- a/app/Http/Livewire/Project/Database/Postgresql/General.php +++ b/app/Http/Livewire/Project/Database/Postgresql/General.php @@ -2,6 +2,8 @@ namespace App\Http\Livewire\Project\Database\Postgresql; +use App\Actions\Database\StartDatabaseProxy; +use App\Actions\Database\StopDatabaseProxy; use App\Models\StandalonePostgresql; use Exception; use Livewire\Component; @@ -67,10 +69,10 @@ class General extends Component } if ($this->database->is_public) { $this->emit('success', 'Starting TCP proxy...'); - startDatabaseProxy($this->database); + StartDatabaseProxy::run($this->database); $this->emit('success', 'Database is now publicly accessible.'); } else { - stopDatabaseProxy($this->database); + StopDatabaseProxy::run($this->database); $this->emit('success', 'Database is no longer publicly accessible.'); } $this->getDbUrl(); diff --git a/app/Http/Livewire/Project/Database/Redis/General.php b/app/Http/Livewire/Project/Database/Redis/General.php index c8e15062a..6979a739a 100644 --- a/app/Http/Livewire/Project/Database/Redis/General.php +++ b/app/Http/Livewire/Project/Database/Redis/General.php @@ -2,6 +2,8 @@ namespace App\Http\Livewire\Project\Database\Redis; +use App\Actions\Database\StartDatabaseProxy; +use App\Actions\Database\StopDatabaseProxy; use App\Models\StandaloneRedis; use Exception; use Livewire\Component; @@ -55,10 +57,10 @@ class General extends Component } if ($this->database->is_public) { $this->emit('success', 'Starting TCP proxy...'); - startDatabaseProxy($this->database); + StartDatabaseProxy::run($this->database); $this->emit('success', 'Database is now publicly accessible.'); } else { - stopDatabaseProxy($this->database); + StopDatabaseProxy::run($this->database); $this->emit('success', 'Database is no longer publicly accessible.'); } $this->getDbUrl(); diff --git a/app/Http/Livewire/Project/Shared/Danger.php b/app/Http/Livewire/Project/Shared/Danger.php index 7b6dcab3b..45bc5d2d7 100644 --- a/app/Http/Livewire/Project/Shared/Danger.php +++ b/app/Http/Livewire/Project/Shared/Danger.php @@ -2,7 +2,7 @@ namespace App\Http\Livewire\Project\Shared; -use App\Actions\Service\StopService; +use App\Jobs\StopResourceJob; use Livewire\Component; use Visus\Cuid2\Cuid2; @@ -10,7 +10,7 @@ class Danger extends Component { public $resource; public array $parameters; - public string|null $modalId = null; + public ?string $modalId = null; public function mount() { @@ -20,22 +20,8 @@ class Danger extends Component public function delete() { - // Should be queued try { - if ($this->resource->type() === 'service') { - $server = $this->resource->server; - StopService::run($this->resource); - } else { - $destination = data_get($this->resource, 'destination'); - if ($destination) { - $destination = $this->resource->destination->getMorphClass()::where('id', $this->resource->destination->id)->first(); - $server = $destination->server; - } - if ($this->resource->destination->server->isFunctional()) { - instant_remote_process(["docker rm -f {$this->resource->uuid}"], $server); - } - } - $this->resource->delete(); + StopResourceJob::dispatchSync($this->resource); return redirect()->route('project.resources', [ 'project_uuid' => $this->parameters['project_uuid'], 'environment_name' => $this->parameters['environment_name'] diff --git a/app/Jobs/StopResourceJob.php b/app/Jobs/StopResourceJob.php new file mode 100644 index 000000000..a702d83f3 --- /dev/null +++ b/app/Jobs/StopResourceJob.php @@ -0,0 +1,54 @@ +resource->destination->server; + if (!$server->isFunctional()) { + return 'Server is not functional'; + } + switch ($this->resource->type()) { + case 'application': + StopApplication::run($this->resource); + break; + case 'standalone-postgresql': + StopDatabase::run($this->resource); + break; + case 'standalone-redis': + StopDatabase::run($this->resource); + break; + case 'service': + StopService::run($this->resource); + break; + } + $this->resource->delete(); + } catch (\Throwable $e) { + send_internal_notification('ContainerStoppingJob failed with: ' . $e->getMessage()); + throw $e; + } + } +} diff --git a/app/Models/Application.php b/app/Models/Application.php index 634569c0f..e5bf9db07 100644 --- a/app/Models/Application.php +++ b/app/Models/Application.php @@ -32,16 +32,8 @@ class Application extends BaseModel ]); }); static::deleting(function ($application) { - // Stop Container - if ($application->destination->server->isFunctional()) { - instant_remote_process( - ["docker rm -f {$application->uuid}"], - $application->destination->server, - false - ); - } $application->settings()->delete(); - $storages = $application->persistentStorages()->get(); + $storages = $application->persistentStorages()->get(); foreach ($storages as $storage) { instant_remote_process(["docker volume rm -f $storage->name"], $application->destination->server, false); } diff --git a/app/Models/Service.php b/app/Models/Service.php index 4b547d0e6..a8a9570f8 100644 --- a/app/Models/Service.php +++ b/app/Models/Service.php @@ -19,7 +19,6 @@ class Service extends BaseModel static::deleting(function ($service) { $storagesToDelete = collect([]); foreach ($service->applications()->get() as $application) { - instant_remote_process(["docker rm -f {$application->name}-{$service->uuid}"], $service->server, false); $storages = $application->persistentStorages()->get(); foreach ($storages as $storage) { $storagesToDelete->push($storage); @@ -27,7 +26,6 @@ class Service extends BaseModel $application->persistentStorages()->delete(); } foreach ($service->databases()->get() as $database) { - instant_remote_process(["docker rm -f {$database->name}-{$service->uuid}"], $service->server, false); $storages = $database->persistentStorages()->get(); foreach ($storages as $storage) { $storagesToDelete->push($storage); diff --git a/app/Models/StandalonePostgresql.php b/app/Models/StandalonePostgresql.php index d177e9ab9..41a10cfd9 100644 --- a/app/Models/StandalonePostgresql.php +++ b/app/Models/StandalonePostgresql.php @@ -29,21 +29,13 @@ class StandalonePostgresql extends BaseModel ]); }); static::deleting(function ($database) { - // Stop Container - instant_remote_process( - ["docker rm -f {$database->uuid}"], - $database->destination->server, - false - ); - // Stop TCP Proxy - if ($database->is_public) { - instant_remote_process(["docker rm -f {$database->uuid}-proxy"], $database->destination->server, false); + $storages = $database->persistentStorages()->get(); + foreach ($storages as $storage) { + instant_remote_process(["docker volume rm -f $storage->name"], $database->destination->server, false); } $database->scheduledBackups()->delete(); $database->persistentStorages()->delete(); $database->environment_variables()->delete(); - // Remove Volume - instant_remote_process(['docker volume rm postgres-data-' . $database->uuid], $database->destination->server, false); }); } diff --git a/app/Models/StandaloneRedis.php b/app/Models/StandaloneRedis.php index f48dc7bb6..6517c2ef7 100644 --- a/app/Models/StandaloneRedis.php +++ b/app/Models/StandaloneRedis.php @@ -24,21 +24,13 @@ class StandaloneRedis extends BaseModel ]); }); static::deleting(function ($database) { - // Stop Container - instant_remote_process( - ["docker rm -f {$database->uuid}"], - $database->destination->server, - false - ); - // Stop TCP Proxy - if ($database->is_public) { - instant_remote_process(["docker rm -f {$database->uuid}-proxy"], $database->destination->server, false); - } $database->scheduledBackups()->delete(); + $storages = $database->persistentStorages()->get(); + foreach ($storages as $storage) { + instant_remote_process(["docker volume rm -f $storage->name"], $database->destination->server, false); + } $database->persistentStorages()->delete(); $database->environment_variables()->delete(); - // Remove Volume - instant_remote_process(['docker volume rm postgres-data-' . $database->uuid], $database->destination->server, false); }); } diff --git a/app/Notifications/Application/StatusChanged.php b/app/Notifications/Application/StatusChanged.php index df12f2b0a..17481e37b 100644 --- a/app/Notifications/Application/StatusChanged.php +++ b/app/Notifications/Application/StatusChanged.php @@ -15,25 +15,23 @@ class StatusChanged extends Notification implements ShouldQueue public $tries = 1; - public Application $application; - public string $application_name; + public string $resource_name; public string $project_uuid; public string $environment_name; - public ?string $application_url = null; + public ?string $resource_url = null; public ?string $fqdn; - public function __construct($application) + public function __construct(public Application $resource) { - $this->application = $application; - $this->application_name = data_get($application, 'name'); - $this->project_uuid = data_get($application, 'environment.project.uuid'); - $this->environment_name = data_get($application, 'environment.name'); - $this->fqdn = data_get($application, 'fqdn', null); + $this->resource_name = data_get($resource, 'name'); + $this->project_uuid = data_get($resource, 'environment.project.uuid'); + $this->environment_name = data_get($resource, 'environment.name'); + $this->fqdn = data_get($resource, 'fqdn', null); if (Str::of($this->fqdn)->explode(',')->count() > 1) { $this->fqdn = Str::of($this->fqdn)->explode(',')->first(); } - $this->application_url = base_url() . "/project/{$this->project_uuid}/{$this->environment_name}/application/{$this->application->uuid}"; + $this->resource_url = base_url() . "/project/{$this->project_uuid}/{$this->environment_name}/application/{$this->resource->uuid}"; } public function via(object $notifiable): array @@ -45,32 +43,32 @@ class StatusChanged extends Notification implements ShouldQueue { $mail = new MailMessage(); $fqdn = $this->fqdn; - $mail->subject("Coolify: {$this->application_name} has been stopped"); + $mail->subject("Coolify: {$this->resource_name} has been stopped"); $mail->view('emails.application-status-changes', [ - 'name' => $this->application_name, + 'name' => $this->resource_name, 'fqdn' => $fqdn, - 'application_url' => $this->application_url, + 'resource_url' => $this->resource_url, ]); return $mail; } public function toDiscord(): string { - $message = 'Coolify: ' . $this->application_name . ' has been stopped. + $message = 'Coolify: ' . $this->resource_name . ' has been stopped. '; - $message .= '[Open Application in Coolify](' . $this->application_url . ')'; + $message .= '[Open Application in Coolify](' . $this->resource_url . ')'; return $message; } public function toTelegram(): array { - $message = 'Coolify: ' . $this->application_name . ' has been stopped.'; + $message = 'Coolify: ' . $this->resource_name . ' has been stopped.'; return [ "message" => $message, "buttons" => [ [ "text" => "Open Application in Coolify", - "url" => $this->application_url + "url" => $this->resource_url ] ], ]; diff --git a/bootstrap/helpers/proxy.php b/bootstrap/helpers/proxy.php index 08f134d15..ee9c624f5 100644 --- a/bootstrap/helpers/proxy.php +++ b/bootstrap/helpers/proxy.php @@ -2,8 +2,6 @@ use App\Actions\Proxy\SaveConfiguration; use App\Models\Server; -use App\Models\StandalonePostgresql; -use App\Models\StandaloneRedis; use Symfony\Component\Yaml\Yaml; function get_proxy_path() @@ -187,87 +185,3 @@ function setup_default_redirect_404(string|null $redirect_url, Server $server) } } } - -function startDatabaseProxy(StandalonePostgresql|StandaloneRedis $database) -{ - $internalPort = null; - if ($database->getMorphClass()=== 'App\Models\StandaloneRedis') { - $internalPort = 6379; - } else if ($database->getMorphClass()=== 'App\Models\StandalonePostgresql') { - $internalPort = 5432; - } - $containerName = "{$database->uuid}-proxy"; - $configuration_dir = database_proxy_dir($database->uuid); - $nginxconf = <<public_port; - proxy_pass $database->uuid:$internalPort; - } -} -EOF; - $dockerfile = <<< EOF -FROM nginx:stable-alpine - -COPY nginx.conf /etc/nginx/nginx.conf -EOF; - $docker_compose = [ - 'version' => '3.8', - 'services' => [ - $containerName => [ - 'build' => [ - 'context' => $configuration_dir, - 'dockerfile' => 'Dockerfile', - ], - 'image' => "nginx:stable-alpine", - 'container_name' => $containerName, - 'restart' => RESTART_MODE, - 'ports' => [ - "$database->public_port:$database->public_port", - ], - 'networks' => [ - $database->destination->network, - ], - 'healthcheck' => [ - 'test' => [ - 'CMD-SHELL', - 'stat /etc/nginx/nginx.conf || exit 1', - ], - 'interval' => '5s', - 'timeout' => '5s', - 'retries' => 3, - 'start_period' => '1s' - ], - ] - ], - 'networks' => [ - $database->destination->network => [ - 'external' => true, - 'name' => $database->destination->network, - 'attachable' => true, - ] - ] - ]; - $dockercompose_base64 = base64_encode(Yaml::dump($docker_compose, 4, 2)); - $nginxconf_base64 = base64_encode($nginxconf); - $dockerfile_base64 = base64_encode($dockerfile); - instant_remote_process([ - "mkdir -p $configuration_dir", - "echo '{$dockerfile_base64}' | base64 -d > $configuration_dir/Dockerfile", - "echo '{$nginxconf_base64}' | base64 -d > $configuration_dir/nginx.conf", - "echo '{$dockercompose_base64}' | base64 -d > $configuration_dir/docker-compose.yaml", - "docker compose --project-directory {$configuration_dir} up --build -d >/dev/null", - ], $database->destination->server); -} -function stopDatabaseProxy(StandalonePostgresql|StandaloneRedis $database) -{ - instant_remote_process(["docker rm -f {$database->uuid}-proxy"], $database->destination->server); -} diff --git a/config/sentry.php b/config/sentry.php index 3e1d76d3f..83b5e5e5f 100644 --- a/config/sentry.php +++ b/config/sentry.php @@ -7,7 +7,7 @@ return [ // The release version of your application // Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD')) - 'release' => '4.0.0-beta.83', + 'release' => '4.0.0-beta.84', // When left empty or `null` the Laravel environment will be used 'environment' => config('app.env'), diff --git a/config/version.php b/config/version.php index ce833230d..e9a5cd388 100644 --- a/config/version.php +++ b/config/version.php @@ -1,3 +1,3 @@ @foreach ($environment->applications->sortBy('name') as $application) -
{{ $application->name }}
{{ $application->description }}
+
+ @if (Str::of(data_get($application, 'status'))->startsWith('running')) +
+ @elseif (Str::of(data_get($application, 'status'))->startsWith('exited')) +
+ @endif
@endforeach - @foreach ($environment->databases()->sortBy('name') as $databases) - + @foreach ($environment->databases()->sortBy('name') as $database) +
-
{{ $databases->name }}
-
{{ $databases->description }}
+
{{ $database->name }}
+
{{ $database->description }}
+ @if (Str::of(data_get($database, 'status'))->startsWith('running')) +
+ @elseif (Str::of(data_get($database, 'status'))->startsWith('exited')) +
+ @endif
@endforeach @foreach ($environment->services->sortBy('name') as $service) -
{{ $service->name }}
{{ $service->description }}
+ @if (Str::of(serviceStatus($service))->startsWith('running')) +
+ @elseif (Str::of(serviceStatus($service))->startsWith('degraded')) +
+ @elseif (Str::of(serviceStatus($service))->startsWith('exited')) +
+ @endif
@endforeach diff --git a/versions.json b/versions.json index 986f9ba55..0811b005b 100644 --- a/versions.json +++ b/versions.json @@ -4,7 +4,7 @@ "version": "3.12.36" }, "v4": { - "version": "4.0.0-beta.83" + "version": "4.0.0-beta.84" } } }