Merge remote-tracking branch 'upstream/next' into next
This commit is contained in:
		
							
								
								
									
										17
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								README.md
									
									
									
									
									
								
							@@ -1,6 +1,10 @@
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||
[](https://console.algora.io/org/coollabsio/bounties/new)
 | 
			
		||||
[](https://console.algora.io/org/coollabsio/bounties?status=open)
 | 
			
		||||
[](https://console.algora.io/org/coollabsio/bounties?status=completed)
 | 
			
		||||
 | 
			
		||||
# About the Project
 | 
			
		||||
 | 
			
		||||
Coolify is an open-source & self-hostable alternative to Heroku / Netlify / Vercel / etc. 
 | 
			
		||||
@@ -34,13 +38,17 @@ Thank you so much!
 | 
			
		||||
Special thanks to our biggest sponsors!
 | 
			
		||||
 | 
			
		||||
<a href="https://cccareers.org/" target="_blank"><img src="./other/logos/ccc-logo.webp" alt="cccareers logo" width="200"/></a>
 | 
			
		||||
<a href="http://htznr.li/CoolifyXHetzner" target="_blank"><img src="./other/logos/hetzner.jpg" alt="hetzner logo" width="200"/></a>
 | 
			
		||||
<a href="https://logto.io/?ref=coolify" target="_blank"><img src="./other/logos/logto.webp" alt="logto logo" width="200"/></a>
 | 
			
		||||
<a href="http://htznr.li/CoolifyXHetzner" target="_blank"><img src="./other/logos/hetzner.jpg" alt="hetzner logo" width="150"/></a>
 | 
			
		||||
<a href="https://logto.io/?ref=coolify" target="_blank"><img src="./other/logos/logto.webp" alt="logto logo" width="150"/></a>
 | 
			
		||||
<a href="https://bc.direct/?ref=coolify.io" target="_blank"><img src="./other/logos/bc.png" alt="bc direct logo" width="200"/></a>
 | 
			
		||||
<a href="https://www.quantcdn.io/?ref=coolify.io" target="_blank"><img src="./other/logos/quant.svg" alt="quantcdn logo" width="200"/></a>
 | 
			
		||||
<a href="https://www.quantcdn.io/?ref=coolify.io" target="_blank"><img src="./other/logos/quant.svg" alt="quantcdn logo" width="150"/></a>
 | 
			
		||||
<a href="https://arcjet.com/?ref=coolify.io" target="_blank"><img src="./other/logos/arcjet.svg" alt="arcjet logo" width="200"/></a>
 | 
			
		||||
<a href="https://supa.guide/?ref=coolify.io" target="_blank"><img src="./other/logos/supaguide.png" alt="supaguide logo" width="200"/></a>
 | 
			
		||||
<a href="https://tigrisdata.com/?ref=coolify.io" target="_blank"><img src="./other/logos/tigris.svg" alt="tigris logo" width="200"/></a>
 | 
			
		||||
<a href="https://tigrisdata.com/?ref=coolify.io" target="_blank"><img src="./other/logos/tigris.svg" alt="tigris logo" width="140"/></a>
 | 
			
		||||
<a href="https://fractalnetworks.co/?ref=coolify.io" target="_blank"><img src="./other/logos/fractal.svg" alt="fractal logo" width="180"/></a>
 | 
			
		||||
<a href="https://coolify.ad.vin/?ref=coolify.io" target="_blank"><img src="./other/logos/advin.png" alt="advin logo" width="250"/></a>
 | 
			
		||||
<a href="https://trieve.ai/?ref=coolify.io" target="_blank"><img src="./other/logos/trieve_bg.png" alt="trieve logo" width="180"/></a>
 | 
			
		||||
<a href="https://blacksmith.sh/?ref=coolify.io" target="_blank"><img src="./other/logos/blacksmith.svg" alt="blacksmith logo" width="200"/></a>
 | 
			
		||||
 | 
			
		||||
## Github Sponsors ($40+)
 | 
			
		||||
<a href="https://serpapi.com/?ref=coolify.io"><img width="60px" alt="SerpAPI" src="https://github.com/serpapi.png"/></a>
 | 
			
		||||
@@ -51,6 +59,7 @@ Special thanks to our biggest sponsors!
 | 
			
		||||
<a href="https://www.flint.sh/en/home?ref=coolify.io"> <img src="https://github.com/Flint-company.png" width="60px" alt="FlintCompany"/></a>
 | 
			
		||||
<a href="https://americancloud.com/?ref=coolify.io"><img src="https://github.com/American-Cloud.png" width="60px" alt="American Cloud"/></a>
 | 
			
		||||
<a href="https://cryptojobslist.com/?ref=coolify.io"><img src="https://github.com/cryptojobslist.png" width="60px" alt="CryptoJobsList" /></a>
 | 
			
		||||
<a href="https://codext.link/coolify-io?ref=coolify.io"><img src="./other/logos/codext.jpg" width="60px" alt="Codext" /></a>
 | 
			
		||||
<a href="https://x.com/mrsmith9ja?ref=coolify.io"><img width="60px" alt="Thompson Edolo" src="https://github.com/verygreenboi.png"/></a>
 | 
			
		||||
<a href="https://www.uxwizz.com/?ref=coolify.io"><img width="60px" alt="UXWizz" src="https://github.com/UXWizz.png"/></a>
 | 
			
		||||
<a href="https://github.com/Flowko"><img src="https://barrad.me/_ipx/f_webp&s_300x300/younes.jpg" width="60px" alt="Younes Barrad" /></a>
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@
 | 
			
		||||
 | 
			
		||||
namespace App\Actions\Database;
 | 
			
		||||
 | 
			
		||||
use App\Events\DatabaseStatusChanged;
 | 
			
		||||
use App\Models\ServiceDatabase;
 | 
			
		||||
use App\Models\StandaloneClickhouse;
 | 
			
		||||
use App\Models\StandaloneDragonfly;
 | 
			
		||||
@@ -28,5 +29,6 @@ class StopDatabaseProxy
 | 
			
		||||
        instant_remote_process(["docker rm -f {$uuid}-proxy"], $server);
 | 
			
		||||
        $database->is_public = false;
 | 
			
		||||
        $database->save();
 | 
			
		||||
        DatabaseStatusChanged::dispatch();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -12,12 +12,15 @@ class StartSentinel
 | 
			
		||||
    public function handle(Server $server, $version = 'latest', bool $restart = false)
 | 
			
		||||
    {
 | 
			
		||||
        if ($restart) {
 | 
			
		||||
            instant_remote_process(['docker rm -f coolify-sentinel'], $server, false);
 | 
			
		||||
            StopSentinel::run($server);
 | 
			
		||||
        }
 | 
			
		||||
        $metrics_history = $server->settings->metrics_history_days;
 | 
			
		||||
        $refresh_rate = $server->settings->metrics_refresh_rate_seconds;
 | 
			
		||||
        $token = $server->settings->metrics_token;
 | 
			
		||||
        instant_remote_process([
 | 
			
		||||
            "docker run --rm --pull always -d -e \"SCHEDULER=true\" --name coolify-sentinel -v /var/run/docker.sock:/var/run/docker.sock -v /data/coolify/metrics:/app/metrics -v /data/coolify/logs:/app/logs --pid host --health-cmd \"curl --fail http://127.0.0.1:8888/api/health || exit 1\" --health-interval 10s --health-retries 3 ghcr.io/coollabsio/sentinel:$version",
 | 
			
		||||
            "docker run --rm --pull always -d -e \"TOKEN={$token}\" -e \"SCHEDULER=true\" -e \"METRICS_HISTORY={$metrics_history}\" -e \"REFRESH_RATE={$refresh_rate}\" --name coolify-sentinel -v /var/run/docker.sock:/var/run/docker.sock -v /data/coolify/metrics:/app/metrics -v /data/coolify/logs:/app/logs --pid host --health-cmd \"curl --fail http://127.0.0.1:8888/api/health || exit 1\" --health-interval 10s --health-retries 3 ghcr.io/coollabsio/sentinel:$version",
 | 
			
		||||
            'chown -R 9999:root /data/coolify/metrics /data/coolify/logs',
 | 
			
		||||
            'chmod -R 700 /data/coolify/metrics /data/coolify/logs',
 | 
			
		||||
        ], $server, false);
 | 
			
		||||
        ], $server, true);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										16
									
								
								app/Actions/Server/StopSentinel.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								app/Actions/Server/StopSentinel.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace App\Actions\Server;
 | 
			
		||||
 | 
			
		||||
use App\Models\Server;
 | 
			
		||||
use Lorisleiva\Actions\Concerns\AsAction;
 | 
			
		||||
 | 
			
		||||
class StopSentinel
 | 
			
		||||
{
 | 
			
		||||
    use AsAction;
 | 
			
		||||
 | 
			
		||||
    public function handle(Server $server)
 | 
			
		||||
    {
 | 
			
		||||
        instant_remote_process(['docker rm -f coolify-sentinel'], $server, false);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -5,6 +5,7 @@ namespace App\Console\Commands;
 | 
			
		||||
use App\Enums\ApplicationDeploymentStatus;
 | 
			
		||||
use App\Jobs\CleanupHelperContainersJob;
 | 
			
		||||
use App\Models\ApplicationDeploymentQueue;
 | 
			
		||||
use App\Models\Environment;
 | 
			
		||||
use App\Models\InstanceSettings;
 | 
			
		||||
use App\Models\ScheduledDatabaseBackup;
 | 
			
		||||
use App\Models\Server;
 | 
			
		||||
@@ -24,6 +25,8 @@ class Init extends Command
 | 
			
		||||
        get_public_ips();
 | 
			
		||||
        $full_cleanup = $this->option('full-cleanup');
 | 
			
		||||
        $cleanup_deployments = $this->option('cleanup-deployments');
 | 
			
		||||
 | 
			
		||||
        $this->replace_slash_in_environment_name();
 | 
			
		||||
        if ($cleanup_deployments) {
 | 
			
		||||
            echo "Running cleanup deployments.\n";
 | 
			
		||||
            $this->cleanup_in_progress_application_deployments();
 | 
			
		||||
@@ -150,4 +153,15 @@ class Init extends Command
 | 
			
		||||
            echo "Error: {$e->getMessage()}\n";
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function replace_slash_in_environment_name()
 | 
			
		||||
    {
 | 
			
		||||
        $environments = Environment::all();
 | 
			
		||||
        foreach ($environments as $environment) {
 | 
			
		||||
            if (str_contains($environment->name, '/')) {
 | 
			
		||||
                $environment->name = str_replace('/', '-', $environment->name);
 | 
			
		||||
                $environment->save();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -61,7 +61,7 @@ class Kernel extends ConsoleKernel
 | 
			
		||||
    {
 | 
			
		||||
        $servers = $this->all_servers->where('settings.is_usable', true)->where('settings.is_reachable', true)->where('ip', '!=', '1.2.3.4');
 | 
			
		||||
        foreach ($servers as $server) {
 | 
			
		||||
            if (config('coolify.is_sentinel_enabled')) {
 | 
			
		||||
            if ($server->isSentinelEnabled()) {
 | 
			
		||||
                $schedule->job(new PullSentinelImageJob($server))->everyFiveMinutes()->onOneServer();
 | 
			
		||||
            }
 | 
			
		||||
            $schedule->job(new PullHelperImageJob($server))->everyFiveMinutes()->onOneServer();
 | 
			
		||||
 
 | 
			
		||||
@@ -11,6 +11,5 @@ class ServerMetadata extends Data
 | 
			
		||||
    public function __construct(
 | 
			
		||||
        public ?ProxyTypes $type,
 | 
			
		||||
        public ?ProxyStatus $status
 | 
			
		||||
    ) {
 | 
			
		||||
    }
 | 
			
		||||
    ) {}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -10,8 +10,5 @@ class ProxyStarted
 | 
			
		||||
{
 | 
			
		||||
    use Dispatchable, InteractsWithSockets, SerializesModels;
 | 
			
		||||
 | 
			
		||||
    public function __construct(public $data)
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
    public function __construct(public $data) {}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,4 @@ namespace App\Exceptions;
 | 
			
		||||
 | 
			
		||||
use Exception;
 | 
			
		||||
 | 
			
		||||
class ProcessException extends Exception
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
class ProcessException extends Exception {}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										183
									
								
								app/Http/Controllers/Api/Applications.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										183
									
								
								app/Http/Controllers/Api/Applications.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,183 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace App\Http\Controllers\Api;
 | 
			
		||||
 | 
			
		||||
use App\Actions\Application\StopApplication;
 | 
			
		||||
use App\Http\Controllers\Controller;
 | 
			
		||||
use App\Models\Application;
 | 
			
		||||
use App\Models\Project;
 | 
			
		||||
use Illuminate\Http\Request;
 | 
			
		||||
use Visus\Cuid2\Cuid2;
 | 
			
		||||
 | 
			
		||||
class Applications extends Controller
 | 
			
		||||
{
 | 
			
		||||
    public function applications(Request $request)
 | 
			
		||||
    {
 | 
			
		||||
        $teamId = get_team_id_from_token();
 | 
			
		||||
        if (is_null($teamId)) {
 | 
			
		||||
            return invalid_token();
 | 
			
		||||
        }
 | 
			
		||||
        $projects = Project::where('team_id', $teamId)->get();
 | 
			
		||||
        $applications = collect();
 | 
			
		||||
        $applications->push($projects->pluck('applications')->flatten());
 | 
			
		||||
        $applications = $applications->flatten();
 | 
			
		||||
 | 
			
		||||
        return response()->json($applications);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function application_by_uuid(Request $request)
 | 
			
		||||
    {
 | 
			
		||||
        $teamId = get_team_id_from_token();
 | 
			
		||||
        if (is_null($teamId)) {
 | 
			
		||||
            return invalid_token();
 | 
			
		||||
        }
 | 
			
		||||
        $uuid = $request->route('uuid');
 | 
			
		||||
        if (! $uuid) {
 | 
			
		||||
            return response()->json(['error' => 'UUID is required.'], 400);
 | 
			
		||||
        }
 | 
			
		||||
        $application = Application::where('uuid', $uuid)->first();
 | 
			
		||||
        if (! $application) {
 | 
			
		||||
            return response()->json(['error' => 'Application not found.'], 404);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return response()->json($application);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function update_by_uuid(Request $request)
 | 
			
		||||
    {
 | 
			
		||||
        $teamId = get_team_id_from_token();
 | 
			
		||||
        if (is_null($teamId)) {
 | 
			
		||||
            return invalid_token();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ($request->collect()->count() == 0) {
 | 
			
		||||
            return response()->json([
 | 
			
		||||
                'message' => 'No data provided.',
 | 
			
		||||
            ], 400);
 | 
			
		||||
        }
 | 
			
		||||
        $application = Application::where('uuid', $request->uuid)->first();
 | 
			
		||||
 | 
			
		||||
        if (! $application) {
 | 
			
		||||
            return response()->json([
 | 
			
		||||
                'success' => false,
 | 
			
		||||
                'message' => 'Application not found',
 | 
			
		||||
            ], 404);
 | 
			
		||||
        }
 | 
			
		||||
        ray($request->collect());
 | 
			
		||||
 | 
			
		||||
        // if ($request->has('domains')) {
 | 
			
		||||
        //     $existingDomains = explode(',', $application->fqdn);
 | 
			
		||||
        //     $newDomains = $request->domains;
 | 
			
		||||
        //     $filteredNewDomains = array_filter($newDomains, function ($domain) use ($existingDomains) {
 | 
			
		||||
        //         return ! in_array($domain, $existingDomains);
 | 
			
		||||
        //     });
 | 
			
		||||
        //     $mergedDomains = array_unique(array_merge($existingDomains, $filteredNewDomains));
 | 
			
		||||
        //     $application->fqdn = implode(',', $mergedDomains);
 | 
			
		||||
        //     $application->custom_labels = base64_encode(implode("\n ", generateLabelsApplication($application)));
 | 
			
		||||
        //     $application->save();
 | 
			
		||||
        // }
 | 
			
		||||
 | 
			
		||||
        return response()->json([
 | 
			
		||||
            'message' => 'Application updated successfully.',
 | 
			
		||||
            'application' => serialize_api_response($application),
 | 
			
		||||
        ]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function action_deploy(Request $request)
 | 
			
		||||
    {
 | 
			
		||||
        $teamId = get_team_id_from_token();
 | 
			
		||||
        if (is_null($teamId)) {
 | 
			
		||||
            return invalid_token();
 | 
			
		||||
        }
 | 
			
		||||
        $force = $request->query->get('force') ?? false;
 | 
			
		||||
        $instant_deploy = $request->query->get('instant_deploy') ?? false;
 | 
			
		||||
        $uuid = $request->route('uuid');
 | 
			
		||||
        if (! $uuid) {
 | 
			
		||||
            return response()->json(['error' => 'UUID is required.'], 400);
 | 
			
		||||
        }
 | 
			
		||||
        $application = Application::where('uuid', $uuid)->first();
 | 
			
		||||
        if (! $application) {
 | 
			
		||||
            return response()->json(['error' => 'Application not found.'], 404);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $deployment_uuid = new Cuid2(7);
 | 
			
		||||
 | 
			
		||||
        queue_application_deployment(
 | 
			
		||||
            application: $application,
 | 
			
		||||
            deployment_uuid: $deployment_uuid,
 | 
			
		||||
            force_rebuild: $force,
 | 
			
		||||
            is_api: true,
 | 
			
		||||
            no_questions_asked: $instant_deploy
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        return response()->json(
 | 
			
		||||
            [
 | 
			
		||||
                'message' => 'Deployment request queued.',
 | 
			
		||||
                'deployment_uuid' => $deployment_uuid->toString(),
 | 
			
		||||
                'deployment_api_url' => base_url().'/api/v1/deployment/'.$deployment_uuid->toString(),
 | 
			
		||||
            ],
 | 
			
		||||
            200
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function action_stop(Request $request)
 | 
			
		||||
    {
 | 
			
		||||
        $teamId = get_team_id_from_token();
 | 
			
		||||
        if (is_null($teamId)) {
 | 
			
		||||
            return invalid_token();
 | 
			
		||||
        }
 | 
			
		||||
        $uuid = $request->route('uuid');
 | 
			
		||||
        $sync = $request->query->get('sync') ?? false;
 | 
			
		||||
        if (! $uuid) {
 | 
			
		||||
            return response()->json(['error' => 'UUID is required.'], 400);
 | 
			
		||||
        }
 | 
			
		||||
        $application = Application::where('uuid', $uuid)->first();
 | 
			
		||||
        if (! $application) {
 | 
			
		||||
            return response()->json(['error' => 'Application not found.'], 404);
 | 
			
		||||
        }
 | 
			
		||||
        if ($sync) {
 | 
			
		||||
            StopApplication::run($application);
 | 
			
		||||
 | 
			
		||||
            return response()->json(['message' => 'Stopped the application.'], 200);
 | 
			
		||||
        } else {
 | 
			
		||||
            StopApplication::dispatch($application);
 | 
			
		||||
 | 
			
		||||
            return response()->json(['message' => 'Stopping request queued.'], 200);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function action_restart(Request $request)
 | 
			
		||||
    {
 | 
			
		||||
        $teamId = get_team_id_from_token();
 | 
			
		||||
        if (is_null($teamId)) {
 | 
			
		||||
            return invalid_token();
 | 
			
		||||
        }
 | 
			
		||||
        $uuid = $request->route('uuid');
 | 
			
		||||
        if (! $uuid) {
 | 
			
		||||
            return response()->json(['error' => 'UUID is required.'], 400);
 | 
			
		||||
        }
 | 
			
		||||
        $application = Application::where('uuid', $uuid)->first();
 | 
			
		||||
        if (! $application) {
 | 
			
		||||
            return response()->json(['error' => 'Application not found.'], 404);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $deployment_uuid = new Cuid2(7);
 | 
			
		||||
 | 
			
		||||
        queue_application_deployment(
 | 
			
		||||
            application: $application,
 | 
			
		||||
            deployment_uuid: $deployment_uuid,
 | 
			
		||||
            restart_only: true,
 | 
			
		||||
            is_api: true,
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        return response()->json(
 | 
			
		||||
            [
 | 
			
		||||
                'message' => 'Restart request queued.',
 | 
			
		||||
                'deployment_uuid' => $deployment_uuid->toString(),
 | 
			
		||||
                'deployment_api_url' => base_url().'/api/v1/deployment/'.$deployment_uuid->toString(),
 | 
			
		||||
            ],
 | 
			
		||||
            200
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -38,7 +38,25 @@ class Deploy extends Controller
 | 
			
		||||
            'status',
 | 
			
		||||
        ])->sortBy('id')->toArray();
 | 
			
		||||
 | 
			
		||||
        return response()->json($deployments_per_server, 200);
 | 
			
		||||
        return response()->json(serialize_api_response($deployments_per_server), 200);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function deployment_by_uuid(Request $request)
 | 
			
		||||
    {
 | 
			
		||||
        $teamId = get_team_id_from_token();
 | 
			
		||||
        if (is_null($teamId)) {
 | 
			
		||||
            return invalid_token();
 | 
			
		||||
        }
 | 
			
		||||
        $uuid = $request->route('uuid');
 | 
			
		||||
        if (! $uuid) {
 | 
			
		||||
            return response()->json(['error' => 'UUID is required.'], 400);
 | 
			
		||||
        }
 | 
			
		||||
        $deployment = ApplicationDeploymentQueue::where('deployment_uuid', $uuid)->first()->makeHidden('logs');
 | 
			
		||||
        if (! $deployment) {
 | 
			
		||||
            return response()->json(['error' => 'Deployment not found.'], 404);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return response()->json(serialize_api_response($deployment), 200);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function deploy(Request $request)
 | 
			
		||||
 
 | 
			
		||||
@@ -3,102 +3,52 @@
 | 
			
		||||
namespace App\Http\Controllers\Api;
 | 
			
		||||
 | 
			
		||||
use App\Http\Controllers\Controller;
 | 
			
		||||
use App\Models\InstanceSettings;
 | 
			
		||||
use App\Models\Project as ModelsProject;
 | 
			
		||||
use App\Models\Application;
 | 
			
		||||
use Illuminate\Http\Request;
 | 
			
		||||
use Illuminate\Support\Facades\Validator;
 | 
			
		||||
 | 
			
		||||
class Domains extends Controller
 | 
			
		||||
{
 | 
			
		||||
    public function domains(Request $request)
 | 
			
		||||
    public function deleteDomains(Request $request)
 | 
			
		||||
    {
 | 
			
		||||
        $teamId = get_team_id_from_token();
 | 
			
		||||
        if (is_null($teamId)) {
 | 
			
		||||
            return invalid_token();
 | 
			
		||||
        }
 | 
			
		||||
        $projects = ModelsProject::where('team_id', $teamId)->get();
 | 
			
		||||
        $domains = collect();
 | 
			
		||||
        $applications = $projects->pluck('applications')->flatten();
 | 
			
		||||
        $settings = InstanceSettings::get();
 | 
			
		||||
        if ($applications->count() > 0) {
 | 
			
		||||
            foreach ($applications as $application) {
 | 
			
		||||
                $ip = $application->destination->server->ip;
 | 
			
		||||
                $fqdn = str($application->fqdn)->explode(',')->map(function ($fqdn) {
 | 
			
		||||
                    return str($fqdn)->replace('http://', '')->replace('https://', '')->replace('/', '');
 | 
			
		||||
                });
 | 
			
		||||
                if ($ip === 'host.docker.internal') {
 | 
			
		||||
                    if ($settings->public_ipv4) {
 | 
			
		||||
                        $domains->push([
 | 
			
		||||
                            'domain' => $fqdn,
 | 
			
		||||
                            'ip' => $settings->public_ipv4,
 | 
			
		||||
                        ]);
 | 
			
		||||
                    }
 | 
			
		||||
                    if ($settings->public_ipv6) {
 | 
			
		||||
                        $domains->push([
 | 
			
		||||
                            'domain' => $fqdn,
 | 
			
		||||
                            'ip' => $settings->public_ipv6,
 | 
			
		||||
                        ]);
 | 
			
		||||
                    }
 | 
			
		||||
                    if (! $settings->public_ipv4 && ! $settings->public_ipv6) {
 | 
			
		||||
                        $domains->push([
 | 
			
		||||
                            'domain' => $fqdn,
 | 
			
		||||
                            'ip' => $ip,
 | 
			
		||||
                        ]);
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    $domains->push([
 | 
			
		||||
                        'domain' => $fqdn,
 | 
			
		||||
                        'ip' => $ip,
 | 
			
		||||
                    ]);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        $services = $projects->pluck('services')->flatten();
 | 
			
		||||
        if ($services->count() > 0) {
 | 
			
		||||
            foreach ($services as $service) {
 | 
			
		||||
                $service_applications = $service->applications;
 | 
			
		||||
                if ($service_applications->count() > 0) {
 | 
			
		||||
                    foreach ($service_applications as $application) {
 | 
			
		||||
                        $fqdn = str($application->fqdn)->explode(',')->map(function ($fqdn) {
 | 
			
		||||
                            return str($fqdn)->replace('http://', '')->replace('https://', '')->replace('/', '');
 | 
			
		||||
                        });
 | 
			
		||||
                        if ($ip === 'host.docker.internal') {
 | 
			
		||||
                            if ($settings->public_ipv4) {
 | 
			
		||||
                                $domains->push([
 | 
			
		||||
                                    'domain' => $fqdn,
 | 
			
		||||
                                    'ip' => $settings->public_ipv4,
 | 
			
		||||
                                ]);
 | 
			
		||||
                            }
 | 
			
		||||
                            if ($settings->public_ipv6) {
 | 
			
		||||
                                $domains->push([
 | 
			
		||||
                                    'domain' => $fqdn,
 | 
			
		||||
                                    'ip' => $settings->public_ipv6,
 | 
			
		||||
                                ]);
 | 
			
		||||
                            }
 | 
			
		||||
                            if (! $settings->public_ipv4 && ! $settings->public_ipv6) {
 | 
			
		||||
                                $domains->push([
 | 
			
		||||
                                    'domain' => $fqdn,
 | 
			
		||||
                                    'ip' => $ip,
 | 
			
		||||
                                ]);
 | 
			
		||||
                            }
 | 
			
		||||
                        } else {
 | 
			
		||||
                            $domains->push([
 | 
			
		||||
                                'domain' => $fqdn,
 | 
			
		||||
                                'ip' => $ip,
 | 
			
		||||
                            ]);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        $domains = $domains->groupBy('ip')->map(function ($domain) {
 | 
			
		||||
            return $domain->pluck('domain')->flatten();
 | 
			
		||||
        })->map(function ($domain, $ip) {
 | 
			
		||||
            return [
 | 
			
		||||
                'ip' => $ip,
 | 
			
		||||
                'domains' => $domain,
 | 
			
		||||
            ];
 | 
			
		||||
        })->values();
 | 
			
		||||
        $validator = Validator::make($request->all(), [
 | 
			
		||||
            'uuid' => 'required|string|exists:applications,uuid',
 | 
			
		||||
            'domains' => 'required|array',
 | 
			
		||||
            'domains.*' => 'required|string|distinct',
 | 
			
		||||
        ]);
 | 
			
		||||
 | 
			
		||||
        return response()->json($domains);
 | 
			
		||||
        if ($validator->fails()) {
 | 
			
		||||
            return response()->json([
 | 
			
		||||
                'success' => false,
 | 
			
		||||
                'message' => 'Validation failed',
 | 
			
		||||
                'errors' => $validator->errors(),
 | 
			
		||||
            ], 422);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $application = Application::where('uuid', $request->uuid)->first();
 | 
			
		||||
 | 
			
		||||
        if (! $application) {
 | 
			
		||||
            return response()->json([
 | 
			
		||||
                'success' => false,
 | 
			
		||||
                'message' => 'Application not found',
 | 
			
		||||
            ], 404);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $existingDomains = explode(',', $application->fqdn);
 | 
			
		||||
        $domainsToDelete = $request->domains;
 | 
			
		||||
        $updatedDomains = array_diff($existingDomains, $domainsToDelete);
 | 
			
		||||
        $application->fqdn = implode(',', $updatedDomains);
 | 
			
		||||
        $application->custom_labels = base64_encode(implode("\n ", generateLabelsApplication($application)));
 | 
			
		||||
        $application->save();
 | 
			
		||||
 | 
			
		||||
        return response()->json([
 | 
			
		||||
            'success' => true,
 | 
			
		||||
            'message' => 'Domains updated successfully',
 | 
			
		||||
            'application' => $application,
 | 
			
		||||
        ]);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,9 @@
 | 
			
		||||
namespace App\Http\Controllers\Api;
 | 
			
		||||
 | 
			
		||||
use App\Http\Controllers\Controller;
 | 
			
		||||
use App\Models\Application;
 | 
			
		||||
use App\Models\InstanceSettings;
 | 
			
		||||
use App\Models\Project;
 | 
			
		||||
use App\Models\Server as ModelsServer;
 | 
			
		||||
use Illuminate\Http\Request;
 | 
			
		||||
 | 
			
		||||
@@ -59,4 +62,106 @@ class Server extends Controller
 | 
			
		||||
 | 
			
		||||
        return response()->json($server);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function get_domains_by_server(Request $request)
 | 
			
		||||
    {
 | 
			
		||||
        $teamId = get_team_id_from_token();
 | 
			
		||||
        if (is_null($teamId)) {
 | 
			
		||||
            return invalid_token();
 | 
			
		||||
        }
 | 
			
		||||
        $uuid = $request->query->get('uuid');
 | 
			
		||||
        if ($uuid) {
 | 
			
		||||
            $domains = Application::getDomainsByUuid($uuid);
 | 
			
		||||
 | 
			
		||||
            return response()->json([
 | 
			
		||||
                'uuid' => $uuid,
 | 
			
		||||
                'domains' => $domains,
 | 
			
		||||
            ]);
 | 
			
		||||
        }
 | 
			
		||||
        $projects = Project::where('team_id', $teamId)->get();
 | 
			
		||||
        $domains = collect();
 | 
			
		||||
        $applications = $projects->pluck('applications')->flatten();
 | 
			
		||||
        $settings = InstanceSettings::get();
 | 
			
		||||
        if ($applications->count() > 0) {
 | 
			
		||||
            foreach ($applications as $application) {
 | 
			
		||||
                $ip = $application->destination->server->ip;
 | 
			
		||||
                $fqdn = str($application->fqdn)->explode(',')->map(function ($fqdn) {
 | 
			
		||||
                    return str($fqdn)->replace('http://', '')->replace('https://', '')->replace('/', '');
 | 
			
		||||
                });
 | 
			
		||||
                if ($ip === 'host.docker.internal') {
 | 
			
		||||
                    if ($settings->public_ipv4) {
 | 
			
		||||
                        $domains->push([
 | 
			
		||||
                            'domain' => $fqdn,
 | 
			
		||||
                            'ip' => $settings->public_ipv4,
 | 
			
		||||
                        ]);
 | 
			
		||||
                    }
 | 
			
		||||
                    if ($settings->public_ipv6) {
 | 
			
		||||
                        $domains->push([
 | 
			
		||||
                            'domain' => $fqdn,
 | 
			
		||||
                            'ip' => $settings->public_ipv6,
 | 
			
		||||
                        ]);
 | 
			
		||||
                    }
 | 
			
		||||
                    if (! $settings->public_ipv4 && ! $settings->public_ipv6) {
 | 
			
		||||
                        $domains->push([
 | 
			
		||||
                            'domain' => $fqdn,
 | 
			
		||||
                            'ip' => $ip,
 | 
			
		||||
                        ]);
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    $domains->push([
 | 
			
		||||
                        'domain' => $fqdn,
 | 
			
		||||
                        'ip' => $ip,
 | 
			
		||||
                    ]);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        $services = $projects->pluck('services')->flatten();
 | 
			
		||||
        if ($services->count() > 0) {
 | 
			
		||||
            foreach ($services as $service) {
 | 
			
		||||
                $service_applications = $service->applications;
 | 
			
		||||
                if ($service_applications->count() > 0) {
 | 
			
		||||
                    foreach ($service_applications as $application) {
 | 
			
		||||
                        $fqdn = str($application->fqdn)->explode(',')->map(function ($fqdn) {
 | 
			
		||||
                            return str($fqdn)->replace('http://', '')->replace('https://', '')->replace('/', '');
 | 
			
		||||
                        });
 | 
			
		||||
                        if ($ip === 'host.docker.internal') {
 | 
			
		||||
                            if ($settings->public_ipv4) {
 | 
			
		||||
                                $domains->push([
 | 
			
		||||
                                    'domain' => $fqdn,
 | 
			
		||||
                                    'ip' => $settings->public_ipv4,
 | 
			
		||||
                                ]);
 | 
			
		||||
                            }
 | 
			
		||||
                            if ($settings->public_ipv6) {
 | 
			
		||||
                                $domains->push([
 | 
			
		||||
                                    'domain' => $fqdn,
 | 
			
		||||
                                    'ip' => $settings->public_ipv6,
 | 
			
		||||
                                ]);
 | 
			
		||||
                            }
 | 
			
		||||
                            if (! $settings->public_ipv4 && ! $settings->public_ipv6) {
 | 
			
		||||
                                $domains->push([
 | 
			
		||||
                                    'domain' => $fqdn,
 | 
			
		||||
                                    'ip' => $ip,
 | 
			
		||||
                                ]);
 | 
			
		||||
                            }
 | 
			
		||||
                        } else {
 | 
			
		||||
                            $domains->push([
 | 
			
		||||
                                'domain' => $fqdn,
 | 
			
		||||
                                'ip' => $ip,
 | 
			
		||||
                            ]);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        $domains = $domains->groupBy('ip')->map(function ($domain) {
 | 
			
		||||
            return $domain->pluck('domain')->flatten();
 | 
			
		||||
        })->map(function ($domain, $ip) {
 | 
			
		||||
            return [
 | 
			
		||||
                'ip' => $ip,
 | 
			
		||||
                'domains' => $domain,
 | 
			
		||||
            ];
 | 
			
		||||
        })->values();
 | 
			
		||||
 | 
			
		||||
        return response()->json($domains);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,8 +2,10 @@
 | 
			
		||||
 | 
			
		||||
namespace App\Http\Controllers;
 | 
			
		||||
 | 
			
		||||
use App\Models\InstanceSettings;
 | 
			
		||||
use App\Models\User;
 | 
			
		||||
use Illuminate\Support\Facades\Auth;
 | 
			
		||||
use Symfony\Component\HttpKernel\Exception\HttpException;
 | 
			
		||||
 | 
			
		||||
class OauthController extends Controller
 | 
			
		||||
{
 | 
			
		||||
@@ -20,6 +22,11 @@ class OauthController extends Controller
 | 
			
		||||
            $oauthUser = get_socialite_provider($provider)->user();
 | 
			
		||||
            $user = User::whereEmail($oauthUser->email)->first();
 | 
			
		||||
            if (! $user) {
 | 
			
		||||
                $settings = InstanceSettings::get();
 | 
			
		||||
                if (! $settings->is_registration_enabled) {
 | 
			
		||||
                    abort(403, 'Registration is disabled');
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                $user = User::create([
 | 
			
		||||
                    'name' => $oauthUser->name,
 | 
			
		||||
                    'email' => $oauthUser->email,
 | 
			
		||||
@@ -31,7 +38,9 @@ class OauthController extends Controller
 | 
			
		||||
        } catch (\Exception $e) {
 | 
			
		||||
            ray($e->getMessage());
 | 
			
		||||
 | 
			
		||||
            return redirect()->route('login')->withErrors([__('auth.failed.callback')]);
 | 
			
		||||
            $errorCode = $e instanceof HttpException ? 'auth.failed' : 'auth.failed.callback';
 | 
			
		||||
 | 
			
		||||
            return redirect()->route('login')->withErrors([__($errorCode)]);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -72,14 +72,14 @@ class Stripe extends Controller
 | 
			
		||||
                    }
 | 
			
		||||
                    $subscription = Subscription::where('team_id', $teamId)->first();
 | 
			
		||||
                    if ($subscription) {
 | 
			
		||||
                        send_internal_notification('Old subscription activated for team: '.$teamId);
 | 
			
		||||
                        // send_internal_notification('Old subscription activated for team: '.$teamId);
 | 
			
		||||
                        $subscription->update([
 | 
			
		||||
                            'stripe_subscription_id' => $subscriptionId,
 | 
			
		||||
                            'stripe_customer_id' => $customerId,
 | 
			
		||||
                            'stripe_invoice_paid' => true,
 | 
			
		||||
                        ]);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        send_internal_notification('New subscription for team: '.$teamId);
 | 
			
		||||
                        // send_internal_notification('New subscription for team: '.$teamId);
 | 
			
		||||
                        Subscription::create([
 | 
			
		||||
                            'team_id' => $teamId,
 | 
			
		||||
                            'stripe_subscription_id' => $subscriptionId,
 | 
			
		||||
@@ -92,7 +92,7 @@ class Stripe extends Controller
 | 
			
		||||
                    $customerId = data_get($data, 'customer');
 | 
			
		||||
                    $planId = data_get($data, 'lines.data.0.plan.id');
 | 
			
		||||
                    if (Str::contains($excludedPlans, $planId)) {
 | 
			
		||||
                        send_internal_notification('Subscription excluded.');
 | 
			
		||||
                        // send_internal_notification('Subscription excluded.');
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                    $subscription = Subscription::where('stripe_customer_id', $customerId)->first();
 | 
			
		||||
@@ -108,33 +108,33 @@ class Stripe extends Controller
 | 
			
		||||
                    $customerId = data_get($data, 'customer');
 | 
			
		||||
                    $subscription = Subscription::where('stripe_customer_id', $customerId)->first();
 | 
			
		||||
                    if (! $subscription) {
 | 
			
		||||
                        send_internal_notification('invoice.payment_failed failed but no subscription found in Coolify for customer: '.$customerId);
 | 
			
		||||
                        // send_internal_notification('invoice.payment_failed failed but no subscription found in Coolify for customer: '.$customerId);
 | 
			
		||||
 | 
			
		||||
                        return response('No subscription found in Coolify.');
 | 
			
		||||
                    }
 | 
			
		||||
                    $team = data_get($subscription, 'team');
 | 
			
		||||
                    if (! $team) {
 | 
			
		||||
                        send_internal_notification('invoice.payment_failed failed but no team found in Coolify for customer: '.$customerId);
 | 
			
		||||
                        // send_internal_notification('invoice.payment_failed failed but no team found in Coolify for customer: '.$customerId);
 | 
			
		||||
 | 
			
		||||
                        return response('No team found in Coolify.');
 | 
			
		||||
                    }
 | 
			
		||||
                    if (! $subscription->stripe_invoice_paid) {
 | 
			
		||||
                        SubscriptionInvoiceFailedJob::dispatch($team);
 | 
			
		||||
                        send_internal_notification('Invoice payment failed: '.$customerId);
 | 
			
		||||
                        // send_internal_notification('Invoice payment failed: '.$customerId);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        send_internal_notification('Invoice payment failed but already paid: '.$customerId);
 | 
			
		||||
                        // send_internal_notification('Invoice payment failed but already paid: '.$customerId);
 | 
			
		||||
                    }
 | 
			
		||||
                    break;
 | 
			
		||||
                case 'payment_intent.payment_failed':
 | 
			
		||||
                    $customerId = data_get($data, 'customer');
 | 
			
		||||
                    $subscription = Subscription::where('stripe_customer_id', $customerId)->first();
 | 
			
		||||
                    if (! $subscription) {
 | 
			
		||||
                        send_internal_notification('payment_intent.payment_failed, no subscription found in Coolify for customer: '.$customerId);
 | 
			
		||||
                        // send_internal_notification('payment_intent.payment_failed, no subscription found in Coolify for customer: '.$customerId);
 | 
			
		||||
 | 
			
		||||
                        return response('No subscription found in Coolify.');
 | 
			
		||||
                    }
 | 
			
		||||
                    if ($subscription->stripe_invoice_paid) {
 | 
			
		||||
                        send_internal_notification('payment_intent.payment_failed but invoice is active for customer: '.$customerId);
 | 
			
		||||
                        // send_internal_notification('payment_intent.payment_failed but invoice is active for customer: '.$customerId);
 | 
			
		||||
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
@@ -146,7 +146,7 @@ class Stripe extends Controller
 | 
			
		||||
                    $subscriptionId = data_get($data, 'items.data.0.subscription');
 | 
			
		||||
                    $planId = data_get($data, 'items.data.0.plan.id');
 | 
			
		||||
                    if (Str::contains($excludedPlans, $planId)) {
 | 
			
		||||
                        send_internal_notification('Subscription excluded.');
 | 
			
		||||
                        // send_internal_notification('Subscription excluded.');
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                    $subscription = Subscription::where('stripe_customer_id', $customerId)->first();
 | 
			
		||||
@@ -156,11 +156,11 @@ class Stripe extends Controller
 | 
			
		||||
                    }
 | 
			
		||||
                    if (! $subscription) {
 | 
			
		||||
                        if ($status === 'incomplete_expired') {
 | 
			
		||||
                            send_internal_notification('Subscription incomplete expired for customer: '.$customerId);
 | 
			
		||||
                            // send_internal_notification('Subscription incomplete expired for customer: '.$customerId);
 | 
			
		||||
 | 
			
		||||
                            return response('Subscription incomplete expired', 200);
 | 
			
		||||
                        }
 | 
			
		||||
                        send_internal_notification('No subscription found for: '.$customerId);
 | 
			
		||||
                        // send_internal_notification('No subscription found for: '.$customerId);
 | 
			
		||||
 | 
			
		||||
                        return response('No subscription found', 400);
 | 
			
		||||
                    }
 | 
			
		||||
@@ -194,7 +194,7 @@ class Stripe extends Controller
 | 
			
		||||
                        $subscription->update([
 | 
			
		||||
                            'stripe_invoice_paid' => false,
 | 
			
		||||
                        ]);
 | 
			
		||||
                        send_internal_notification('Subscription paused or incomplete for customer: '.$customerId);
 | 
			
		||||
                        // send_internal_notification('Subscription paused or incomplete for customer: '.$customerId);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // Trial ended but subscribed, reactive servers
 | 
			
		||||
@@ -208,13 +208,13 @@ class Stripe extends Controller
 | 
			
		||||
                        if ($comment) {
 | 
			
		||||
                            $reason .= ' with comment: \''.$comment."'";
 | 
			
		||||
                        }
 | 
			
		||||
                        send_internal_notification($reason);
 | 
			
		||||
                        // send_internal_notification($reason);
 | 
			
		||||
                    }
 | 
			
		||||
                    if ($alreadyCancelAtPeriodEnd !== $cancelAtPeriodEnd) {
 | 
			
		||||
                        if ($cancelAtPeriodEnd) {
 | 
			
		||||
                            // send_internal_notification('Subscription cancelled at period end for team: ' . $subscription->team->id);
 | 
			
		||||
                        } else {
 | 
			
		||||
                            send_internal_notification('customer.subscription.updated for customer: '.$customerId);
 | 
			
		||||
                            // send_internal_notification('customer.subscription.updated for customer: '.$customerId);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    break;
 | 
			
		||||
@@ -233,7 +233,7 @@ class Stripe extends Controller
 | 
			
		||||
                        'stripe_invoice_paid' => false,
 | 
			
		||||
                        'stripe_trial_already_ended' => true,
 | 
			
		||||
                    ]);
 | 
			
		||||
                    send_internal_notification('customer.subscription.deleted for customer: '.$customerId);
 | 
			
		||||
                    // send_internal_notification('customer.subscription.deleted for customer: '.$customerId);
 | 
			
		||||
                    break;
 | 
			
		||||
                case 'customer.subscription.trial_will_end':
 | 
			
		||||
                    // Not used for now
 | 
			
		||||
@@ -258,7 +258,7 @@ class Stripe extends Controller
 | 
			
		||||
                        'stripe_invoice_paid' => false,
 | 
			
		||||
                    ]);
 | 
			
		||||
                    SubscriptionTrialEndedJob::dispatch($team);
 | 
			
		||||
                    send_internal_notification('Subscription paused for customer: '.$customerId);
 | 
			
		||||
                    // send_internal_notification('Subscription paused for customer: '.$customerId);
 | 
			
		||||
                    break;
 | 
			
		||||
                default:
 | 
			
		||||
                    // Unhandled event type
 | 
			
		||||
 
 | 
			
		||||
@@ -340,7 +340,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
 | 
			
		||||
    private function post_deployment()
 | 
			
		||||
    {
 | 
			
		||||
        if ($this->server->isProxyShouldRun()) {
 | 
			
		||||
            GetContainersStatus::dispatch($this->server);
 | 
			
		||||
            GetContainersStatus::dispatch($this->server)->onQueue('high');
 | 
			
		||||
            // dispatch(new ContainerStatusJob($this->server));
 | 
			
		||||
        }
 | 
			
		||||
        $this->next(ApplicationDeploymentStatus::FINISHED->value);
 | 
			
		||||
@@ -828,6 +828,9 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
 | 
			
		||||
            if ($this->application->environment_variables_preview->where('key', 'COOLIFY_BRANCH')->isEmpty()) {
 | 
			
		||||
                $envs->push("COOLIFY_BRANCH={$local_branch}");
 | 
			
		||||
            }
 | 
			
		||||
            if ($this->application->environment_variables_preview->where('key', 'COOLIFY_CONTAINER_NAME')->isEmpty()) {
 | 
			
		||||
                $envs->push("COOLIFY_CONTAINER_NAME={$this->container_name}");
 | 
			
		||||
            }
 | 
			
		||||
            foreach ($sorted_environment_variables_preview as $env) {
 | 
			
		||||
                $real_value = $env->real_value;
 | 
			
		||||
                if ($env->version === '4.0.0-beta.239') {
 | 
			
		||||
@@ -869,6 +872,9 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
 | 
			
		||||
            if ($this->application->environment_variables->where('key', 'COOLIFY_BRANCH')->isEmpty()) {
 | 
			
		||||
                $envs->push("COOLIFY_BRANCH={$local_branch}");
 | 
			
		||||
            }
 | 
			
		||||
            if ($this->application->environment_variables->where('key', 'COOLIFY_CONTAINER_NAME')->isEmpty()) {
 | 
			
		||||
                $envs->push("COOLIFY_CONTAINER_NAME={$this->container_name}");
 | 
			
		||||
            }
 | 
			
		||||
            foreach ($sorted_environment_variables as $env) {
 | 
			
		||||
                $real_value = $env->real_value;
 | 
			
		||||
                if ($env->version === '4.0.0-beta.239') {
 | 
			
		||||
@@ -1863,12 +1869,12 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
 | 
			
		||||
                        $this->execute_remote_command([
 | 
			
		||||
                            executeInDocker($this->deployment_uuid, "nixpacks build -c /artifacts/thegameplan.json --no-cache --no-error-without-start -n {$this->build_image_name} {$this->workdir} -o {$this->workdir}"), 'hidden' => true,
 | 
			
		||||
                        ]);
 | 
			
		||||
                        $build_command = "docker build --no-cache {$this->addHosts} --network host -f {$this->workdir}/.nixpacks/Dockerfile {$this->build_args} --progress plain -t {$this->production_image_name} {$this->workdir}";
 | 
			
		||||
                        $build_command = "docker build --no-cache {$this->addHosts} --network host -f {$this->workdir}/.nixpacks/Dockerfile {$this->build_args} --progress plain -t {$this->build_image_name} {$this->workdir}";
 | 
			
		||||
                    } else {
 | 
			
		||||
                        $this->execute_remote_command([
 | 
			
		||||
                            executeInDocker($this->deployment_uuid, "nixpacks build -c /artifacts/thegameplan.json --cache-key '{$this->application->uuid}' --no-error-without-start -n {$this->build_image_name} {$this->workdir} -o {$this->workdir}"), 'hidden' => true,
 | 
			
		||||
                        ]);
 | 
			
		||||
                        $build_command = "docker build {$this->addHosts} --network host -f {$this->workdir}/.nixpacks/Dockerfile {$this->build_args} --progress plain -t {$this->production_image_name} {$this->workdir}";
 | 
			
		||||
                        $build_command = "docker build {$this->addHosts} --network host -f {$this->workdir}/.nixpacks/Dockerfile {$this->build_args} --progress plain -t {$this->build_image_name} {$this->workdir}";
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    $base64_build_command = base64_encode($build_command);
 | 
			
		||||
@@ -1898,7 +1904,6 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
 | 
			
		||||
                        ]
 | 
			
		||||
                    );
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                $dockerfile = base64_encode("FROM {$this->application->static_image}
 | 
			
		||||
WORKDIR /usr/share/nginx/html/
 | 
			
		||||
LABEL coolify.deploymentId={$this->deployment_uuid}
 | 
			
		||||
 
 | 
			
		||||
@@ -25,8 +25,7 @@ class ApplicationPullRequestUpdateJob implements ShouldBeEncrypted, ShouldQueue
 | 
			
		||||
        public ApplicationPreview $preview,
 | 
			
		||||
        public ProcessStatus $status,
 | 
			
		||||
        public ?string $deployment_uuid = null
 | 
			
		||||
    ) {
 | 
			
		||||
    }
 | 
			
		||||
    ) {}
 | 
			
		||||
 | 
			
		||||
    public function handle()
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -19,9 +19,7 @@ class CheckLogDrainContainerJob implements ShouldBeEncrypted, ShouldQueue
 | 
			
		||||
{
 | 
			
		||||
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
 | 
			
		||||
 | 
			
		||||
    public function __construct(public Server $server)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    public function __construct(public Server $server) {}
 | 
			
		||||
 | 
			
		||||
    public function middleware(): array
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -14,9 +14,7 @@ class CheckResaleLicenseJob implements ShouldBeEncrypted, ShouldQueue
 | 
			
		||||
{
 | 
			
		||||
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
 | 
			
		||||
 | 
			
		||||
    public function __construct()
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    public function __construct() {}
 | 
			
		||||
 | 
			
		||||
    public function handle(): void
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -15,9 +15,7 @@ class CleanupHelperContainersJob implements ShouldBeEncrypted, ShouldBeUnique, S
 | 
			
		||||
{
 | 
			
		||||
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
 | 
			
		||||
 | 
			
		||||
    public function __construct(public Server $server)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    public function __construct(public Server $server) {}
 | 
			
		||||
 | 
			
		||||
    public function handle(): void
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -16,10 +16,7 @@ class CleanupInstanceStuffsJob implements ShouldBeEncrypted, ShouldBeUnique, Sho
 | 
			
		||||
{
 | 
			
		||||
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
 | 
			
		||||
 | 
			
		||||
    public function __construct()
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
    public function __construct() {}
 | 
			
		||||
 | 
			
		||||
    // public function uniqueId(): string
 | 
			
		||||
    // {
 | 
			
		||||
 
 | 
			
		||||
@@ -23,9 +23,7 @@ class ContainerStatusJob implements ShouldBeEncrypted, ShouldQueue
 | 
			
		||||
        return isDev() ? 1 : 3;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function __construct(public Server $server)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    public function __construct(public Server $server) {}
 | 
			
		||||
 | 
			
		||||
    public function middleware(): array
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -23,8 +23,7 @@ class CoolifyTask implements ShouldBeEncrypted, ShouldQueue
 | 
			
		||||
        public bool $ignore_errors = false,
 | 
			
		||||
        public $call_event_on_finish = null,
 | 
			
		||||
        public $call_event_data = null
 | 
			
		||||
    ) {
 | 
			
		||||
    }
 | 
			
		||||
    ) {}
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Execute the job.
 | 
			
		||||
 
 | 
			
		||||
@@ -18,9 +18,7 @@ class DatabaseBackupStatusJob implements ShouldBeEncrypted, ShouldQueue
 | 
			
		||||
 | 
			
		||||
    public $tries = 1;
 | 
			
		||||
 | 
			
		||||
    public function __construct()
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    public function __construct() {}
 | 
			
		||||
 | 
			
		||||
    public function handle()
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -28,9 +28,7 @@ class DeleteResourceJob implements ShouldBeEncrypted, ShouldQueue
 | 
			
		||||
{
 | 
			
		||||
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
 | 
			
		||||
 | 
			
		||||
    public function __construct(public Application|Service|StandalonePostgresql|StandaloneRedis|StandaloneMongodb|StandaloneMysql|StandaloneMariadb|StandaloneKeydb|StandaloneDragonfly|StandaloneClickhouse $resource, public bool $deleteConfigurations = false)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    public function __construct(public Application|Service|StandalonePostgresql|StandaloneRedis|StandaloneMongodb|StandaloneMysql|StandaloneMariadb|StandaloneKeydb|StandaloneDragonfly|StandaloneClickhouse $resource, public bool $deleteConfigurations = false) {}
 | 
			
		||||
 | 
			
		||||
    public function handle()
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -22,9 +22,7 @@ class DockerCleanupJob implements ShouldBeEncrypted, ShouldQueue
 | 
			
		||||
 | 
			
		||||
    public ?int $usageBefore = null;
 | 
			
		||||
 | 
			
		||||
    public function __construct(public Server $server)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    public function __construct(public Server $server) {}
 | 
			
		||||
 | 
			
		||||
    public function handle(): void
 | 
			
		||||
    {
 | 
			
		||||
@@ -62,7 +60,7 @@ class DockerCleanupJob implements ShouldBeEncrypted, ShouldQueue
 | 
			
		||||
                Log::info('No need to clean up '.$this->server->name);
 | 
			
		||||
            }
 | 
			
		||||
        } catch (\Throwable $e) {
 | 
			
		||||
            send_internal_notification('DockerCleanupJob failed with: '.$e->getMessage());
 | 
			
		||||
            // send_internal_notification('DockerCleanupJob failed with: '.$e->getMessage());
 | 
			
		||||
            ray($e->getMessage());
 | 
			
		||||
            throw $e;
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -23,9 +23,7 @@ class GithubAppPermissionJob implements ShouldBeEncrypted, ShouldQueue
 | 
			
		||||
        return isDev() ? 1 : 3;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function __construct(public GithubApp $github_app)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    public function __construct(public GithubApp $github_app) {}
 | 
			
		||||
 | 
			
		||||
    public function middleware(): array
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -19,9 +19,7 @@ class InstanceAutoUpdateJob implements ShouldBeEncrypted, ShouldBeUnique, Should
 | 
			
		||||
 | 
			
		||||
    public $tries = 1;
 | 
			
		||||
 | 
			
		||||
    public function __construct()
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    public function __construct() {}
 | 
			
		||||
 | 
			
		||||
    public function handle(): void
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -19,9 +19,7 @@ class PullCoolifyImageJob implements ShouldBeEncrypted, ShouldQueue
 | 
			
		||||
 | 
			
		||||
    public $timeout = 1000;
 | 
			
		||||
 | 
			
		||||
    public function __construct()
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    public function __construct() {}
 | 
			
		||||
 | 
			
		||||
    public function handle(): void
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -27,9 +27,7 @@ class PullHelperImageJob implements ShouldBeEncrypted, ShouldQueue
 | 
			
		||||
        return $this->server->uuid;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function __construct(public Server $server)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    public function __construct(public Server $server) {}
 | 
			
		||||
 | 
			
		||||
    public function handle(): void
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -28,9 +28,7 @@ class PullSentinelImageJob implements ShouldBeEncrypted, ShouldQueue
 | 
			
		||||
        return $this->server->uuid;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function __construct(public Server $server)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    public function __construct(public Server $server) {}
 | 
			
		||||
 | 
			
		||||
    public function handle(): void
 | 
			
		||||
    {
 | 
			
		||||
@@ -52,7 +50,7 @@ class PullSentinelImageJob implements ShouldBeEncrypted, ShouldQueue
 | 
			
		||||
            }
 | 
			
		||||
            ray('Sentinel image is up to date');
 | 
			
		||||
        } catch (\Throwable $e) {
 | 
			
		||||
            send_internal_notification('PullSentinelImageJob failed with: '.$e->getMessage());
 | 
			
		||||
            // send_internal_notification('PullSentinelImageJob failed with: '.$e->getMessage());
 | 
			
		||||
            ray($e->getMessage());
 | 
			
		||||
            throw $e;
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -17,9 +17,7 @@ class PullTemplatesFromCDN implements ShouldBeEncrypted, ShouldQueue
 | 
			
		||||
 | 
			
		||||
    public $timeout = 10;
 | 
			
		||||
 | 
			
		||||
    public function __construct()
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    public function __construct() {}
 | 
			
		||||
 | 
			
		||||
    public function handle(): void
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -17,9 +17,7 @@ class PullVersionsFromCDN implements ShouldBeEncrypted, ShouldQueue
 | 
			
		||||
 | 
			
		||||
    public $timeout = 10;
 | 
			
		||||
 | 
			
		||||
    public function __construct()
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    public function __construct() {}
 | 
			
		||||
 | 
			
		||||
    public function handle(): void
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -14,9 +14,7 @@ class SendConfirmationForWaitlistJob implements ShouldBeEncrypted, ShouldQueue
 | 
			
		||||
{
 | 
			
		||||
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
 | 
			
		||||
 | 
			
		||||
    public function __construct(public string $email, public string $uuid)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    public function __construct(public string $email, public string $uuid) {}
 | 
			
		||||
 | 
			
		||||
    public function handle()
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -31,8 +31,7 @@ class SendMessageToDiscordJob implements ShouldBeEncrypted, ShouldQueue
 | 
			
		||||
    public function __construct(
 | 
			
		||||
        public string $text,
 | 
			
		||||
        public string $webhookUrl
 | 
			
		||||
    ) {
 | 
			
		||||
    }
 | 
			
		||||
    ) {}
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Execute the job.
 | 
			
		||||
 
 | 
			
		||||
@@ -33,8 +33,7 @@ class SendMessageToTelegramJob implements ShouldBeEncrypted, ShouldQueue
 | 
			
		||||
        public string $token,
 | 
			
		||||
        public string $chatId,
 | 
			
		||||
        public ?string $topicId = null,
 | 
			
		||||
    ) {
 | 
			
		||||
    }
 | 
			
		||||
    ) {}
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Execute the job.
 | 
			
		||||
 
 | 
			
		||||
@@ -16,9 +16,7 @@ class ServerFilesFromServerJob implements ShouldBeEncrypted, ShouldQueue
 | 
			
		||||
{
 | 
			
		||||
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
 | 
			
		||||
 | 
			
		||||
    public function __construct(public ServiceApplication|ServiceDatabase|Application $resource)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    public function __construct(public ServiceApplication|ServiceDatabase|Application $resource) {}
 | 
			
		||||
 | 
			
		||||
    public function handle()
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -24,9 +24,7 @@ class ServerLimitCheckJob implements ShouldBeEncrypted, ShouldQueue
 | 
			
		||||
        return isDev() ? 1 : 3;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function __construct(public Team $team)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    public function __construct(public Team $team) {}
 | 
			
		||||
 | 
			
		||||
    public function middleware(): array
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -25,9 +25,7 @@ class ServerStatusJob implements ShouldBeEncrypted, ShouldQueue
 | 
			
		||||
        return isDev() ? 1 : 3;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function __construct(public Server $server)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    public function __construct(public Server $server) {}
 | 
			
		||||
 | 
			
		||||
    public function middleware(): array
 | 
			
		||||
    {
 | 
			
		||||
@@ -48,7 +46,7 @@ class ServerStatusJob implements ShouldBeEncrypted, ShouldQueue
 | 
			
		||||
            if ($this->server->isFunctional()) {
 | 
			
		||||
                $this->cleanup(notify: false);
 | 
			
		||||
                $this->remove_unnecessary_coolify_yaml();
 | 
			
		||||
                if (config('coolify.is_sentinel_enabled')) {
 | 
			
		||||
                if ($this->server->isSentinelEnabled()) {
 | 
			
		||||
                    $this->server->checkSentinel();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
@@ -14,9 +14,7 @@ class ServerStorageSaveJob implements ShouldBeEncrypted, ShouldQueue
 | 
			
		||||
{
 | 
			
		||||
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
 | 
			
		||||
 | 
			
		||||
    public function __construct(public LocalFileVolume $localFileVolume)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    public function __construct(public LocalFileVolume $localFileVolume) {}
 | 
			
		||||
 | 
			
		||||
    public function handle()
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -15,9 +15,7 @@ class SubscriptionInvoiceFailedJob implements ShouldBeEncrypted, ShouldQueue
 | 
			
		||||
{
 | 
			
		||||
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
 | 
			
		||||
 | 
			
		||||
    public function __construct(protected Team $team)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    public function __construct(protected Team $team) {}
 | 
			
		||||
 | 
			
		||||
    public function handle()
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -17,8 +17,7 @@ class SubscriptionTrialEndedJob implements ShouldBeEncrypted, ShouldQueue
 | 
			
		||||
 | 
			
		||||
    public function __construct(
 | 
			
		||||
        public Team $team
 | 
			
		||||
    ) {
 | 
			
		||||
    }
 | 
			
		||||
    ) {}
 | 
			
		||||
 | 
			
		||||
    public function handle(): void
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -17,8 +17,7 @@ class SubscriptionTrialEndsSoonJob implements ShouldBeEncrypted, ShouldQueue
 | 
			
		||||
 | 
			
		||||
    public function __construct(
 | 
			
		||||
        public Team $team
 | 
			
		||||
    ) {
 | 
			
		||||
    }
 | 
			
		||||
    ) {}
 | 
			
		||||
 | 
			
		||||
    public function handle(): void
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -9,9 +9,7 @@ use Symfony\Component\HttpFoundation\Request as SymfonyRequest;
 | 
			
		||||
 | 
			
		||||
class MaintenanceModeDisabledNotification
 | 
			
		||||
{
 | 
			
		||||
    public function __construct()
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    public function __construct() {}
 | 
			
		||||
 | 
			
		||||
    public function handle(EventsMaintenanceModeDisabled $event): void
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -9,9 +9,7 @@ class ProxyStartedNotification
 | 
			
		||||
{
 | 
			
		||||
    public Server $server;
 | 
			
		||||
 | 
			
		||||
    public function __construct()
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    public function __construct() {}
 | 
			
		||||
 | 
			
		||||
    public function handle(ProxyStarted $event): void
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@ use Livewire\Component;
 | 
			
		||||
 | 
			
		||||
class Index extends Component
 | 
			
		||||
{
 | 
			
		||||
    protected $listeners = ['serverInstalled' => 'validateServer'];
 | 
			
		||||
    protected $listeners = ['refreshBoardingIndex' => 'validateServer'];
 | 
			
		||||
 | 
			
		||||
    public string $currentState = 'welcome';
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										51
									
								
								app/Livewire/MonacoEditor.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								app/Livewire/MonacoEditor.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,51 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace App\Livewire;
 | 
			
		||||
 | 
			
		||||
//use Livewire\Component;
 | 
			
		||||
use Illuminate\View\Component;
 | 
			
		||||
use Visus\Cuid2\Cuid2;
 | 
			
		||||
 | 
			
		||||
class MonacoEditor extends Component
 | 
			
		||||
{
 | 
			
		||||
    protected $listeners = [
 | 
			
		||||
        'configurationChanged' => '$refresh',
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    public function __construct(
 | 
			
		||||
        public ?string $id,
 | 
			
		||||
        public ?string $name,
 | 
			
		||||
        public ?string $type,
 | 
			
		||||
        public ?string $monacoContent,
 | 
			
		||||
        public ?string $value,
 | 
			
		||||
        public ?string $label,
 | 
			
		||||
        public ?string $placeholder,
 | 
			
		||||
        public bool $required,
 | 
			
		||||
        public bool $disabled,
 | 
			
		||||
        public bool $readonly,
 | 
			
		||||
        public bool $allowTab,
 | 
			
		||||
        public bool $spellcheck,
 | 
			
		||||
        public ?string $helper,
 | 
			
		||||
        public bool $realtimeValidation,
 | 
			
		||||
        public bool $allowToPeak,
 | 
			
		||||
        public string $defaultClass,
 | 
			
		||||
        public string $defaultClassInput,
 | 
			
		||||
        public ?string $language
 | 
			
		||||
 | 
			
		||||
    ) {
 | 
			
		||||
        //
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function render()
 | 
			
		||||
    {
 | 
			
		||||
        if (is_null($this->id)) {
 | 
			
		||||
            $this->id = new Cuid2(7);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (is_null($this->name)) {
 | 
			
		||||
            $this->name = $this->id;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return view('components.forms.monaco-editor');
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -347,7 +347,9 @@ class General extends Component
 | 
			
		||||
    public function submit($showToaster = true)
 | 
			
		||||
    {
 | 
			
		||||
        try {
 | 
			
		||||
            $this->set_redirect();
 | 
			
		||||
            if ($this->application->isDirty('redirect')) {
 | 
			
		||||
                $this->set_redirect();
 | 
			
		||||
            }
 | 
			
		||||
            $this->application->fqdn = str($this->application->fqdn)->replaceEnd(',', '')->trim();
 | 
			
		||||
            $this->application->fqdn = str($this->application->fqdn)->replaceStart(',', '')->trim();
 | 
			
		||||
            $this->application->fqdn = str($this->application->fqdn)->trim()->explode(',')->map(function ($domain) {
 | 
			
		||||
 
 | 
			
		||||
@@ -45,7 +45,7 @@ class Heading extends Component
 | 
			
		||||
    public function check_status($showNotification = false)
 | 
			
		||||
    {
 | 
			
		||||
        if ($this->application->destination->server->isFunctional()) {
 | 
			
		||||
            GetContainersStatus::dispatch($this->application->destination->server);
 | 
			
		||||
            GetContainersStatus::dispatch($this->application->destination->server)->onQueue('high');
 | 
			
		||||
            // dispatch(new ContainerStatusJob($this->application->destination->server));
 | 
			
		||||
        } else {
 | 
			
		||||
            dispatch(new ServerStatusJob($this->application->destination->server));
 | 
			
		||||
 
 | 
			
		||||
@@ -186,7 +186,7 @@ class Previews extends Component
 | 
			
		||||
                    instant_remote_process(["docker rm -f $name"], $this->application->destination->server, throwError: false);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            GetContainersStatus::dispatchSync($this->application->destination->server);
 | 
			
		||||
            GetContainersStatus::dispatchSync($this->application->destination->server)->onQueue('high');
 | 
			
		||||
            $this->dispatch('reloadWindow');
 | 
			
		||||
        } catch (\Throwable $e) {
 | 
			
		||||
            return handleError($e, $this);
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,6 @@ use App\Actions\Database\StartPostgresql;
 | 
			
		||||
use App\Actions\Database\StartRedis;
 | 
			
		||||
use App\Actions\Database\StopDatabase;
 | 
			
		||||
use App\Actions\Docker\GetContainersStatus;
 | 
			
		||||
use App\Jobs\ContainerStatusJob;
 | 
			
		||||
use Livewire\Component;
 | 
			
		||||
 | 
			
		||||
class Heading extends Component
 | 
			
		||||
 
 | 
			
		||||
@@ -25,7 +25,17 @@ class General extends Component
 | 
			
		||||
 | 
			
		||||
    public ?string $db_url_public = null;
 | 
			
		||||
 | 
			
		||||
    protected $listeners = ['refresh', 'save_init_script', 'delete_init_script'];
 | 
			
		||||
    public function getListeners()
 | 
			
		||||
    {
 | 
			
		||||
        $userId = auth()->user()->id;
 | 
			
		||||
 | 
			
		||||
        return [
 | 
			
		||||
            "echo-private:user.{$userId},DatabaseStatusChanged" => 'database_stopped',
 | 
			
		||||
            'refresh',
 | 
			
		||||
            'save_init_script',
 | 
			
		||||
            'delete_init_script',
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected $rules = [
 | 
			
		||||
        'database.name' => 'required',
 | 
			
		||||
@@ -69,6 +79,11 @@ class General extends Component
 | 
			
		||||
        $this->server = data_get($this->database, 'destination.server');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function database_stopped()
 | 
			
		||||
    {
 | 
			
		||||
        $this->dispatch('success', 'Database proxy stopped. Database is no longer publicly accessible.');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function instantSaveAdvanced()
 | 
			
		||||
    {
 | 
			
		||||
        try {
 | 
			
		||||
 
 | 
			
		||||
@@ -176,10 +176,12 @@ class Select extends Component
 | 
			
		||||
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        // if (count($this->servers) === 1) {
 | 
			
		||||
        //     $server = $this->servers->first();
 | 
			
		||||
        //     $this->setServer($server);
 | 
			
		||||
        // }
 | 
			
		||||
        if (count($this->servers) === 1) {
 | 
			
		||||
            $server = $this->servers->first();
 | 
			
		||||
            if ($server instanceof Server) {
 | 
			
		||||
                $this->setServer($server);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (! is_null($this->server)) {
 | 
			
		||||
            $foundServer = $this->servers->where('id', $this->server->id)->first();
 | 
			
		||||
            if ($foundServer) {
 | 
			
		||||
@@ -195,6 +197,13 @@ class Select extends Component
 | 
			
		||||
        $this->server = $server;
 | 
			
		||||
        $this->standaloneDockers = $server->standaloneDockers;
 | 
			
		||||
        $this->swarmDockers = $server->swarmDockers;
 | 
			
		||||
        $count = count($this->standaloneDockers) + count($this->swarmDockers);
 | 
			
		||||
        if ($count === 1) {
 | 
			
		||||
            $docker = $this->standaloneDockers->first() ?? $this->swarmDockers->first();
 | 
			
		||||
            if ($docker) {
 | 
			
		||||
                $this->setDestination($docker->uuid);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        $this->current_step = 'destinations';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										35
									
								
								app/Livewire/Project/Resource/EnvironmentSelect.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								app/Livewire/Project/Resource/EnvironmentSelect.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,35 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace App\Livewire\Project\Resource;
 | 
			
		||||
 | 
			
		||||
use Illuminate\Database\Eloquent\Collection;
 | 
			
		||||
use Livewire\Component;
 | 
			
		||||
 | 
			
		||||
class EnvironmentSelect extends Component
 | 
			
		||||
{
 | 
			
		||||
    public Collection $environments;
 | 
			
		||||
 | 
			
		||||
    public string $project_uuid = '';
 | 
			
		||||
 | 
			
		||||
    public string $selectedEnvironment = '';
 | 
			
		||||
 | 
			
		||||
    public function mount()
 | 
			
		||||
    {
 | 
			
		||||
        $this->selectedEnvironment = request()->route('environment_name');
 | 
			
		||||
        $this->project_uuid = request()->route('project_uuid');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function updatedSelectedEnvironment($value)
 | 
			
		||||
    {
 | 
			
		||||
        if ($value === 'edit') {
 | 
			
		||||
            return redirect()->route('project.show', [
 | 
			
		||||
                'project_uuid' => $this->project_uuid,
 | 
			
		||||
            ]);
 | 
			
		||||
        } else {
 | 
			
		||||
            return redirect()->route('project.resource.index', [
 | 
			
		||||
                'project_uuid' => $this->project_uuid,
 | 
			
		||||
                'environment_name' => $value,
 | 
			
		||||
            ]);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -11,6 +11,8 @@ class EditCompose extends Component
 | 
			
		||||
 | 
			
		||||
    public $serviceId;
 | 
			
		||||
 | 
			
		||||
    protected $listeners = ['refreshEnvs' => 'mount'];
 | 
			
		||||
 | 
			
		||||
    protected $rules = [
 | 
			
		||||
        'service.docker_compose_raw' => 'required',
 | 
			
		||||
        'service.docker_compose' => 'required',
 | 
			
		||||
 
 | 
			
		||||
@@ -75,14 +75,12 @@ class StackForm extends Component
 | 
			
		||||
            $this->service->parse();
 | 
			
		||||
            $this->service->refresh();
 | 
			
		||||
            $this->service->saveComposeConfigs();
 | 
			
		||||
            $this->dispatch('refreshStacks');
 | 
			
		||||
            $this->dispatch('refreshEnvs');
 | 
			
		||||
            $this->dispatch('success', 'Service saved.');
 | 
			
		||||
        } catch (\Throwable $e) {
 | 
			
		||||
            return handleError($e, $this);
 | 
			
		||||
        } finally {
 | 
			
		||||
            if (is_null($this->service->config_hash)) {
 | 
			
		||||
                ray('asdf');
 | 
			
		||||
                $this->service->isConfigurationChanged(true);
 | 
			
		||||
            } else {
 | 
			
		||||
                $this->dispatch('configurationChanged');
 | 
			
		||||
 
 | 
			
		||||
@@ -59,15 +59,6 @@ class Logs extends Component
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function loadMetrics()
 | 
			
		||||
    {
 | 
			
		||||
        return;
 | 
			
		||||
        $server = data_get($this->resource, 'destination.server');
 | 
			
		||||
        if ($server->isFunctional()) {
 | 
			
		||||
            $this->cpu = $server->getMetrics();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function mount()
 | 
			
		||||
    {
 | 
			
		||||
        try {
 | 
			
		||||
@@ -122,7 +113,6 @@ class Logs extends Component
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $this->loadMetrics();
 | 
			
		||||
        } catch (\Exception $e) {
 | 
			
		||||
            return handleError($e, $this);
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										64
									
								
								app/Livewire/Project/Shared/Metrics.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								app/Livewire/Project/Shared/Metrics.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,64 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace App\Livewire\Project\Shared;
 | 
			
		||||
 | 
			
		||||
use Livewire\Component;
 | 
			
		||||
 | 
			
		||||
class Metrics extends Component
 | 
			
		||||
{
 | 
			
		||||
    public $resource;
 | 
			
		||||
 | 
			
		||||
    public $chartId = 'container-cpu';
 | 
			
		||||
 | 
			
		||||
    public $data;
 | 
			
		||||
 | 
			
		||||
    public $categories;
 | 
			
		||||
 | 
			
		||||
    public int $interval = 5;
 | 
			
		||||
 | 
			
		||||
    public bool $poll = true;
 | 
			
		||||
 | 
			
		||||
    public function pollData()
 | 
			
		||||
    {
 | 
			
		||||
        if ($this->poll || $this->interval <= 10) {
 | 
			
		||||
            $this->loadData();
 | 
			
		||||
            if ($this->interval > 10) {
 | 
			
		||||
                $this->poll = false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function loadData()
 | 
			
		||||
    {
 | 
			
		||||
        try {
 | 
			
		||||
            $metrics = $this->resource->getMetrics($this->interval);
 | 
			
		||||
            $cpuMetrics = collect($metrics)->map(function ($metric) {
 | 
			
		||||
                return [$metric[0], $metric[1]];
 | 
			
		||||
            });
 | 
			
		||||
            $memoryMetrics = collect($metrics)->map(function ($metric) {
 | 
			
		||||
                return [$metric[0], $metric[2]];
 | 
			
		||||
            });
 | 
			
		||||
            $this->dispatch("refreshChartData-{$this->chartId}-cpu", [
 | 
			
		||||
                'seriesData' => $cpuMetrics,
 | 
			
		||||
            ]);
 | 
			
		||||
            $this->dispatch("refreshChartData-{$this->chartId}-memory", [
 | 
			
		||||
                'seriesData' => $memoryMetrics,
 | 
			
		||||
            ]);
 | 
			
		||||
        } catch (\Throwable $e) {
 | 
			
		||||
            return handleError($e, $this);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setInterval()
 | 
			
		||||
    {
 | 
			
		||||
        if ($this->interval <= 10) {
 | 
			
		||||
            $this->poll = true;
 | 
			
		||||
        }
 | 
			
		||||
        $this->loadData();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function render()
 | 
			
		||||
    {
 | 
			
		||||
        return view('livewire.project.shared.metrics');
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -9,6 +9,8 @@ class Show extends Component
 | 
			
		||||
{
 | 
			
		||||
    public Project $project;
 | 
			
		||||
 | 
			
		||||
    public $environments;
 | 
			
		||||
 | 
			
		||||
    public function mount()
 | 
			
		||||
    {
 | 
			
		||||
        $projectUuid = request()->route('project_uuid');
 | 
			
		||||
@@ -18,7 +20,8 @@ class Show extends Component
 | 
			
		||||
        if (! $project) {
 | 
			
		||||
            return redirect()->route('dashboard');
 | 
			
		||||
        }
 | 
			
		||||
        $project->load(['environments']);
 | 
			
		||||
 | 
			
		||||
        $this->environments = $project->environments->sortBy('created_at');
 | 
			
		||||
        $this->project = $project;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										62
									
								
								app/Livewire/Server/Charts.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								app/Livewire/Server/Charts.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,62 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace App\Livewire\Server;
 | 
			
		||||
 | 
			
		||||
use App\Models\Server;
 | 
			
		||||
use Livewire\Component;
 | 
			
		||||
 | 
			
		||||
class Charts extends Component
 | 
			
		||||
{
 | 
			
		||||
    public Server $server;
 | 
			
		||||
 | 
			
		||||
    public $chartId = 'server';
 | 
			
		||||
 | 
			
		||||
    public $data;
 | 
			
		||||
 | 
			
		||||
    public $categories;
 | 
			
		||||
 | 
			
		||||
    public int $interval = 5;
 | 
			
		||||
 | 
			
		||||
    public bool $poll = true;
 | 
			
		||||
 | 
			
		||||
    public function pollData()
 | 
			
		||||
    {
 | 
			
		||||
        if ($this->poll || $this->interval <= 10) {
 | 
			
		||||
            $this->loadData();
 | 
			
		||||
            if ($this->interval > 10) {
 | 
			
		||||
                $this->poll = false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function loadData()
 | 
			
		||||
    {
 | 
			
		||||
        try {
 | 
			
		||||
            $cpuMetrics = $this->server->getCpuMetrics($this->interval);
 | 
			
		||||
            $memoryMetrics = $this->server->getMemoryMetrics($this->interval);
 | 
			
		||||
            $cpuMetrics = collect($cpuMetrics)->map(function ($metric) {
 | 
			
		||||
                return [$metric[0], $metric[1]];
 | 
			
		||||
            });
 | 
			
		||||
            $memoryMetrics = collect($memoryMetrics)->map(function ($metric) {
 | 
			
		||||
                return [$metric[0], $metric[1]];
 | 
			
		||||
            });
 | 
			
		||||
            $this->dispatch("refreshChartData-{$this->chartId}-cpu", [
 | 
			
		||||
                'seriesData' => $cpuMetrics,
 | 
			
		||||
            ]);
 | 
			
		||||
            $this->dispatch("refreshChartData-{$this->chartId}-memory", [
 | 
			
		||||
                'seriesData' => $memoryMetrics,
 | 
			
		||||
            ]);
 | 
			
		||||
 | 
			
		||||
        } catch (\Throwable $e) {
 | 
			
		||||
            return handleError($e, $this);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setInterval()
 | 
			
		||||
    {
 | 
			
		||||
        if ($this->interval <= 10) {
 | 
			
		||||
            $this->poll = true;
 | 
			
		||||
        }
 | 
			
		||||
        $this->loadData();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -21,7 +21,7 @@ class ConfigureCloudflareTunnels extends Component
 | 
			
		||||
            $server->settings->is_cloudflare_tunnel = true;
 | 
			
		||||
            $server->settings->save();
 | 
			
		||||
            $this->dispatch('success', 'Cloudflare Tunnels configured successfully.');
 | 
			
		||||
            $this->dispatch('serverInstalled');
 | 
			
		||||
            $this->dispatch('refreshServerShow');
 | 
			
		||||
        } catch (\Throwable $e) {
 | 
			
		||||
            return handleError($e, $this);
 | 
			
		||||
        }
 | 
			
		||||
@@ -37,7 +37,7 @@ class ConfigureCloudflareTunnels extends Component
 | 
			
		||||
            $server->save();
 | 
			
		||||
            $server->settings->save();
 | 
			
		||||
            $this->dispatch('success', 'Cloudflare Tunnels configured successfully.');
 | 
			
		||||
            $this->dispatch('serverInstalled');
 | 
			
		||||
            $this->dispatch('refreshServerShow');
 | 
			
		||||
        } catch (\Throwable $e) {
 | 
			
		||||
            return handleError($e, $this);
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,9 @@
 | 
			
		||||
 | 
			
		||||
namespace App\Livewire\Server;
 | 
			
		||||
 | 
			
		||||
use App\Actions\Server\StartSentinel;
 | 
			
		||||
use App\Actions\Server\StopSentinel;
 | 
			
		||||
use App\Jobs\PullSentinelImageJob;
 | 
			
		||||
use App\Models\Server;
 | 
			
		||||
use Livewire\Component;
 | 
			
		||||
 | 
			
		||||
@@ -36,7 +39,12 @@ class Form extends Component
 | 
			
		||||
        'server.settings.is_build_server' => 'required|boolean',
 | 
			
		||||
        'server.settings.concurrent_builds' => 'required|integer|min:1',
 | 
			
		||||
        'server.settings.dynamic_timeout' => 'required|integer|min:1',
 | 
			
		||||
        'server.settings.is_metrics_enabled' => 'required|boolean',
 | 
			
		||||
        'server.settings.metrics_token' => 'required',
 | 
			
		||||
        'server.settings.metrics_refresh_rate_seconds' => 'required|integer|min:1',
 | 
			
		||||
        'server.settings.metrics_history_days' => 'required|integer|min:1',
 | 
			
		||||
        'wildcard_domain' => 'nullable|url',
 | 
			
		||||
        'server.settings.is_server_api_enabled' => 'required|boolean',
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    protected $validationAttributes = [
 | 
			
		||||
@@ -52,7 +60,11 @@ class Form extends Component
 | 
			
		||||
        'server.settings.is_build_server' => 'Build Server',
 | 
			
		||||
        'server.settings.concurrent_builds' => 'Concurrent Builds',
 | 
			
		||||
        'server.settings.dynamic_timeout' => 'Dynamic Timeout',
 | 
			
		||||
 | 
			
		||||
        'server.settings.is_metrics_enabled' => 'Metrics',
 | 
			
		||||
        'server.settings.metrics_token' => 'Metrics Token',
 | 
			
		||||
        'server.settings.metrics_refresh_rate_seconds' => 'Metrics Interval',
 | 
			
		||||
        'server.settings.metrics_history_days' => 'Metrics History',
 | 
			
		||||
        'server.settings.is_server_api_enabled' => 'Server API',
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    public function mount()
 | 
			
		||||
@@ -69,18 +81,59 @@ class Form extends Component
 | 
			
		||||
 | 
			
		||||
    public function updatedServerSettingsIsBuildServer()
 | 
			
		||||
    {
 | 
			
		||||
        $this->dispatch('serverInstalled');
 | 
			
		||||
        $this->dispatch('refreshServerShow');
 | 
			
		||||
        $this->dispatch('serverRefresh');
 | 
			
		||||
        $this->dispatch('proxyStatusUpdated');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function checkPortForServerApi()
 | 
			
		||||
    {
 | 
			
		||||
        try {
 | 
			
		||||
            if ($this->server->settings->is_server_api_enabled === true) {
 | 
			
		||||
                $this->server->checkServerApi();
 | 
			
		||||
                $this->dispatch('success', 'Server API is reachable.');
 | 
			
		||||
            }
 | 
			
		||||
        } catch (\Throwable $e) {
 | 
			
		||||
            return handleError($e, $this);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function instantSave()
 | 
			
		||||
    {
 | 
			
		||||
        try {
 | 
			
		||||
            refresh_server_connection($this->server->privateKey);
 | 
			
		||||
            $this->validateServer(false);
 | 
			
		||||
            $this->server->settings->save();
 | 
			
		||||
            $this->server->save();
 | 
			
		||||
            $this->dispatch('success', 'Server updated.');
 | 
			
		||||
            $this->dispatch('refreshServerShow');
 | 
			
		||||
            if ($this->server->isSentinelEnabled()) {
 | 
			
		||||
                PullSentinelImageJob::dispatchSync($this->server);
 | 
			
		||||
                ray('Sentinel is enabled');
 | 
			
		||||
                if ($this->server->settings->isDirty('is_metrics_enabled')) {
 | 
			
		||||
                    $this->dispatch('reloadWindow');
 | 
			
		||||
                }
 | 
			
		||||
                if ($this->server->settings->isDirty('is_server_api_enabled') && $this->server->settings->is_server_api_enabled === true) {
 | 
			
		||||
                    ray('Starting sentinel');
 | 
			
		||||
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                ray('Sentinel is not enabled');
 | 
			
		||||
                StopSentinel::dispatch($this->server);
 | 
			
		||||
            }
 | 
			
		||||
            // $this->checkPortForServerApi();
 | 
			
		||||
 | 
			
		||||
        } catch (\Throwable $e) {
 | 
			
		||||
            return handleError($e, $this);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function restartSentinel()
 | 
			
		||||
    {
 | 
			
		||||
        try {
 | 
			
		||||
            $version = get_latest_sentinel_version();
 | 
			
		||||
            StartSentinel::run($this->server, $version, true);
 | 
			
		||||
            $this->dispatch('success', 'Sentinel restarted.');
 | 
			
		||||
        } catch (\Throwable $e) {
 | 
			
		||||
            return handleError($e, $this);
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,7 @@ class Show extends Component
 | 
			
		||||
 | 
			
		||||
    public $parameters = [];
 | 
			
		||||
 | 
			
		||||
    protected $listeners = ['serverInstalled' => '$refresh'];
 | 
			
		||||
    protected $listeners = ['refreshServerShow' => '$refresh'];
 | 
			
		||||
 | 
			
		||||
    public function mount()
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -143,7 +143,8 @@ class ValidateAndInstall extends Component
 | 
			
		||||
        } else {
 | 
			
		||||
            $this->docker_version = $this->server->validateDockerEngineVersion();
 | 
			
		||||
            if ($this->docker_version) {
 | 
			
		||||
                $this->dispatch('serverInstalled');
 | 
			
		||||
                $this->dispatch('refreshServerShow');
 | 
			
		||||
                $this->dispatch('refreshBoardingIndex');
 | 
			
		||||
                $this->dispatch('success', 'Server validated.');
 | 
			
		||||
            } else {
 | 
			
		||||
                $this->error = 'Docker Engine version is not 22+. Please install Docker manually before continuing: <a target="_blank" class="underline" href="https://docs.docker.com/engine/install/#server">documentation</a>.';
 | 
			
		||||
 
 | 
			
		||||
@@ -29,6 +29,7 @@ class Configuration extends Component
 | 
			
		||||
        'settings.public_port_min' => 'required',
 | 
			
		||||
        'settings.public_port_max' => 'required',
 | 
			
		||||
        'settings.custom_dns_servers' => 'nullable',
 | 
			
		||||
        'settings.instance_name' => 'nullable',
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    protected $validationAttributes = [
 | 
			
		||||
 
 | 
			
		||||
@@ -228,7 +228,7 @@ class Application extends BaseModel
 | 
			
		||||
 | 
			
		||||
    public function gitCommitLink($link): string
 | 
			
		||||
    {
 | 
			
		||||
        if (! is_null($this->source?->html_url) && ! is_null($this->git_repository) && ! is_null($this->git_branch)) {
 | 
			
		||||
        if (! is_null(data_get($this, 'source.html_url')) && ! is_null(data_get($this, 'git_repository')) && ! is_null(data_get($this, 'git_branch'))) {
 | 
			
		||||
            if (str($this->source->html_url)->contains('bitbucket')) {
 | 
			
		||||
                return "{$this->source->html_url}/{$this->git_repository}/commits/{$link}";
 | 
			
		||||
            }
 | 
			
		||||
@@ -245,8 +245,11 @@ class Application extends BaseModel
 | 
			
		||||
        }
 | 
			
		||||
        if (strpos($this->git_repository, 'git@') === 0) {
 | 
			
		||||
            $git_repository = str_replace(['git@', ':', '.git'], ['', '/', ''], $this->git_repository);
 | 
			
		||||
            if (data_get($this, 'source.html_url')) {
 | 
			
		||||
                return "{$this->source->html_url}/{$git_repository}/commit/{$link}";
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return "https://{$git_repository}/commit/{$link}";
 | 
			
		||||
            return "{$git_repository}/commit/{$link}";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $this->git_repository;
 | 
			
		||||
@@ -1167,4 +1170,44 @@ class Application extends BaseModel
 | 
			
		||||
 | 
			
		||||
        return $preview;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function getDomainsByUuid(string $uuid): array
 | 
			
		||||
    {
 | 
			
		||||
        $application = self::where('uuid', $uuid)->first();
 | 
			
		||||
 | 
			
		||||
        if ($application) {
 | 
			
		||||
            return $application->fqdns;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return [];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getMetrics(int $mins = 5)
 | 
			
		||||
    {
 | 
			
		||||
        $server = $this->destination->server;
 | 
			
		||||
        $container_name = $this->uuid;
 | 
			
		||||
        if ($server->isMetricsEnabled()) {
 | 
			
		||||
            $from = now()->subMinutes($mins)->toIso8601ZuluString();
 | 
			
		||||
            $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->metrics_token}\" http://localhost:8888/api/container/{$container_name}/metrics/history?from=$from'"], $server, false);
 | 
			
		||||
            if (str($metrics)->contains('error')) {
 | 
			
		||||
                $error = json_decode($metrics, true);
 | 
			
		||||
                $error = data_get($error, 'error', 'Something is not okay, are you okay?');
 | 
			
		||||
                if ($error == 'Unauthorized') {
 | 
			
		||||
                    $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
 | 
			
		||||
                }
 | 
			
		||||
                throw new \Exception($error);
 | 
			
		||||
            }
 | 
			
		||||
            $metrics = str($metrics)->explode("\n")->skip(1)->all();
 | 
			
		||||
            $parsedCollection = collect($metrics)->flatMap(function ($item) {
 | 
			
		||||
                return collect(explode("\n", trim($item)))->map(function ($line) {
 | 
			
		||||
                    [$time, $cpu_usage_percent, $memory_usage, $memory_usage_percent] = explode(',', trim($line));
 | 
			
		||||
                    $cpu_usage_percent = number_format($cpu_usage_percent, 2);
 | 
			
		||||
 | 
			
		||||
                    return [(int) $time, (float) $cpu_usage_percent, (int) $memory_usage];
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            return $parsedCollection->toArray();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -109,7 +109,7 @@ class Environment extends Model
 | 
			
		||||
    protected function name(): Attribute
 | 
			
		||||
    {
 | 
			
		||||
        return Attribute::make(
 | 
			
		||||
            set: fn (string $value) => strtolower($value),
 | 
			
		||||
            set: fn (string $value) => str($value)->lower()->trim()->replace('/', '-')->toString(),
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -47,4 +47,14 @@ class InstanceSettings extends Model implements SendsEmail
 | 
			
		||||
 | 
			
		||||
        return explode(',', $recipients);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getTitleDisplayName(): string
 | 
			
		||||
    {
 | 
			
		||||
        $instanceName = $this->instance_name;
 | 
			
		||||
        if (! $instanceName) {
 | 
			
		||||
            return '';
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return "[{$instanceName}]";
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,4 @@
 | 
			
		||||
 | 
			
		||||
namespace App\Models;
 | 
			
		||||
 | 
			
		||||
class Kubernetes extends BaseModel
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
class Kubernetes extends BaseModel {}
 | 
			
		||||
 
 | 
			
		||||
@@ -112,4 +112,18 @@ class Project extends BaseModel
 | 
			
		||||
    {
 | 
			
		||||
        return $this->postgresqls()->get()->merge($this->redis()->get())->merge($this->mongodbs()->get())->merge($this->mysqls()->get())->merge($this->mariadbs()->get())->merge($this->keydbs()->get())->merge($this->dragonflies()->get())->merge($this->clickhouses()->get());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function default_environment()
 | 
			
		||||
    {
 | 
			
		||||
        $default = $this->environments()->where('name', 'production')->first();
 | 
			
		||||
        if ($default) {
 | 
			
		||||
            return $default->name;
 | 
			
		||||
        }
 | 
			
		||||
        $default = $this->environments()->get();
 | 
			
		||||
        if ($default->count() > 0) {
 | 
			
		||||
            return $default->sortBy('created_at')->first()->name;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -5,12 +5,11 @@ namespace App\Models;
 | 
			
		||||
use App\Actions\Server\InstallDocker;
 | 
			
		||||
use App\Enums\ProxyTypes;
 | 
			
		||||
use App\Jobs\PullSentinelImageJob;
 | 
			
		||||
use App\Notifications\Server\Revived;
 | 
			
		||||
use App\Notifications\Server\Unreachable;
 | 
			
		||||
use Illuminate\Database\Eloquent\Builder;
 | 
			
		||||
use Illuminate\Database\Eloquent\Casts\Attribute;
 | 
			
		||||
use Illuminate\Support\Collection;
 | 
			
		||||
use Illuminate\Support\Facades\DB;
 | 
			
		||||
use Illuminate\Support\Facades\Process;
 | 
			
		||||
use Illuminate\Support\Facades\Storage;
 | 
			
		||||
use Illuminate\Support\Str;
 | 
			
		||||
use Illuminate\Support\Stringable;
 | 
			
		||||
@@ -462,10 +461,44 @@ $schema://$host {
 | 
			
		||||
        Storage::disk('ssh-mux')->delete($this->muxFilename());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function isSentinelEnabled()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->isMetricsEnabled() || $this->isServerApiEnabled();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function isMetricsEnabled()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->settings->is_metrics_enabled;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function isServerApiEnabled()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->settings->is_server_api_enabled;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function checkServerApi()
 | 
			
		||||
    {
 | 
			
		||||
        if ($this->isServerApiEnabled()) {
 | 
			
		||||
            $server_ip = $this->ip;
 | 
			
		||||
            if (isDev()) {
 | 
			
		||||
                if ($this->id === 0) {
 | 
			
		||||
                    $server_ip = 'localhost';
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            $command = "curl -s http://{$server_ip}:12172/api/health";
 | 
			
		||||
            $process = Process::timeout(5)->run($command);
 | 
			
		||||
            if ($process->failed()) {
 | 
			
		||||
                ray($process->exitCode(), $process->output(), $process->errorOutput());
 | 
			
		||||
                throw new \Exception("Server API is not reachable on http://{$server_ip}:12172");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function checkSentinel()
 | 
			
		||||
    {
 | 
			
		||||
        ray("Checking sentinel on server: {$this->name}");
 | 
			
		||||
        if ($this->is_metrics_enabled) {
 | 
			
		||||
        if ($this->isSentinelEnabled()) {
 | 
			
		||||
            $sentinel_found = instant_remote_process(['docker inspect coolify-sentinel'], $this, false);
 | 
			
		||||
            $sentinel_found = json_decode($sentinel_found, true);
 | 
			
		||||
            $status = data_get($sentinel_found, '0.State.Status', 'exited');
 | 
			
		||||
@@ -478,21 +511,57 @@ $schema://$host {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getMetrics()
 | 
			
		||||
    public function getCpuMetrics(int $mins = 5)
 | 
			
		||||
    {
 | 
			
		||||
        if ($this->is_metrics_enabled) {
 | 
			
		||||
            $from = now()->subMinutes(5)->toIso8601ZuluString();
 | 
			
		||||
            $cpu = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl http://localhost:8888/api/cpu/history?from=$from'"], $this, false);
 | 
			
		||||
        if ($this->isMetricsEnabled()) {
 | 
			
		||||
            $from = now()->subMinutes($mins)->toIso8601ZuluString();
 | 
			
		||||
            $cpu = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$this->settings->metrics_token}\" http://localhost:8888/api/cpu/history?from=$from'"], $this, false);
 | 
			
		||||
            if (str($cpu)->contains('error')) {
 | 
			
		||||
                $error = json_decode($cpu, true);
 | 
			
		||||
                $error = data_get($error, 'error', 'Something is not okay, are you okay?');
 | 
			
		||||
                if ($error == 'Unauthorized') {
 | 
			
		||||
                    $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
 | 
			
		||||
                }
 | 
			
		||||
                throw new \Exception($error);
 | 
			
		||||
            }
 | 
			
		||||
            $cpu = str($cpu)->explode("\n")->skip(1)->all();
 | 
			
		||||
            $parsedCollection = collect($cpu)->flatMap(function ($item) {
 | 
			
		||||
                return collect(explode("\n", trim($item)))->map(function ($line) {
 | 
			
		||||
                    [$time, $value] = explode(',', trim($line));
 | 
			
		||||
                    [$time, $cpu_usage_percent] = explode(',', trim($line));
 | 
			
		||||
                    $cpu_usage_percent = number_format($cpu_usage_percent, 0);
 | 
			
		||||
 | 
			
		||||
                    return [(int) $time, (float) $value];
 | 
			
		||||
                    return [(int) $time, (float) $cpu_usage_percent];
 | 
			
		||||
                });
 | 
			
		||||
            })->toArray();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            return $parsedCollection;
 | 
			
		||||
            return $parsedCollection->toArray();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getMemoryMetrics(int $mins = 5)
 | 
			
		||||
    {
 | 
			
		||||
        if ($this->isMetricsEnabled()) {
 | 
			
		||||
            $from = now()->subMinutes($mins)->toIso8601ZuluString();
 | 
			
		||||
            $memory = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$this->settings->metrics_token}\" http://localhost:8888/api/memory/history?from=$from'"], $this, false);
 | 
			
		||||
            if (str($memory)->contains('error')) {
 | 
			
		||||
                $error = json_decode($memory, true);
 | 
			
		||||
                $error = data_get($error, 'error', 'Something is not okay, are you okay?');
 | 
			
		||||
                if ($error == 'Unauthorized') {
 | 
			
		||||
                    $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
 | 
			
		||||
                }
 | 
			
		||||
                throw new \Exception($error);
 | 
			
		||||
            }
 | 
			
		||||
            $memory = str($memory)->explode("\n")->skip(1)->all();
 | 
			
		||||
            $parsedCollection = collect($memory)->flatMap(function ($item) {
 | 
			
		||||
                return collect(explode("\n", trim($item)))->map(function ($line) {
 | 
			
		||||
                    [$time, $used, $free, $usedPercent] = explode(',', trim($line));
 | 
			
		||||
                    $usedPercent = number_format($usedPercent, 0);
 | 
			
		||||
 | 
			
		||||
                    return [(int) $time, (float) $usedPercent];
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            return $parsedCollection->toArray();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
 | 
			
		||||
use Illuminate\Database\Eloquent\Relations\HasMany;
 | 
			
		||||
use Illuminate\Database\Eloquent\SoftDeletes;
 | 
			
		||||
use Illuminate\Support\Collection;
 | 
			
		||||
use Symfony\Component\Yaml\Yaml;
 | 
			
		||||
 | 
			
		||||
class Service extends BaseModel
 | 
			
		||||
{
 | 
			
		||||
@@ -837,14 +838,38 @@ class Service extends BaseModel
 | 
			
		||||
        $commands[] = "mkdir -p $workdir";
 | 
			
		||||
        $commands[] = "cd $workdir";
 | 
			
		||||
 | 
			
		||||
        $json = Yaml::parse($this->docker_compose);
 | 
			
		||||
        $envs_from_coolify = $this->environment_variables()->get();
 | 
			
		||||
        // foreach ($json['services'] as $service => $config) {
 | 
			
		||||
        //     if (data_get($config, 'environment') === null) {
 | 
			
		||||
        //         data_set($json, "services.$service.environment", []);
 | 
			
		||||
        //         $envs = collect([]);
 | 
			
		||||
        //     } else {
 | 
			
		||||
        //         $envs = collect($config['environment']);
 | 
			
		||||
        //     }
 | 
			
		||||
        //     // $envs->put('COOLIFY_CONTAINER_NAME', "$service-{$this->uuid}");
 | 
			
		||||
        //     foreach ($envs_from_coolify as $env) {
 | 
			
		||||
        //         $envs = $envs->map(function ($value) use ($env) {
 | 
			
		||||
        //             if (str($value)->startsWith($env->key)) {
 | 
			
		||||
        //                 return "{$env->key}={$env->real_value}";
 | 
			
		||||
        //             }
 | 
			
		||||
 | 
			
		||||
        //             return $value;
 | 
			
		||||
        //         });
 | 
			
		||||
        //     }
 | 
			
		||||
        //     $envs = $envs->unique();
 | 
			
		||||
        //     data_set($json, "services.$service.environment", $envs->toArray());
 | 
			
		||||
        // }
 | 
			
		||||
        $this->docker_compose = Yaml::dump($json, 10, 2, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK);
 | 
			
		||||
        $docker_compose_base64 = base64_encode($this->docker_compose);
 | 
			
		||||
 | 
			
		||||
        $commands[] = "echo $docker_compose_base64 | base64 -d | tee docker-compose.yml > /dev/null";
 | 
			
		||||
        $envs = $this->environment_variables()->get();
 | 
			
		||||
        $commands[] = 'rm -f .env || true';
 | 
			
		||||
        foreach ($envs as $env) {
 | 
			
		||||
 | 
			
		||||
        foreach ($envs_from_coolify as $env) {
 | 
			
		||||
            $commands[] = "echo '{$env->key}={$env->real_value}' >> .env";
 | 
			
		||||
        }
 | 
			
		||||
        if ($envs->count() === 0) {
 | 
			
		||||
        if ($envs_from_coolify->count() === 0) {
 | 
			
		||||
            $commands[] = 'touch .env';
 | 
			
		||||
        }
 | 
			
		||||
        instant_remote_process($commands, $this->server);
 | 
			
		||||
 
 | 
			
		||||
@@ -226,4 +226,33 @@ class StandaloneClickhouse extends BaseModel
 | 
			
		||||
    {
 | 
			
		||||
        return $this->morphMany(ScheduledDatabaseBackup::class, 'database');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getMetrics(int $mins = 5)
 | 
			
		||||
    {
 | 
			
		||||
        $server = $this->destination->server;
 | 
			
		||||
        $container_name = $this->uuid;
 | 
			
		||||
        if ($server->isMetricsEnabled()) {
 | 
			
		||||
            $from = now()->subMinutes($mins)->toIso8601ZuluString();
 | 
			
		||||
            $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->metrics_token}\" http://localhost:8888/api/container/{$container_name}/metrics/history?from=$from'"], $server, false);
 | 
			
		||||
            if (str($metrics)->contains('error')) {
 | 
			
		||||
                $error = json_decode($metrics, true);
 | 
			
		||||
                $error = data_get($error, 'error', 'Something is not okay, are you okay?');
 | 
			
		||||
                if ($error == 'Unauthorized') {
 | 
			
		||||
                    $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
 | 
			
		||||
                }
 | 
			
		||||
                throw new \Exception($error);
 | 
			
		||||
            }
 | 
			
		||||
            $metrics = str($metrics)->explode("\n")->skip(1)->all();
 | 
			
		||||
            $parsedCollection = collect($metrics)->flatMap(function ($item) {
 | 
			
		||||
                return collect(explode("\n", trim($item)))->map(function ($line) {
 | 
			
		||||
                    [$time, $cpu_usage_percent, $memory_usage, $memory_usage_percent] = explode(',', trim($line));
 | 
			
		||||
                    $cpu_usage_percent = number_format($cpu_usage_percent, 2);
 | 
			
		||||
 | 
			
		||||
                    return [(int) $time, (float) $cpu_usage_percent, (int) $memory_usage];
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            return $parsedCollection->toArray();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -226,4 +226,33 @@ class StandaloneDragonfly extends BaseModel
 | 
			
		||||
    {
 | 
			
		||||
        return $this->morphMany(ScheduledDatabaseBackup::class, 'database');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getMetrics(int $mins = 5)
 | 
			
		||||
    {
 | 
			
		||||
        $server = $this->destination->server;
 | 
			
		||||
        $container_name = $this->uuid;
 | 
			
		||||
        if ($server->isMetricsEnabled()) {
 | 
			
		||||
            $from = now()->subMinutes($mins)->toIso8601ZuluString();
 | 
			
		||||
            $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->metrics_token}\" http://localhost:8888/api/container/{$container_name}/metrics/history?from=$from'"], $server, false);
 | 
			
		||||
            if (str($metrics)->contains('error')) {
 | 
			
		||||
                $error = json_decode($metrics, true);
 | 
			
		||||
                $error = data_get($error, 'error', 'Something is not okay, are you okay?');
 | 
			
		||||
                if ($error == 'Unauthorized') {
 | 
			
		||||
                    $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
 | 
			
		||||
                }
 | 
			
		||||
                throw new \Exception($error);
 | 
			
		||||
            }
 | 
			
		||||
            $metrics = str($metrics)->explode("\n")->skip(1)->all();
 | 
			
		||||
            $parsedCollection = collect($metrics)->flatMap(function ($item) {
 | 
			
		||||
                return collect(explode("\n", trim($item)))->map(function ($line) {
 | 
			
		||||
                    [$time, $cpu_usage_percent, $memory_usage, $memory_usage_percent] = explode(',', trim($line));
 | 
			
		||||
                    $cpu_usage_percent = number_format($cpu_usage_percent, 2);
 | 
			
		||||
 | 
			
		||||
                    return [(int) $time, (float) $cpu_usage_percent, (int) $memory_usage];
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            return $parsedCollection->toArray();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -226,4 +226,33 @@ class StandaloneKeydb extends BaseModel
 | 
			
		||||
    {
 | 
			
		||||
        return $this->morphMany(ScheduledDatabaseBackup::class, 'database');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getMetrics(int $mins = 5)
 | 
			
		||||
    {
 | 
			
		||||
        $server = $this->destination->server;
 | 
			
		||||
        $container_name = $this->uuid;
 | 
			
		||||
        if ($server->isMetricsEnabled()) {
 | 
			
		||||
            $from = now()->subMinutes($mins)->toIso8601ZuluString();
 | 
			
		||||
            $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->metrics_token}\" http://localhost:8888/api/container/{$container_name}/metrics/history?from=$from'"], $server, false);
 | 
			
		||||
            if (str($metrics)->contains('error')) {
 | 
			
		||||
                $error = json_decode($metrics, true);
 | 
			
		||||
                $error = data_get($error, 'error', 'Something is not okay, are you okay?');
 | 
			
		||||
                if ($error == 'Unauthorized') {
 | 
			
		||||
                    $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
 | 
			
		||||
                }
 | 
			
		||||
                throw new \Exception($error);
 | 
			
		||||
            }
 | 
			
		||||
            $metrics = str($metrics)->explode("\n")->skip(1)->all();
 | 
			
		||||
            $parsedCollection = collect($metrics)->flatMap(function ($item) {
 | 
			
		||||
                return collect(explode("\n", trim($item)))->map(function ($line) {
 | 
			
		||||
                    [$time, $cpu_usage_percent, $memory_usage, $memory_usage_percent] = explode(',', trim($line));
 | 
			
		||||
                    $cpu_usage_percent = number_format($cpu_usage_percent, 2);
 | 
			
		||||
 | 
			
		||||
                    return [(int) $time, (float) $cpu_usage_percent, (int) $memory_usage];
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            return $parsedCollection->toArray();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -226,4 +226,33 @@ class StandaloneMariadb extends BaseModel
 | 
			
		||||
    {
 | 
			
		||||
        return $this->morphMany(ScheduledDatabaseBackup::class, 'database');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getMetrics(int $mins = 5)
 | 
			
		||||
    {
 | 
			
		||||
        $server = $this->destination->server;
 | 
			
		||||
        $container_name = $this->uuid;
 | 
			
		||||
        if ($server->isMetricsEnabled()) {
 | 
			
		||||
            $from = now()->subMinutes($mins)->toIso8601ZuluString();
 | 
			
		||||
            $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->metrics_token}\" http://localhost:8888/api/container/{$container_name}/metrics/history?from=$from'"], $server, false);
 | 
			
		||||
            if (str($metrics)->contains('error')) {
 | 
			
		||||
                $error = json_decode($metrics, true);
 | 
			
		||||
                $error = data_get($error, 'error', 'Something is not okay, are you okay?');
 | 
			
		||||
                if ($error == 'Unauthorized') {
 | 
			
		||||
                    $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
 | 
			
		||||
                }
 | 
			
		||||
                throw new \Exception($error);
 | 
			
		||||
            }
 | 
			
		||||
            $metrics = str($metrics)->explode("\n")->skip(1)->all();
 | 
			
		||||
            $parsedCollection = collect($metrics)->flatMap(function ($item) {
 | 
			
		||||
                return collect(explode("\n", trim($item)))->map(function ($line) {
 | 
			
		||||
                    [$time, $cpu_usage_percent, $memory_usage, $memory_usage_percent] = explode(',', trim($line));
 | 
			
		||||
                    $cpu_usage_percent = number_format($cpu_usage_percent, 2);
 | 
			
		||||
 | 
			
		||||
                    return [(int) $time, (float) $cpu_usage_percent, (int) $memory_usage];
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            return $parsedCollection->toArray();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -246,4 +246,33 @@ class StandaloneMongodb extends BaseModel
 | 
			
		||||
    {
 | 
			
		||||
        return $this->morphMany(ScheduledDatabaseBackup::class, 'database');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getMetrics(int $mins = 5)
 | 
			
		||||
    {
 | 
			
		||||
        $server = $this->destination->server;
 | 
			
		||||
        $container_name = $this->uuid;
 | 
			
		||||
        if ($server->isMetricsEnabled()) {
 | 
			
		||||
            $from = now()->subMinutes($mins)->toIso8601ZuluString();
 | 
			
		||||
            $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->metrics_token}\" http://localhost:8888/api/container/{$container_name}/metrics/history?from=$from'"], $server, false);
 | 
			
		||||
            if (str($metrics)->contains('error')) {
 | 
			
		||||
                $error = json_decode($metrics, true);
 | 
			
		||||
                $error = data_get($error, 'error', 'Something is not okay, are you okay?');
 | 
			
		||||
                if ($error == 'Unauthorized') {
 | 
			
		||||
                    $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
 | 
			
		||||
                }
 | 
			
		||||
                throw new \Exception($error);
 | 
			
		||||
            }
 | 
			
		||||
            $metrics = str($metrics)->explode("\n")->skip(1)->all();
 | 
			
		||||
            $parsedCollection = collect($metrics)->flatMap(function ($item) {
 | 
			
		||||
                return collect(explode("\n", trim($item)))->map(function ($line) {
 | 
			
		||||
                    [$time, $cpu_usage_percent, $memory_usage, $memory_usage_percent] = explode(',', trim($line));
 | 
			
		||||
                    $cpu_usage_percent = number_format($cpu_usage_percent, 2);
 | 
			
		||||
 | 
			
		||||
                    return [(int) $time, (float) $cpu_usage_percent, (int) $memory_usage];
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            return $parsedCollection->toArray();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -227,4 +227,33 @@ class StandaloneMysql extends BaseModel
 | 
			
		||||
    {
 | 
			
		||||
        return $this->morphMany(ScheduledDatabaseBackup::class, 'database');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getMetrics(int $mins = 5)
 | 
			
		||||
    {
 | 
			
		||||
        $server = $this->destination->server;
 | 
			
		||||
        $container_name = $this->uuid;
 | 
			
		||||
        if ($server->isMetricsEnabled()) {
 | 
			
		||||
            $from = now()->subMinutes($mins)->toIso8601ZuluString();
 | 
			
		||||
            $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->metrics_token}\" http://localhost:8888/api/container/{$container_name}/metrics/history?from=$from'"], $server, false);
 | 
			
		||||
            if (str($metrics)->contains('error')) {
 | 
			
		||||
                $error = json_decode($metrics, true);
 | 
			
		||||
                $error = data_get($error, 'error', 'Something is not okay, are you okay?');
 | 
			
		||||
                if ($error == 'Unauthorized') {
 | 
			
		||||
                    $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
 | 
			
		||||
                }
 | 
			
		||||
                throw new \Exception($error);
 | 
			
		||||
            }
 | 
			
		||||
            $metrics = str($metrics)->explode("\n")->skip(1)->all();
 | 
			
		||||
            $parsedCollection = collect($metrics)->flatMap(function ($item) {
 | 
			
		||||
                return collect(explode("\n", trim($item)))->map(function ($line) {
 | 
			
		||||
                    [$time, $cpu_usage_percent, $memory_usage, $memory_usage_percent] = explode(',', trim($line));
 | 
			
		||||
                    $cpu_usage_percent = number_format($cpu_usage_percent, 2);
 | 
			
		||||
 | 
			
		||||
                    return [(int) $time, (float) $cpu_usage_percent, (int) $memory_usage];
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            return $parsedCollection->toArray();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -227,4 +227,33 @@ class StandalonePostgresql extends BaseModel
 | 
			
		||||
    {
 | 
			
		||||
        return $this->morphMany(ScheduledDatabaseBackup::class, 'database');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getMetrics(int $mins = 5)
 | 
			
		||||
    {
 | 
			
		||||
        $server = $this->destination->server;
 | 
			
		||||
        $container_name = $this->uuid;
 | 
			
		||||
        if ($server->isMetricsEnabled()) {
 | 
			
		||||
            $from = now()->subMinutes($mins)->toIso8601ZuluString();
 | 
			
		||||
            $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->metrics_token}\" http://localhost:8888/api/container/{$container_name}/metrics/history?from=$from'"], $server, false);
 | 
			
		||||
            if (str($metrics)->contains('error')) {
 | 
			
		||||
                $error = json_decode($metrics, true);
 | 
			
		||||
                $error = data_get($error, 'error', 'Something is not okay, are you okay?');
 | 
			
		||||
                if ($error == 'Unauthorized') {
 | 
			
		||||
                    $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
 | 
			
		||||
                }
 | 
			
		||||
                throw new \Exception($error);
 | 
			
		||||
            }
 | 
			
		||||
            $metrics = str($metrics)->explode("\n")->skip(1)->all();
 | 
			
		||||
            $parsedCollection = collect($metrics)->flatMap(function ($item) {
 | 
			
		||||
                return collect(explode("\n", trim($item)))->map(function ($line) {
 | 
			
		||||
                    [$time, $cpu_usage_percent, $memory_usage, $memory_usage_percent] = explode(',', trim($line));
 | 
			
		||||
                    $cpu_usage_percent = number_format($cpu_usage_percent, 2);
 | 
			
		||||
 | 
			
		||||
                    return [(int) $time, (float) $cpu_usage_percent, (int) $memory_usage];
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            return $parsedCollection->toArray();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -222,4 +222,33 @@ class StandaloneRedis extends BaseModel
 | 
			
		||||
    {
 | 
			
		||||
        return $this->morphMany(ScheduledDatabaseBackup::class, 'database');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getMetrics(int $mins = 5)
 | 
			
		||||
    {
 | 
			
		||||
        $server = $this->destination->server;
 | 
			
		||||
        $container_name = $this->uuid;
 | 
			
		||||
        if ($server->isMetricsEnabled()) {
 | 
			
		||||
            $from = now()->subMinutes($mins)->toIso8601ZuluString();
 | 
			
		||||
            $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->metrics_token}\" http://localhost:8888/api/container/{$container_name}/metrics/history?from=$from'"], $server, false);
 | 
			
		||||
            if (str($metrics)->contains('error')) {
 | 
			
		||||
                $error = json_decode($metrics, true);
 | 
			
		||||
                $error = data_get($error, 'error', 'Something is not okay, are you okay?');
 | 
			
		||||
                if ($error == 'Unauthorized') {
 | 
			
		||||
                    $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
 | 
			
		||||
                }
 | 
			
		||||
                throw new \Exception($error);
 | 
			
		||||
            }
 | 
			
		||||
            $metrics = str($metrics)->explode("\n")->skip(1)->all();
 | 
			
		||||
            $parsedCollection = collect($metrics)->flatMap(function ($item) {
 | 
			
		||||
                return collect(explode("\n", trim($item)))->map(function ($line) {
 | 
			
		||||
                    [$time, $cpu_usage_percent, $memory_usage, $memory_usage_percent] = explode(',', trim($line));
 | 
			
		||||
                    $cpu_usage_percent = number_format($cpu_usage_percent, 2);
 | 
			
		||||
 | 
			
		||||
                    return [(int) $time, (float) $cpu_usage_percent, (int) $memory_usage];
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            return $parsedCollection->toArray();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -14,9 +14,7 @@ class ContainerRestarted extends Notification implements ShouldQueue
 | 
			
		||||
 | 
			
		||||
    public $tries = 1;
 | 
			
		||||
 | 
			
		||||
    public function __construct(public string $name, public Server $server, public ?string $url = null)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    public function __construct(public string $name, public Server $server, public ?string $url = null) {}
 | 
			
		||||
 | 
			
		||||
    public function via(object $notifiable): array
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -14,9 +14,7 @@ class ContainerStopped extends Notification implements ShouldQueue
 | 
			
		||||
 | 
			
		||||
    public $tries = 1;
 | 
			
		||||
 | 
			
		||||
    public function __construct(public string $name, public Server $server, public ?string $url = null)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    public function __construct(public string $name, public Server $server, public ?string $url = null) {}
 | 
			
		||||
 | 
			
		||||
    public function via(object $notifiable): array
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -16,9 +16,7 @@ class DailyBackup extends Notification implements ShouldQueue
 | 
			
		||||
 | 
			
		||||
    public $tries = 1;
 | 
			
		||||
 | 
			
		||||
    public function __construct(public $databases)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    public function __construct(public $databases) {}
 | 
			
		||||
 | 
			
		||||
    public function via(object $notifiable): array
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -14,9 +14,7 @@ class GeneralNotification extends Notification implements ShouldQueue
 | 
			
		||||
 | 
			
		||||
    public $tries = 1;
 | 
			
		||||
 | 
			
		||||
    public function __construct(public string $message)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    public function __construct(public string $message) {}
 | 
			
		||||
 | 
			
		||||
    public function via(object $notifiable): array
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -15,9 +15,7 @@ class DockerCleanup extends Notification implements ShouldQueue
 | 
			
		||||
 | 
			
		||||
    public $tries = 1;
 | 
			
		||||
 | 
			
		||||
    public function __construct(public Server $server, public string $message)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    public function __construct(public Server $server, public string $message) {}
 | 
			
		||||
 | 
			
		||||
    public function via(object $notifiable): array
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -17,9 +17,7 @@ class ForceDisabled extends Notification implements ShouldQueue
 | 
			
		||||
 | 
			
		||||
    public $tries = 1;
 | 
			
		||||
 | 
			
		||||
    public function __construct(public Server $server)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    public function __construct(public Server $server) {}
 | 
			
		||||
 | 
			
		||||
    public function via(object $notifiable): array
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -17,9 +17,7 @@ class ForceEnabled extends Notification implements ShouldQueue
 | 
			
		||||
 | 
			
		||||
    public $tries = 1;
 | 
			
		||||
 | 
			
		||||
    public function __construct(public Server $server)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    public function __construct(public Server $server) {}
 | 
			
		||||
 | 
			
		||||
    public function via(object $notifiable): array
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -17,9 +17,7 @@ class HighDiskUsage extends Notification implements ShouldQueue
 | 
			
		||||
 | 
			
		||||
    public $tries = 1;
 | 
			
		||||
 | 
			
		||||
    public function __construct(public Server $server, public int $disk_usage, public int $cleanup_after_percentage)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    public function __construct(public Server $server, public int $disk_usage, public int $cleanup_after_percentage) {}
 | 
			
		||||
 | 
			
		||||
    public function via(object $notifiable): array
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -24,7 +24,7 @@ class Revived extends Notification implements ShouldQueue
 | 
			
		||||
        if ($this->server->unreachable_notification_sent === false) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        GetContainersStatus::dispatch($server);
 | 
			
		||||
        GetContainersStatus::dispatch($server)->onQueue('high');
 | 
			
		||||
        // dispatch(new ContainerStatusJob($server));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -17,10 +17,7 @@ class Unreachable extends Notification implements ShouldQueue
 | 
			
		||||
 | 
			
		||||
    public $tries = 1;
 | 
			
		||||
 | 
			
		||||
    public function __construct(public Server $server)
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
    public function __construct(public Server $server) {}
 | 
			
		||||
 | 
			
		||||
    public function via(object $notifiable): array
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -13,9 +13,7 @@ class Test extends Notification implements ShouldQueue
 | 
			
		||||
 | 
			
		||||
    public $tries = 5;
 | 
			
		||||
 | 
			
		||||
    public function __construct(public ?string $emails = null)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    public function __construct(public ?string $emails = null) {}
 | 
			
		||||
 | 
			
		||||
    public function via(object $notifiable): array
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -22,9 +22,7 @@ class InvitationLink extends Notification implements ShouldQueue
 | 
			
		||||
        return [TransactionalEmailChannel::class];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function __construct(public User $user)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    public function __construct(public User $user) {}
 | 
			
		||||
 | 
			
		||||
    public function toMail(): MailMessage
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -14,9 +14,7 @@ class Test extends Notification implements ShouldQueue
 | 
			
		||||
 | 
			
		||||
    public $tries = 5;
 | 
			
		||||
 | 
			
		||||
    public function __construct(public string $emails)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    public function __construct(public string $emails) {}
 | 
			
		||||
 | 
			
		||||
    public function via(): array
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -9,9 +9,7 @@ use Laravel\Sanctum\Sanctum;
 | 
			
		||||
 | 
			
		||||
class AppServiceProvider extends ServiceProvider
 | 
			
		||||
{
 | 
			
		||||
    public function register(): void
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    public function register(): void {}
 | 
			
		||||
 | 
			
		||||
    public function boot(): void
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -22,8 +22,7 @@ class Input extends Component
 | 
			
		||||
        public bool $allowToPeak = true,
 | 
			
		||||
        public bool $isMultiline = false,
 | 
			
		||||
        public string $defaultClass = 'input',
 | 
			
		||||
    ) {
 | 
			
		||||
    }
 | 
			
		||||
    ) {}
 | 
			
		||||
 | 
			
		||||
    public function render(): View|Closure|string
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -19,6 +19,8 @@ class Textarea extends Component
 | 
			
		||||
        public ?string $value = null,
 | 
			
		||||
        public ?string $label = null,
 | 
			
		||||
        public ?string $placeholder = null,
 | 
			
		||||
        public ?string $monacoEditorLanguage = '',
 | 
			
		||||
        public bool $useMonacoEditor = false,
 | 
			
		||||
        public bool $required = false,
 | 
			
		||||
        public bool $disabled = false,
 | 
			
		||||
        public bool $readonly = false,
 | 
			
		||||
 
 | 
			
		||||
@@ -16,9 +16,7 @@ class ResourceView extends Component
 | 
			
		||||
        public ?string $logo = null,
 | 
			
		||||
        public ?string $documentation = null,
 | 
			
		||||
        public bool $upgrade = false,
 | 
			
		||||
    ) {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
    ) {}
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the view / contents that represent the component.
 | 
			
		||||
 
 | 
			
		||||
@@ -14,8 +14,7 @@ class Index extends Component
 | 
			
		||||
    public function __construct(
 | 
			
		||||
        public $resource = null,
 | 
			
		||||
        public bool $showRefreshButton = true,
 | 
			
		||||
    ) {
 | 
			
		||||
    }
 | 
			
		||||
    ) {}
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the view / contents that represent the component.
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,7 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
use Illuminate\Database\Eloquent\Collection;
 | 
			
		||||
 | 
			
		||||
function get_team_id_from_token()
 | 
			
		||||
{
 | 
			
		||||
    $token = auth()->user()->currentAccessToken();
 | 
			
		||||
@@ -10,3 +12,27 @@ function invalid_token()
 | 
			
		||||
{
 | 
			
		||||
    return response()->json(['error' => 'Invalid token.', 'docs' => 'https://coolify.io/docs/api-reference/authorization'], 400);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function serialize_api_response($data)
 | 
			
		||||
{
 | 
			
		||||
    if (! $data instanceof Collection) {
 | 
			
		||||
        $data = collect($data);
 | 
			
		||||
    }
 | 
			
		||||
    $data = $data->sortKeys();
 | 
			
		||||
    $created_at = data_get($data, 'created_at');
 | 
			
		||||
    $updated_at = data_get($data, 'updated_at');
 | 
			
		||||
    if ($created_at) {
 | 
			
		||||
        unset($data['created_at']);
 | 
			
		||||
        $data['created_at'] = $created_at;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
    if ($updated_at) {
 | 
			
		||||
        unset($data['updated_at']);
 | 
			
		||||
        $data['updated_at'] = $updated_at;
 | 
			
		||||
    }
 | 
			
		||||
    if (data_get($data, 'id')) {
 | 
			
		||||
        $data = $data->prepend($data['id'], 'id');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return $data;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,7 @@ use App\Models\Server;
 | 
			
		||||
use App\Models\StandaloneDocker;
 | 
			
		||||
use Spatie\Url\Url;
 | 
			
		||||
 | 
			
		||||
function queue_application_deployment(Application $application, string $deployment_uuid, ?int $pull_request_id = 0, string $commit = 'HEAD', bool $force_rebuild = false, bool $is_webhook = false, bool $restart_only = false, ?string $git_type = null, bool $no_questions_asked = false, ?Server $server = null, ?StandaloneDocker $destination = null, bool $only_this_server = false, bool $rollback = false)
 | 
			
		||||
function queue_application_deployment(Application $application, string $deployment_uuid, ?int $pull_request_id = 0, string $commit = 'HEAD', bool $force_rebuild = false, bool $is_webhook = false, bool $is_api = false, bool $restart_only = false, ?string $git_type = null, bool $no_questions_asked = false, ?Server $server = null, ?StandaloneDocker $destination = null, bool $only_this_server = false, bool $rollback = false)
 | 
			
		||||
{
 | 
			
		||||
    $application_id = $application->id;
 | 
			
		||||
    $deployment_link = Url::fromString($application->link()."/deployment/{$deployment_uuid}");
 | 
			
		||||
@@ -35,6 +35,7 @@ function queue_application_deployment(Application $application, string $deployme
 | 
			
		||||
        'pull_request_id' => $pull_request_id,
 | 
			
		||||
        'force_rebuild' => $force_rebuild,
 | 
			
		||||
        'is_webhook' => $is_webhook,
 | 
			
		||||
        'is_api' => $is_api,
 | 
			
		||||
        'restart_only' => $restart_only,
 | 
			
		||||
        'commit' => $commit,
 | 
			
		||||
        'rollback' => $rollback,
 | 
			
		||||
@@ -45,11 +46,11 @@ function queue_application_deployment(Application $application, string $deployme
 | 
			
		||||
    if ($no_questions_asked) {
 | 
			
		||||
        dispatch(new ApplicationDeploymentJob(
 | 
			
		||||
            application_deployment_queue_id: $deployment->id,
 | 
			
		||||
        ));
 | 
			
		||||
        ))->onQueue('high');
 | 
			
		||||
    } elseif (next_queuable($server_id, $application_id)) {
 | 
			
		||||
        dispatch(new ApplicationDeploymentJob(
 | 
			
		||||
            application_deployment_queue_id: $deployment->id,
 | 
			
		||||
        ));
 | 
			
		||||
        ))->onQueue('high');
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
function force_start_deployment(ApplicationDeploymentQueue $deployment)
 | 
			
		||||
@@ -60,7 +61,7 @@ function force_start_deployment(ApplicationDeploymentQueue $deployment)
 | 
			
		||||
 | 
			
		||||
    dispatch(new ApplicationDeploymentJob(
 | 
			
		||||
        application_deployment_queue_id: $deployment->id,
 | 
			
		||||
    ));
 | 
			
		||||
    ))->onQueue('high');
 | 
			
		||||
}
 | 
			
		||||
function queue_next_deployment(Application $application)
 | 
			
		||||
{
 | 
			
		||||
@@ -73,7 +74,7 @@ function queue_next_deployment(Application $application)
 | 
			
		||||
 | 
			
		||||
        dispatch(new ApplicationDeploymentJob(
 | 
			
		||||
            application_deployment_queue_id: $next_found->id,
 | 
			
		||||
        ));
 | 
			
		||||
        ))->onQueue('high');
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -114,7 +115,7 @@ function next_after_cancel(?Server $server = null)
 | 
			
		||||
 | 
			
		||||
                    dispatch(new ApplicationDeploymentJob(
 | 
			
		||||
                        application_deployment_queue_id: $next->id,
 | 
			
		||||
                    ));
 | 
			
		||||
                    ))->onQueue('high');
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user