Merge branch 'next' into patch-1
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
namespace App\Actions\Application;
|
||||
|
||||
use App\Actions\Server\CleanupDocker;
|
||||
use App\Events\ServiceStatusChanged;
|
||||
use App\Models\Application;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
|
||||
@@ -14,6 +15,7 @@ class StopApplication
|
||||
|
||||
public function handle(Application $application, bool $previewDeployments = false, bool $dockerCleanup = true)
|
||||
{
|
||||
ray('StopApplication');
|
||||
try {
|
||||
$server = $application->destination->server;
|
||||
if (! $server->isFunctional()) {
|
||||
@@ -38,6 +40,8 @@ class StopApplication
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return $e->getMessage();
|
||||
} finally {
|
||||
ServiceStatusChanged::dispatch($application->environment->project->team->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace App\Actions\Database;
|
||||
|
||||
use App\Actions\Server\CleanupDocker;
|
||||
use App\Events\ServiceStatusChanged;
|
||||
use App\Models\StandaloneClickhouse;
|
||||
use App\Models\StandaloneDragonfly;
|
||||
use App\Models\StandaloneKeydb;
|
||||
@@ -19,23 +20,30 @@ class StopDatabase
|
||||
|
||||
public function handle(StandaloneRedis|StandalonePostgresql|StandaloneMongodb|StandaloneMysql|StandaloneMariadb|StandaloneKeydb|StandaloneDragonfly|StandaloneClickhouse $database, bool $isDeleteOperation = false, bool $dockerCleanup = true)
|
||||
{
|
||||
$server = $database->destination->server;
|
||||
if (! $server->isFunctional()) {
|
||||
return 'Server is not functional';
|
||||
}
|
||||
|
||||
$this->stopContainer($database, $database->uuid, 30);
|
||||
if ($isDeleteOperation) {
|
||||
if ($dockerCleanup) {
|
||||
CleanupDocker::dispatch($server, true);
|
||||
try {
|
||||
$server = $database->destination->server;
|
||||
if (! $server->isFunctional()) {
|
||||
return 'Server is not functional';
|
||||
}
|
||||
|
||||
$this->stopContainer($database, $database->uuid, 30);
|
||||
if ($isDeleteOperation) {
|
||||
if ($dockerCleanup) {
|
||||
CleanupDocker::dispatch($server, true);
|
||||
}
|
||||
}
|
||||
|
||||
if ($database->is_public) {
|
||||
StopDatabaseProxy::run($database);
|
||||
}
|
||||
|
||||
return 'Database stopped successfully';
|
||||
} catch (\Exception $e) {
|
||||
return 'Database stop failed: '.$e->getMessage();
|
||||
} finally {
|
||||
ServiceStatusChanged::dispatch($database->environment->project->team->id);
|
||||
}
|
||||
|
||||
if ($database->is_public) {
|
||||
StopDatabaseProxy::run($database);
|
||||
}
|
||||
|
||||
return 'Database stopped successfully';
|
||||
}
|
||||
|
||||
private function stopContainer($database, string $containerName, int $timeout = 30): void
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace App\Actions\Docker;
|
||||
|
||||
use App\Actions\Database\StartDatabaseProxy;
|
||||
use App\Actions\Shared\ComplexStatusCheck;
|
||||
use App\Events\ServiceChecked;
|
||||
use App\Models\ApplicationPreview;
|
||||
use App\Models\Server;
|
||||
use App\Models\ServiceDatabase;
|
||||
@@ -341,5 +342,6 @@ class GetContainersStatus
|
||||
}
|
||||
// $this->server->team?->notify(new ContainerStopped($containerName, $this->server, $url));
|
||||
}
|
||||
ServiceChecked::dispatch($this->server->team->id);
|
||||
}
|
||||
}
|
||||
|
||||
227
app/Actions/Server/CheckUpdates.php
Normal file
227
app/Actions/Server/CheckUpdates.php
Normal file
@@ -0,0 +1,227 @@
|
||||
<?php
|
||||
|
||||
namespace App\Actions\Server;
|
||||
|
||||
use App\Models\Server;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
|
||||
class CheckUpdates
|
||||
{
|
||||
use AsAction;
|
||||
|
||||
public string $jobQueue = 'high';
|
||||
|
||||
public function handle(Server $server)
|
||||
{
|
||||
try {
|
||||
if ($server->serverStatus() === false) {
|
||||
return [
|
||||
'error' => 'Server is not reachable or not ready.',
|
||||
];
|
||||
}
|
||||
|
||||
// Try first method - using instant_remote_process
|
||||
$output = instant_remote_process(['cat /etc/os-release'], $server);
|
||||
|
||||
// Parse os-release into an associative array
|
||||
$osInfo = [];
|
||||
foreach (explode("\n", $output) as $line) {
|
||||
if (empty($line)) {
|
||||
continue;
|
||||
}
|
||||
if (strpos($line, '=') === false) {
|
||||
continue;
|
||||
}
|
||||
[$key, $value] = explode('=', $line, 2);
|
||||
$osInfo[$key] = trim($value, '"');
|
||||
}
|
||||
|
||||
// Get the main OS identifier
|
||||
$osId = $osInfo['ID'] ?? '';
|
||||
// $osIdLike = $osInfo['ID_LIKE'] ?? '';
|
||||
// $versionId = $osInfo['VERSION_ID'] ?? '';
|
||||
|
||||
// Normalize OS types based on install.sh logic
|
||||
switch ($osId) {
|
||||
case 'manjaro':
|
||||
case 'manjaro-arm':
|
||||
case 'endeavouros':
|
||||
$osType = 'arch';
|
||||
break;
|
||||
case 'pop':
|
||||
case 'linuxmint':
|
||||
case 'zorin':
|
||||
$osType = 'ubuntu';
|
||||
break;
|
||||
case 'fedora-asahi-remix':
|
||||
$osType = 'fedora';
|
||||
break;
|
||||
default:
|
||||
$osType = $osId;
|
||||
}
|
||||
|
||||
// Determine package manager based on OS type
|
||||
$packageManager = match ($osType) {
|
||||
'arch' => 'pacman',
|
||||
'alpine' => 'apk',
|
||||
'ubuntu', 'debian', 'raspbian' => 'apt',
|
||||
'centos', 'fedora', 'rhel', 'ol', 'rocky', 'almalinux', 'amzn' => 'dnf',
|
||||
'sles', 'opensuse-leap', 'opensuse-tumbleweed' => 'zypper',
|
||||
default => null
|
||||
};
|
||||
|
||||
switch ($packageManager) {
|
||||
case 'zypper':
|
||||
$output = instant_remote_process(['LANG=C zypper -tx list-updates'], $server);
|
||||
$out = $this->parseZypperOutput($output);
|
||||
$out['osId'] = $osId;
|
||||
$out['package_manager'] = $packageManager;
|
||||
|
||||
return $out;
|
||||
case 'dnf':
|
||||
$output = instant_remote_process(['LANG=C dnf list -q --updates --refresh'], $server);
|
||||
$out = $this->parseDnfOutput($output);
|
||||
$out['osId'] = $osId;
|
||||
$out['package_manager'] = $packageManager;
|
||||
$rebootRequired = instant_remote_process(['LANG=C dnf needs-restarting -r'], $server);
|
||||
$out['reboot_required'] = $rebootRequired !== '0';
|
||||
|
||||
return $out;
|
||||
case 'apt':
|
||||
instant_remote_process(['apt-get update -qq'], $server);
|
||||
$output = instant_remote_process(['LANG=C apt list --upgradable 2>/dev/null'], $server);
|
||||
|
||||
$out = $this->parseAptOutput($output);
|
||||
$out['osId'] = $osId;
|
||||
$out['package_manager'] = $packageManager;
|
||||
$rebootRequired = instant_remote_process(['LANG=C test -f /var/run/reboot-required && echo "YES" || echo "NO"'], $server);
|
||||
$out['reboot_required'] = $rebootRequired === 'YES' ? true : false;
|
||||
|
||||
return $out;
|
||||
default:
|
||||
return [
|
||||
'osId' => $osId,
|
||||
'error' => 'Unsupported package manager',
|
||||
'package_manager' => $packageManager,
|
||||
];
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
ray('Error:', $e->getMessage());
|
||||
|
||||
return [
|
||||
'osId' => $osId,
|
||||
'package_manager' => $packageManager,
|
||||
'error' => $e->getMessage(),
|
||||
'trace' => $e->getTraceAsString(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
private function parseZypperOutput(string $output): array
|
||||
{
|
||||
$updates = [];
|
||||
|
||||
try {
|
||||
$xml = simplexml_load_string($output);
|
||||
if ($xml === false) {
|
||||
return [
|
||||
'total_updates' => 0,
|
||||
'updates' => [],
|
||||
'error' => 'Failed to parse XML output',
|
||||
];
|
||||
}
|
||||
|
||||
// Navigate to the update-list node
|
||||
$updateList = $xml->xpath('//update-list/update');
|
||||
|
||||
foreach ($updateList as $update) {
|
||||
$updates[] = [
|
||||
'package' => (string) $update['name'],
|
||||
'new_version' => (string) $update['edition'],
|
||||
'current_version' => (string) $update['edition-old'],
|
||||
'architecture' => (string) $update['arch'],
|
||||
'repository' => (string) $update->source['alias'],
|
||||
'summary' => (string) $update->summary,
|
||||
'description' => (string) $update->description,
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'total_updates' => count($updates),
|
||||
'updates' => $updates,
|
||||
];
|
||||
} catch (\Throwable $e) {
|
||||
return [
|
||||
'total_updates' => 0,
|
||||
'updates' => [],
|
||||
'error' => 'Error parsing zypper output: '.$e->getMessage(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
private function parseDnfOutput(string $output): array
|
||||
{
|
||||
$updates = [];
|
||||
$lines = explode("\n", $output);
|
||||
|
||||
foreach ($lines as $line) {
|
||||
if (empty($line)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Split by multiple spaces/tabs and filter out empty elements
|
||||
$parts = array_values(array_filter(preg_split('/\s+/', $line)));
|
||||
|
||||
if (count($parts) >= 3) {
|
||||
$package = $parts[0];
|
||||
$new_version = $parts[1];
|
||||
$repository = $parts[2];
|
||||
|
||||
// Extract architecture from package name (e.g., "cloud-init.noarch" -> "noarch")
|
||||
$architecture = str_contains($package, '.') ? explode('.', $package)[1] : 'noarch';
|
||||
|
||||
$updates[] = [
|
||||
'package' => $package,
|
||||
'new_version' => $new_version,
|
||||
'repository' => $repository,
|
||||
'architecture' => $architecture,
|
||||
'current_version' => 'unknown', // DNF doesn't show current version in check-update output
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'total_updates' => count($updates),
|
||||
'updates' => $updates,
|
||||
];
|
||||
}
|
||||
|
||||
private function parseAptOutput(string $output): array
|
||||
{
|
||||
$updates = [];
|
||||
$lines = explode("\n", $output);
|
||||
|
||||
foreach ($lines as $line) {
|
||||
// Skip the "Listing... Done" line and empty lines
|
||||
if (empty($line) || str_contains($line, 'Listing...')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Example line: package/stable 2.0-1 amd64 [upgradable from: 1.0-1]
|
||||
if (preg_match('/^(.+?)\/(\S+)\s+(\S+)\s+(\S+)\s+\[upgradable from: (.+?)\]/', $line, $matches)) {
|
||||
$updates[] = [
|
||||
'package' => $matches[1],
|
||||
'repository' => $matches[2],
|
||||
'new_version' => $matches[3],
|
||||
'architecture' => $matches[4],
|
||||
'current_version' => $matches[5],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'total_updates' => count($updates),
|
||||
'updates' => $updates,
|
||||
];
|
||||
}
|
||||
}
|
||||
52
app/Actions/Server/UpdatePackage.php
Normal file
52
app/Actions/Server/UpdatePackage.php
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace App\Actions\Server;
|
||||
|
||||
use App\Models\Server;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
use Spatie\Activitylog\Contracts\Activity;
|
||||
|
||||
class UpdatePackage
|
||||
{
|
||||
use AsAction;
|
||||
|
||||
public string $jobQueue = 'high';
|
||||
|
||||
public function handle(Server $server, string $osId, ?string $package = null, ?string $packageManager = null, bool $all = false): Activity|array
|
||||
{
|
||||
try {
|
||||
if ($server->serverStatus() === false) {
|
||||
return [
|
||||
'error' => 'Server is not reachable or not ready.',
|
||||
];
|
||||
}
|
||||
switch ($packageManager) {
|
||||
case 'zypper':
|
||||
$commandAll = 'zypper update -y';
|
||||
$commandInstall = 'zypper install -y '.$package;
|
||||
break;
|
||||
case 'dnf':
|
||||
$commandAll = 'dnf update -y';
|
||||
$commandInstall = 'dnf update -y '.$package;
|
||||
break;
|
||||
case 'apt':
|
||||
$commandAll = 'apt update && apt upgrade -y';
|
||||
$commandInstall = 'apt install -y '.$package;
|
||||
break;
|
||||
default:
|
||||
return [
|
||||
'error' => 'OS not supported',
|
||||
];
|
||||
}
|
||||
if ($all) {
|
||||
return remote_process([$commandAll], $server);
|
||||
}
|
||||
|
||||
return remote_process([$commandInstall], $server);
|
||||
} catch (\Exception $e) {
|
||||
return [
|
||||
'error' => $e->getMessage(),
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,6 +41,6 @@ class StartService
|
||||
}
|
||||
}
|
||||
|
||||
return remote_process($commands, $service->server, type_uuid: $service->uuid, callEventOnFinish: 'ServiceStatusChanged');
|
||||
return remote_process($commands, $service->server, type_uuid: $service->uuid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace App\Actions\Service;
|
||||
|
||||
use App\Actions\Server\CleanupDocker;
|
||||
use App\Events\ServiceStatusChanged;
|
||||
use App\Models\Service;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
|
||||
@@ -31,6 +32,8 @@ class StopService
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return $e->getMessage();
|
||||
} finally {
|
||||
ServiceStatusChanged::dispatch($service->environment->project->team->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
35
app/Events/ServerPackageUpdated.php
Normal file
35
app/Events/ServerPackageUpdated.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||
use Illuminate\Broadcasting\PrivateChannel;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||
use Illuminate\Foundation\Events\Dispatchable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class ServerPackageUpdated implements ShouldBroadcast
|
||||
{
|
||||
use Dispatchable, InteractsWithSockets, SerializesModels;
|
||||
|
||||
public ?int $teamId = null;
|
||||
|
||||
public function __construct($teamId = null)
|
||||
{
|
||||
if (is_null($teamId) && auth()->check() && auth()->user()->currentTeam()) {
|
||||
$teamId = auth()->user()->currentTeam()->id;
|
||||
}
|
||||
$this->teamId = $teamId;
|
||||
}
|
||||
|
||||
public function broadcastOn(): array
|
||||
{
|
||||
if (is_null($this->teamId)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return [
|
||||
new PrivateChannel("team.{$this->teamId}"),
|
||||
];
|
||||
}
|
||||
}
|
||||
35
app/Events/ServiceChecked.php
Normal file
35
app/Events/ServiceChecked.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||
use Illuminate\Broadcasting\PrivateChannel;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||
use Illuminate\Foundation\Events\Dispatchable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class ServiceChecked implements ShouldBroadcast
|
||||
{
|
||||
use Dispatchable, InteractsWithSockets, SerializesModels;
|
||||
|
||||
public ?int $teamId = null;
|
||||
|
||||
public function __construct($teamId = null)
|
||||
{
|
||||
if (is_null($teamId) && auth()->check() && auth()->user()->currentTeam()) {
|
||||
$teamId = auth()->user()->currentTeam()->id;
|
||||
}
|
||||
$this->teamId = $teamId;
|
||||
}
|
||||
|
||||
public function broadcastOn(): array
|
||||
{
|
||||
if (is_null($this->teamId)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return [
|
||||
new PrivateChannel("team.{$this->teamId}"),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -13,24 +13,22 @@ class ServiceStatusChanged implements ShouldBroadcast
|
||||
{
|
||||
use Dispatchable, InteractsWithSockets, SerializesModels;
|
||||
|
||||
public int|string|null $userId = null;
|
||||
|
||||
public function __construct($userId = null)
|
||||
{
|
||||
if (is_null($userId)) {
|
||||
$userId = Auth::id() ?? null;
|
||||
public function __construct(
|
||||
public ?int $teamId = null
|
||||
) {
|
||||
if (is_null($this->teamId) && Auth::check() && Auth::user()->currentTeam()) {
|
||||
$this->teamId = Auth::user()->currentTeam()->id;
|
||||
}
|
||||
$this->userId = $userId;
|
||||
}
|
||||
|
||||
public function broadcastOn(): ?array
|
||||
public function broadcastOn(): array
|
||||
{
|
||||
if (is_null($this->userId)) {
|
||||
if (is_null($this->teamId)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return [
|
||||
new PrivateChannel("user.{$this->userId}"),
|
||||
new PrivateChannel("team.{$this->teamId}"),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -989,7 +989,34 @@ class ApplicationsController extends Controller
|
||||
|
||||
$dockerComposeDomainsJson = collect();
|
||||
if ($request->has('docker_compose_domains')) {
|
||||
$yaml = Yaml::parse($application->docker_compose_raw);
|
||||
if (! $request->has('docker_compose_raw')) {
|
||||
return response()->json([
|
||||
'message' => 'Validation failed.',
|
||||
'errors' => [
|
||||
'docker_compose_raw' => 'The base64 encoded docker_compose_raw is required.',
|
||||
],
|
||||
], 422);
|
||||
}
|
||||
|
||||
if (! isBase64Encoded($request->docker_compose_raw)) {
|
||||
return response()->json([
|
||||
'message' => 'Validation failed.',
|
||||
'errors' => [
|
||||
'docker_compose_raw' => 'The docker_compose_raw should be base64 encoded.',
|
||||
],
|
||||
], 422);
|
||||
}
|
||||
$dockerComposeRaw = base64_decode($request->docker_compose_raw);
|
||||
if (mb_detect_encoding($dockerComposeRaw, 'ASCII', true) === false) {
|
||||
return response()->json([
|
||||
'message' => 'Validation failed.',
|
||||
'errors' => [
|
||||
'docker_compose_raw' => 'The docker_compose_raw should be base64 encoded.',
|
||||
],
|
||||
], 422);
|
||||
}
|
||||
$dockerComposeRaw = base64_decode($request->docker_compose_raw);
|
||||
$yaml = Yaml::parse($dockerComposeRaw);
|
||||
$services = data_get($yaml, 'services');
|
||||
$dockerComposeDomains = collect($request->docker_compose_domains);
|
||||
if ($dockerComposeDomains->count() > 0) {
|
||||
@@ -1095,7 +1122,34 @@ class ApplicationsController extends Controller
|
||||
|
||||
$dockerComposeDomainsJson = collect();
|
||||
if ($request->has('docker_compose_domains')) {
|
||||
$yaml = Yaml::parse($application->docker_compose_raw);
|
||||
if (! $request->has('docker_compose_raw')) {
|
||||
return response()->json([
|
||||
'message' => 'Validation failed.',
|
||||
'errors' => [
|
||||
'docker_compose_raw' => 'The base64 encoded docker_compose_raw is required.',
|
||||
],
|
||||
], 422);
|
||||
}
|
||||
|
||||
if (! isBase64Encoded($request->docker_compose_raw)) {
|
||||
return response()->json([
|
||||
'message' => 'Validation failed.',
|
||||
'errors' => [
|
||||
'docker_compose_raw' => 'The docker_compose_raw should be base64 encoded.',
|
||||
],
|
||||
], 422);
|
||||
}
|
||||
$dockerComposeRaw = base64_decode($request->docker_compose_raw);
|
||||
if (mb_detect_encoding($dockerComposeRaw, 'ASCII', true) === false) {
|
||||
return response()->json([
|
||||
'message' => 'Validation failed.',
|
||||
'errors' => [
|
||||
'docker_compose_raw' => 'The docker_compose_raw should be base64 encoded.',
|
||||
],
|
||||
], 422);
|
||||
}
|
||||
$dockerComposeRaw = base64_decode($request->docker_compose_raw);
|
||||
$yaml = Yaml::parse($dockerComposeRaw);
|
||||
$services = data_get($yaml, 'services');
|
||||
$dockerComposeDomains = collect($request->docker_compose_domains);
|
||||
if ($dockerComposeDomains->count() > 0) {
|
||||
@@ -1918,7 +1972,34 @@ class ApplicationsController extends Controller
|
||||
|
||||
$dockerComposeDomainsJson = collect();
|
||||
if ($request->has('docker_compose_domains')) {
|
||||
$yaml = Yaml::parse($application->docker_compose_raw);
|
||||
if (! $request->has('docker_compose_raw')) {
|
||||
return response()->json([
|
||||
'message' => 'Validation failed.',
|
||||
'errors' => [
|
||||
'docker_compose_raw' => 'The base64 encoded docker_compose_raw is required.',
|
||||
],
|
||||
], 422);
|
||||
}
|
||||
|
||||
if (! isBase64Encoded($request->docker_compose_raw)) {
|
||||
return response()->json([
|
||||
'message' => 'Validation failed.',
|
||||
'errors' => [
|
||||
'docker_compose_raw' => 'The docker_compose_raw should be base64 encoded.',
|
||||
],
|
||||
], 422);
|
||||
}
|
||||
$dockerComposeRaw = base64_decode($request->docker_compose_raw);
|
||||
if (mb_detect_encoding($dockerComposeRaw, 'ASCII', true) === false) {
|
||||
return response()->json([
|
||||
'message' => 'Validation failed.',
|
||||
'errors' => [
|
||||
'docker_compose_raw' => 'The docker_compose_raw should be base64 encoded.',
|
||||
],
|
||||
], 422);
|
||||
}
|
||||
$dockerComposeRaw = base64_decode($request->docker_compose_raw);
|
||||
$yaml = Yaml::parse($dockerComposeRaw);
|
||||
$services = data_get($yaml, 'services');
|
||||
$dockerComposeDomains = collect($request->docker_compose_domains);
|
||||
if ($dockerComposeDomains->count() > 0) {
|
||||
|
||||
@@ -319,9 +319,10 @@ class DeployController extends Controller
|
||||
default:
|
||||
// Database resource
|
||||
StartDatabase::dispatch($resource);
|
||||
$resource->update([
|
||||
'started_at' => now(),
|
||||
]);
|
||||
|
||||
$resource->started_at ??= now();
|
||||
$resource->save();
|
||||
|
||||
$message = "Database {$resource->name} started.";
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace App\Jobs;
|
||||
use App\Actions\Docker\GetContainersStatus;
|
||||
use App\Enums\ApplicationDeploymentStatus;
|
||||
use App\Enums\ProcessStatus;
|
||||
use App\Events\ApplicationStatusChanged;
|
||||
use App\Events\ServiceStatusChanged;
|
||||
use App\Models\Application;
|
||||
use App\Models\ApplicationDeploymentQueue;
|
||||
use App\Models\ApplicationPreview;
|
||||
@@ -331,7 +331,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
$this->application_deployment_queue->addLogEntry("Gracefully shutting down build container: {$this->deployment_uuid}");
|
||||
$this->graceful_shutdown_container($this->deployment_uuid);
|
||||
|
||||
ApplicationStatusChanged::dispatch(data_get($this->application, 'environment.project.team.id'));
|
||||
ServiceStatusChanged::dispatch(data_get($this->application, 'environment.project.team.id'));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,8 @@ class ActivityMonitor extends Component
|
||||
|
||||
protected $activity;
|
||||
|
||||
public static $eventDispatched = false;
|
||||
|
||||
protected $listeners = ['activityMonitor' => 'newMonitorActivity'];
|
||||
|
||||
public function newMonitorActivity($activityId, $eventToDispatch = 'activityFinished')
|
||||
@@ -51,15 +53,19 @@ class ActivityMonitor extends Component
|
||||
$causer_id = data_get($this->activity, 'causer_id');
|
||||
$user = User::find($causer_id);
|
||||
if ($user) {
|
||||
foreach ($user->teams as $team) {
|
||||
$teamId = $team->id;
|
||||
$teamId = $user->currentTeam()->id;
|
||||
if (! self::$eventDispatched) {
|
||||
$this->eventToDispatch::dispatch($teamId);
|
||||
self::$eventDispatched = true;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
$this->dispatch($this->eventToDispatch);
|
||||
if (! self::$eventDispatched) {
|
||||
$this->dispatch($this->eventToDispatch);
|
||||
self::$eventDispatched = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,15 @@ class Configuration extends Component
|
||||
|
||||
public $servers;
|
||||
|
||||
protected $listeners = ['buildPackUpdated' => '$refresh'];
|
||||
public function getListeners()
|
||||
{
|
||||
$teamId = auth()->user()->currentTeam()->id;
|
||||
|
||||
return [
|
||||
"echo-private:team.{$teamId},ServiceChecked" => '$refresh',
|
||||
'buildPackUpdated' => '$refresh',
|
||||
];
|
||||
}
|
||||
|
||||
public function mount()
|
||||
{
|
||||
|
||||
@@ -28,6 +28,15 @@ class Index extends Component
|
||||
|
||||
protected $queryString = ['pull_request_id'];
|
||||
|
||||
public function getListeners()
|
||||
{
|
||||
$teamId = auth()->user()->currentTeam()->id;
|
||||
|
||||
return [
|
||||
"echo-private:team.{$teamId},ServiceChecked" => '$refresh',
|
||||
];
|
||||
}
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$project = currentTeam()->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
|
||||
|
||||
@@ -18,7 +18,15 @@ class Show extends Component
|
||||
|
||||
public $isKeepAliveOn = true;
|
||||
|
||||
protected $listeners = ['refreshQueue'];
|
||||
public function getListeners()
|
||||
{
|
||||
$teamId = auth()->user()->currentTeam()->id;
|
||||
|
||||
return [
|
||||
"echo-private:team.{$teamId},ServiceChecked" => '$refresh',
|
||||
'refreshQueue',
|
||||
];
|
||||
}
|
||||
|
||||
public function mount()
|
||||
{
|
||||
|
||||
@@ -4,7 +4,6 @@ namespace App\Livewire\Project\Application;
|
||||
|
||||
use App\Actions\Application\StopApplication;
|
||||
use App\Actions\Docker\GetContainersStatus;
|
||||
use App\Events\ApplicationStatusChanged;
|
||||
use App\Models\Application;
|
||||
use Livewire\Component;
|
||||
use Visus\Cuid2\Cuid2;
|
||||
@@ -28,7 +27,8 @@ class Heading extends Component
|
||||
$teamId = auth()->user()->currentTeam()->id;
|
||||
|
||||
return [
|
||||
"echo-private:team.{$teamId},ApplicationStatusChanged" => 'check_status',
|
||||
"echo-private:team.{$teamId},ServiceStatusChanged" => 'checkStatus',
|
||||
"echo-private:team.{$teamId},ServiceChecked" => '$refresh',
|
||||
'compose_loaded' => '$refresh',
|
||||
'update_links' => '$refresh',
|
||||
];
|
||||
@@ -46,14 +46,11 @@ class Heading extends Component
|
||||
$this->lastDeploymentLink = $this->application->gitCommitLink(data_get($lastDeployment, 'commit'));
|
||||
}
|
||||
|
||||
public function check_status($showNotification = false)
|
||||
public function checkStatus()
|
||||
{
|
||||
if ($this->application->destination->server->isFunctional()) {
|
||||
GetContainersStatus::dispatch($this->application->destination->server);
|
||||
}
|
||||
if ($showNotification) {
|
||||
$this->dispatch('success', 'Success', 'Application status updated.');
|
||||
}
|
||||
}
|
||||
|
||||
public function force_deploy_without_cache()
|
||||
@@ -111,16 +108,7 @@ class Heading extends Component
|
||||
|
||||
public function stop()
|
||||
{
|
||||
StopApplication::run($this->application, false, $this->docker_cleanup);
|
||||
$this->application->status = 'exited';
|
||||
$this->application->save();
|
||||
if ($this->application->additional_servers->count() > 0) {
|
||||
$this->application->additional_servers->each(function ($server) {
|
||||
$server->pivot->status = 'exited:unhealthy';
|
||||
$server->pivot->save();
|
||||
});
|
||||
}
|
||||
ApplicationStatusChanged::dispatch(data_get($this->application, 'environment.project.team.id'));
|
||||
StopApplication::dispatch($this->application, false, $this->docker_cleanup);
|
||||
}
|
||||
|
||||
public function restart()
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Livewire\Project\Database;
|
||||
|
||||
use Auth;
|
||||
use Livewire\Component;
|
||||
|
||||
class Configuration extends Component
|
||||
@@ -14,6 +15,15 @@ class Configuration extends Component
|
||||
|
||||
public $environment;
|
||||
|
||||
public function getListeners()
|
||||
{
|
||||
$teamId = Auth::user()->currentTeam()->id;
|
||||
|
||||
return [
|
||||
"echo-private:team.{$teamId},ServiceChecked" => '$refresh',
|
||||
];
|
||||
}
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->currentRoute = request()->route()->getName();
|
||||
|
||||
@@ -6,7 +6,7 @@ use App\Actions\Database\RestartDatabase;
|
||||
use App\Actions\Database\StartDatabase;
|
||||
use App\Actions\Database\StopDatabase;
|
||||
use App\Actions\Docker\GetContainersStatus;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use App\Events\ServiceStatusChanged;
|
||||
use Livewire\Component;
|
||||
|
||||
class Heading extends Component
|
||||
@@ -19,36 +19,38 @@ class Heading extends Component
|
||||
|
||||
public function getListeners()
|
||||
{
|
||||
$userId = Auth::id();
|
||||
$teamId = auth()->user()->currentTeam()->id;
|
||||
|
||||
return [
|
||||
"echo-private:user.{$userId},DatabaseStatusChanged" => 'activityFinished',
|
||||
"echo-private:team.{$teamId},ServiceStatusChanged" => 'checkStatus',
|
||||
"echo-private:team.{$teamId},ServiceChecked" => 'activityFinished',
|
||||
'refresh' => '$refresh',
|
||||
'compose_loaded' => '$refresh',
|
||||
'update_links' => '$refresh',
|
||||
];
|
||||
}
|
||||
|
||||
public function activityFinished()
|
||||
{
|
||||
$this->database->update([
|
||||
'started_at' => now(),
|
||||
]);
|
||||
$this->check_status();
|
||||
try {
|
||||
$this->database->started_at ??= now();
|
||||
$this->database->save();
|
||||
|
||||
if (is_null($this->database->config_hash) || $this->database->isConfigurationChanged()) {
|
||||
$this->database->isConfigurationChanged(true);
|
||||
$this->dispatch('configurationChanged');
|
||||
} else {
|
||||
if (is_null($this->database->config_hash) || $this->database->isConfigurationChanged()) {
|
||||
$this->database->isConfigurationChanged(true);
|
||||
}
|
||||
$this->dispatch('configurationChanged');
|
||||
} catch (\Exception $e) {
|
||||
return handleError($e, $this);
|
||||
} finally {
|
||||
$this->dispatch('refresh');
|
||||
}
|
||||
}
|
||||
|
||||
public function check_status($showNotification = false)
|
||||
public function checkStatus()
|
||||
{
|
||||
if ($this->database->destination->server->isFunctional()) {
|
||||
GetContainersStatus::run($this->database->destination->server);
|
||||
}
|
||||
|
||||
if ($showNotification) {
|
||||
$this->dispatch('success', 'Database status updated.');
|
||||
GetContainersStatus::dispatch($this->database->destination->server);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,23 +61,24 @@ class Heading extends Component
|
||||
|
||||
public function stop()
|
||||
{
|
||||
StopDatabase::run($this->database, false, $this->docker_cleanup);
|
||||
$this->database->status = 'exited';
|
||||
$this->database->save();
|
||||
$this->check_status();
|
||||
$this->dispatch('refresh');
|
||||
try {
|
||||
$this->dispatch('info', 'Stopping database.');
|
||||
StopDatabase::dispatch($this->database, false, $this->docker_cleanup);
|
||||
} catch (\Exception $e) {
|
||||
$this->dispatch('error', $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function restart()
|
||||
{
|
||||
$activity = RestartDatabase::run($this->database);
|
||||
$this->dispatch('activityMonitor', $activity->id);
|
||||
$this->dispatch('activityMonitor', $activity->id, ServiceStatusChanged::class);
|
||||
}
|
||||
|
||||
public function start()
|
||||
{
|
||||
$activity = StartDatabase::run($this->database);
|
||||
$this->dispatch('activityMonitor', $activity->id);
|
||||
$this->dispatch('activityMonitor', $activity->id, ServiceStatusChanged::class);
|
||||
}
|
||||
|
||||
public function render()
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
namespace App\Livewire\Project\Service;
|
||||
|
||||
use App\Actions\Docker\GetContainersStatus;
|
||||
use App\Models\Service;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Livewire\Component;
|
||||
@@ -27,13 +26,10 @@ class Configuration extends Component
|
||||
|
||||
public function getListeners()
|
||||
{
|
||||
$userId = Auth::id();
|
||||
$teamId = Auth::user()->currentTeam()->id;
|
||||
|
||||
return [
|
||||
"echo-private:user.{$userId},ServiceStatusChanged" => 'check_status',
|
||||
'refreshStatus' => '$refresh',
|
||||
'check_status',
|
||||
'refreshServices',
|
||||
"echo-private:team.{$teamId},ServiceChecked" => 'serviceChecked',
|
||||
];
|
||||
}
|
||||
|
||||
@@ -97,19 +93,15 @@ class Configuration extends Component
|
||||
}
|
||||
}
|
||||
|
||||
public function check_status()
|
||||
public function serviceChecked()
|
||||
{
|
||||
try {
|
||||
if ($this->service->server->isFunctional()) {
|
||||
GetContainersStatus::dispatch($this->service->server);
|
||||
}
|
||||
$this->service->applications->each(function ($application) {
|
||||
$application->refresh();
|
||||
});
|
||||
$this->service->databases->each(function ($database) {
|
||||
$database->refresh();
|
||||
});
|
||||
$this->dispatch('refreshStatus');
|
||||
} catch (\Exception $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
|
||||
@@ -47,7 +47,6 @@ class EditDomain extends Component
|
||||
$this->application->service->parse();
|
||||
$this->dispatch('refresh');
|
||||
$this->dispatch('configurationChanged');
|
||||
$this->dispatch('refreshStatus');
|
||||
} catch (\Throwable $e) {
|
||||
$originalFqdn = $this->application->getOriginal('fqdn');
|
||||
if ($originalFqdn !== $this->application->fqdn) {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Livewire\Project\Service;
|
||||
|
||||
use App\Actions\Docker\GetContainersStatus;
|
||||
use App\Actions\Service\StartService;
|
||||
use App\Actions\Service\StopService;
|
||||
use App\Enums\ProcessStatus;
|
||||
@@ -11,7 +12,7 @@ use Illuminate\Support\Facades\Auth;
|
||||
use Livewire\Component;
|
||||
use Spatie\Activitylog\Models\Activity;
|
||||
|
||||
class Navbar extends Component
|
||||
class Heading extends Component
|
||||
{
|
||||
public Service $service;
|
||||
|
||||
@@ -35,35 +36,42 @@ class Navbar extends Component
|
||||
|
||||
public function getListeners()
|
||||
{
|
||||
$userId = Auth::id();
|
||||
$teamId = Auth::user()->currentTeam()->id;
|
||||
|
||||
return [
|
||||
"echo-private:user.{$userId},ServiceStatusChanged" => 'serviceStarted',
|
||||
"echo-private:team.{$teamId},ServiceStatusChanged" => 'checkStatus',
|
||||
"echo-private:team.{$teamId},ServiceChecked" => 'serviceChecked',
|
||||
'refresh' => '$refresh',
|
||||
'envsUpdated' => '$refresh',
|
||||
'refreshStatus' => '$refresh',
|
||||
];
|
||||
}
|
||||
|
||||
public function serviceStarted()
|
||||
public function checkStatus()
|
||||
{
|
||||
// $this->dispatch('success', 'Service status changed.');
|
||||
if (is_null($this->service->config_hash) || $this->service->isConfigurationChanged()) {
|
||||
$this->service->isConfigurationChanged(true);
|
||||
$this->dispatch('configurationChanged');
|
||||
} else {
|
||||
$this->dispatch('configurationChanged');
|
||||
if ($this->service->server->isFunctional()) {
|
||||
GetContainersStatus::dispatch($this->service->server);
|
||||
}
|
||||
}
|
||||
|
||||
public function check_status_without_notification()
|
||||
public function serviceChecked()
|
||||
{
|
||||
$this->dispatch('check_status');
|
||||
}
|
||||
try {
|
||||
$this->service->applications->each(function ($application) {
|
||||
$application->refresh();
|
||||
});
|
||||
$this->service->databases->each(function ($database) {
|
||||
$database->refresh();
|
||||
});
|
||||
if (is_null($this->service->config_hash) || $this->service->isConfigurationChanged()) {
|
||||
$this->service->isConfigurationChanged(true);
|
||||
}
|
||||
$this->dispatch('configurationChanged');
|
||||
} catch (\Exception $e) {
|
||||
return handleError($e, $this);
|
||||
} finally {
|
||||
$this->dispatch('refresh')->self();
|
||||
}
|
||||
|
||||
public function check_status()
|
||||
{
|
||||
$this->dispatch('check_status');
|
||||
$this->dispatch('success', 'Service status updated.');
|
||||
}
|
||||
|
||||
public function checkDeployments()
|
||||
@@ -86,34 +94,32 @@ class Navbar extends Component
|
||||
public function start()
|
||||
{
|
||||
$activity = StartService::run($this->service, pullLatestImages: true);
|
||||
$this->dispatch('activityMonitor', $activity->id);
|
||||
$this->dispatch('activityMonitor', $activity->id, ServiceStatusChanged::class);
|
||||
}
|
||||
|
||||
public function forceDeploy()
|
||||
{
|
||||
try {
|
||||
$activities = Activity::where('properties->type_uuid', $this->service->uuid)->where('properties->status', ProcessStatus::IN_PROGRESS->value)->orWhere('properties->status', ProcessStatus::QUEUED->value)->get();
|
||||
$activities = Activity::where('properties->type_uuid', $this->service->uuid)
|
||||
->where(function ($q) {
|
||||
$q->where('properties->status', ProcessStatus::IN_PROGRESS->value)
|
||||
->orWhere('properties->status', ProcessStatus::QUEUED->value);
|
||||
})->get();
|
||||
foreach ($activities as $activity) {
|
||||
$activity->properties->status = ProcessStatus::ERROR->value;
|
||||
$activity->save();
|
||||
}
|
||||
$activity = StartService::run($this->service, pullLatestImages: true, stopBeforeStart: true);
|
||||
$this->dispatch('activityMonitor', $activity->id);
|
||||
$this->dispatch('activityMonitor', $activity->id, ServiceStatusChanged::class);
|
||||
} catch (\Exception $e) {
|
||||
$this->dispatch('error', $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function stop($cleanupContainers = false)
|
||||
public function stop()
|
||||
{
|
||||
try {
|
||||
StopService::run($this->service, false, $this->docker_cleanup);
|
||||
ServiceStatusChanged::dispatch();
|
||||
if ($cleanupContainers) {
|
||||
$this->dispatch('success', 'Containers cleaned up.');
|
||||
} else {
|
||||
$this->dispatch('success', 'Service stopped.');
|
||||
}
|
||||
StopService::dispatch($this->service, false, $this->docker_cleanup);
|
||||
} catch (\Exception $e) {
|
||||
$this->dispatch('error', $e->getMessage());
|
||||
}
|
||||
@@ -128,7 +134,7 @@ class Navbar extends Component
|
||||
return;
|
||||
}
|
||||
$activity = StartService::run($this->service, stopBeforeStart: true);
|
||||
$this->dispatch('activityMonitor', $activity->id);
|
||||
$this->dispatch('activityMonitor', $activity->id, ServiceStatusChanged::class);
|
||||
}
|
||||
|
||||
public function pullAndRestartEvent()
|
||||
@@ -140,12 +146,12 @@ class Navbar extends Component
|
||||
return;
|
||||
}
|
||||
$activity = StartService::run($this->service, pullLatestImages: true, stopBeforeStart: true);
|
||||
$this->dispatch('activityMonitor', $activity->id);
|
||||
$this->dispatch('activityMonitor', $activity->id, ServiceStatusChanged::class);
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.project.service.navbar', [
|
||||
return view('livewire.project.service.heading', [
|
||||
'checkboxes' => [
|
||||
['id' => 'docker_cleanup', 'label' => __('resource.docker_cleanup')],
|
||||
],
|
||||
@@ -119,17 +119,14 @@ class Destination extends Component
|
||||
public function refreshServers()
|
||||
{
|
||||
GetContainersStatus::run($this->resource->destination->server);
|
||||
// ContainerStatusJob::dispatchSync($this->resource->destination->server);
|
||||
$this->loadData();
|
||||
$this->dispatch('refresh');
|
||||
ApplicationStatusChanged::dispatch(data_get($this->resource, 'environment.project.team.id'));
|
||||
}
|
||||
|
||||
public function addServer(int $network_id, int $server_id)
|
||||
{
|
||||
$this->resource->additional_networks()->attach($network_id, ['server_id' => $server_id]);
|
||||
$this->loadData();
|
||||
ApplicationStatusChanged::dispatch(data_get($this->resource, 'environment.project.team.id'));
|
||||
}
|
||||
|
||||
public function removeServer(int $network_id, int $server_id, $password)
|
||||
|
||||
@@ -35,6 +35,15 @@ class ExecuteContainerCommand extends Component
|
||||
'command' => 'required',
|
||||
];
|
||||
|
||||
public function getListeners()
|
||||
{
|
||||
$teamId = auth()->user()->currentTeam()->id;
|
||||
|
||||
return [
|
||||
"echo-private:team.{$teamId},ServiceChecked" => '$refresh',
|
||||
];
|
||||
}
|
||||
|
||||
public function mount()
|
||||
{
|
||||
if (! auth()->user()->isAdmin()) {
|
||||
|
||||
@@ -37,6 +37,15 @@ class Logs extends Component
|
||||
|
||||
public $cpu;
|
||||
|
||||
public function getListeners()
|
||||
{
|
||||
$teamId = auth()->user()->currentTeam()->id;
|
||||
|
||||
return [
|
||||
"echo-private:team.{$teamId},ServiceChecked" => '$refresh',
|
||||
];
|
||||
}
|
||||
|
||||
public function loadContainers($server_id)
|
||||
{
|
||||
try {
|
||||
|
||||
@@ -46,6 +46,15 @@ class Show extends Component
|
||||
#[Locked]
|
||||
public string $task_uuid;
|
||||
|
||||
public function getListeners()
|
||||
{
|
||||
$teamId = auth()->user()->currentTeam()->id;
|
||||
|
||||
return [
|
||||
"echo-private:team.{$teamId},ServiceChecked" => '$refresh',
|
||||
];
|
||||
}
|
||||
|
||||
public function mount(string $task_uuid, string $project_uuid, string $environment_uuid, ?string $application_uuid = null, ?string $service_uuid = null)
|
||||
{
|
||||
try {
|
||||
|
||||
102
app/Livewire/Server/Security/Patches.php
Normal file
102
app/Livewire/Server/Security/Patches.php
Normal file
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
namespace App\Livewire\Server\Security;
|
||||
|
||||
use App\Actions\Server\CheckUpdates;
|
||||
use App\Actions\Server\UpdatePackage;
|
||||
use App\Events\ServerPackageUpdated;
|
||||
use App\Models\Server;
|
||||
use Livewire\Component;
|
||||
|
||||
class Patches extends Component
|
||||
{
|
||||
public array $parameters;
|
||||
|
||||
public Server $server;
|
||||
|
||||
public ?int $totalUpdates = null;
|
||||
|
||||
public ?array $updates = null;
|
||||
|
||||
public ?string $error = null;
|
||||
|
||||
public ?string $osId = null;
|
||||
|
||||
public ?string $packageManager = null;
|
||||
|
||||
public function getListeners()
|
||||
{
|
||||
$teamId = auth()->user()->currentTeam()->id;
|
||||
|
||||
return [
|
||||
"echo-private:team.{$teamId},ServerPackageUpdated" => 'checkForUpdatesDispatch',
|
||||
];
|
||||
}
|
||||
|
||||
public function mount()
|
||||
{
|
||||
if (! auth()->user()->isAdmin()) {
|
||||
abort(403);
|
||||
}
|
||||
$this->parameters = get_route_parameters();
|
||||
$this->server = Server::ownedByCurrentTeam()->whereUuid($this->parameters['server_uuid'])->firstOrFail();
|
||||
}
|
||||
|
||||
public function checkForUpdatesDispatch()
|
||||
{
|
||||
$this->totalUpdates = null;
|
||||
$this->updates = null;
|
||||
$this->error = null;
|
||||
$this->osId = null;
|
||||
$this->packageManager = null;
|
||||
$this->dispatch('checkForUpdatesDispatch');
|
||||
}
|
||||
|
||||
public function checkForUpdates()
|
||||
{
|
||||
$job = CheckUpdates::run($this->server);
|
||||
if (isset($job['error'])) {
|
||||
$this->error = data_get($job, 'error', 'Something went wrong.');
|
||||
} else {
|
||||
$this->totalUpdates = data_get($job, 'total_updates', 0);
|
||||
$this->updates = data_get($job, 'updates', []);
|
||||
$this->osId = data_get($job, 'osId', null);
|
||||
$this->packageManager = data_get($job, 'package_manager', null);
|
||||
}
|
||||
}
|
||||
|
||||
public function updateAllPackages()
|
||||
{
|
||||
if (! $this->packageManager || ! $this->osId) {
|
||||
$this->dispatch('error', message: 'Run “Check for updates” first.');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$activity = UpdatePackage::run(
|
||||
server: $this->server,
|
||||
packageManager: $this->packageManager,
|
||||
osId: $this->osId,
|
||||
all: true
|
||||
);
|
||||
$this->dispatch('activityMonitor', $activity->id, ServerPackageUpdated::class);
|
||||
} catch (\Exception $e) {
|
||||
$this->dispatch('error', message: $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function updatePackage($package)
|
||||
{
|
||||
try {
|
||||
$activity = UpdatePackage::run(server: $this->server, packageManager: $this->packageManager, osId: $this->osId, package: $package);
|
||||
$this->dispatch('activityMonitor', $activity->id, ServerPackageUpdated::class);
|
||||
} catch (\Exception $e) {
|
||||
$this->dispatch('error', message: $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.server.security.patches');
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,7 @@ class Checkbox extends Component
|
||||
public string|bool|null $checked = false,
|
||||
public string|bool $instantSave = false,
|
||||
public bool $disabled = false,
|
||||
public string $defaultClass = 'dark:border-neutral-700 text-coolgray-400 focus:ring-warning dark:bg-coolgray-100 rounded cursor-pointer dark:disabled:bg-base dark:disabled:cursor-not-allowed',
|
||||
public string $defaultClass = 'dark:border-neutral-700 text-coolgray-400 focus:ring-warning dark:bg-coolgray-100 rounded-sm cursor-pointer dark:disabled:bg-base dark:disabled:cursor-not-allowed',
|
||||
) {
|
||||
if ($this->disabled) {
|
||||
$this->defaultClass .= ' opacity-40';
|
||||
|
||||
Reference in New Issue
Block a user