mirror of
https://github.com/ershisan99/coolify.git
synced 2026-01-03 12:34:08 +00:00
Compare commits
47 Commits
v4.0.0-bet
...
v4.0.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e9158b7305 | ||
|
|
0f5690db85 | ||
|
|
3ebb35a5cd | ||
|
|
f557cd0933 | ||
|
|
063aa702b1 | ||
|
|
4f1070083a | ||
|
|
5e625f71c5 | ||
|
|
cc36a0ecd1 | ||
|
|
a849c25672 | ||
|
|
8b95b93c72 | ||
|
|
3d9557bc50 | ||
|
|
01f2f56be6 | ||
|
|
e658ed993a | ||
|
|
58fc897ea5 | ||
|
|
f8c5a35b56 | ||
|
|
2c92cc40e1 | ||
|
|
1266810c4d | ||
|
|
1de8657a56 | ||
|
|
3a1e5f7f0c | ||
|
|
8d85976ac0 | ||
|
|
fe7eaa594f | ||
|
|
5500a1edb3 | ||
|
|
eb27e34972 | ||
|
|
8335c299b8 | ||
|
|
feadc60b14 | ||
|
|
b59799dc2b | ||
|
|
f0b2f6eb00 | ||
|
|
c3fb126a0a | ||
|
|
f6708f6e47 | ||
|
|
d48b5a9079 | ||
|
|
99354f0d7d | ||
|
|
0fa8552aa3 | ||
|
|
4869c388b2 | ||
|
|
2adade0927 | ||
|
|
87b7337d9e | ||
|
|
351c9c1ad3 | ||
|
|
7759fe2cdf | ||
|
|
5d2651afc1 | ||
|
|
ce3b2de5e7 | ||
|
|
1782f59a96 | ||
|
|
3612096b56 | ||
|
|
97aa6139ea | ||
|
|
e5d915a7a9 | ||
|
|
5bc31c305c | ||
|
|
8c7590a249 | ||
|
|
d54d524cef | ||
|
|
a3d3ada500 |
@@ -48,7 +48,7 @@ Special thanks to our biggest sponsors!
|
||||
<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.png" alt="blacksmith 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>
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace App\Actions\CoolifyTask;
|
||||
|
||||
use App\Data\CoolifyTaskArgs;
|
||||
use App\Enums\ActivityTypes;
|
||||
use App\Jobs\CoolifyTask;
|
||||
use Spatie\Activitylog\Models\Activity;
|
||||
|
||||
@@ -40,8 +41,18 @@ class PrepareCoolifyTask
|
||||
|
||||
public function __invoke(): Activity
|
||||
{
|
||||
$job = new CoolifyTask($this->activity, ignore_errors: $this->remoteProcessArgs->ignore_errors, call_event_on_finish: $this->remoteProcessArgs->call_event_on_finish, call_event_data: $this->remoteProcessArgs->call_event_data);
|
||||
dispatch($job);
|
||||
$job = new CoolifyTask(
|
||||
activity: $this->activity,
|
||||
ignore_errors: $this->remoteProcessArgs->ignore_errors,
|
||||
call_event_on_finish: $this->remoteProcessArgs->call_event_on_finish,
|
||||
call_event_data: $this->remoteProcessArgs->call_event_data,
|
||||
);
|
||||
if ($this->remoteProcessArgs->type === ActivityTypes::COMMAND->value) {
|
||||
ray('Dispatching a high priority job');
|
||||
dispatch($job)->onQueue('high');
|
||||
} else {
|
||||
dispatch($job);
|
||||
}
|
||||
$this->activity->refresh();
|
||||
|
||||
return $this->activity;
|
||||
|
||||
@@ -39,7 +39,7 @@ class RunRemoteProcess
|
||||
public function __construct(Activity $activity, bool $hide_from_output = false, bool $ignore_errors = false, $call_event_on_finish = null, $call_event_data = null)
|
||||
{
|
||||
|
||||
if ($activity->getExtraProperty('type') !== ActivityTypes::INLINE->value) {
|
||||
if ($activity->getExtraProperty('type') !== ActivityTypes::INLINE->value && $activity->getExtraProperty('type') !== ActivityTypes::COMMAND->value) {
|
||||
throw new \RuntimeException('Incompatible Activity to run a remote command.');
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
namespace App\Actions\Database;
|
||||
|
||||
use App\Models\StandaloneClickhouse;
|
||||
use Illuminate\Support\Str;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
@@ -155,11 +154,11 @@ class StartClickhouse
|
||||
$environment_variables->push("$env->key=$env->real_value");
|
||||
}
|
||||
|
||||
if ($environment_variables->filter(fn ($env) => Str::of($env)->contains('CLICKHOUSE_ADMIN_USER'))->isEmpty()) {
|
||||
if ($environment_variables->filter(fn ($env) => str($env)->contains('CLICKHOUSE_ADMIN_USER'))->isEmpty()) {
|
||||
$environment_variables->push("CLICKHOUSE_ADMIN_USER={$this->database->clickhouse_admin_user}");
|
||||
}
|
||||
|
||||
if ($environment_variables->filter(fn ($env) => Str::of($env)->contains('CLICKHOUSE_ADMIN_PASSWORD'))->isEmpty()) {
|
||||
if ($environment_variables->filter(fn ($env) => str($env)->contains('CLICKHOUSE_ADMIN_PASSWORD'))->isEmpty()) {
|
||||
$environment_variables->push("CLICKHOUSE_ADMIN_PASSWORD={$this->database->clickhouse_admin_password}");
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
namespace App\Actions\Database;
|
||||
|
||||
use App\Models\StandaloneDragonfly;
|
||||
use Illuminate\Support\Str;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
@@ -155,7 +154,7 @@ class StartDragonfly
|
||||
$environment_variables->push("$env->key=$env->real_value");
|
||||
}
|
||||
|
||||
if ($environment_variables->filter(fn ($env) => Str::of($env)->contains('REDIS_PASSWORD'))->isEmpty()) {
|
||||
if ($environment_variables->filter(fn ($env) => str($env)->contains('REDIS_PASSWORD'))->isEmpty()) {
|
||||
$environment_variables->push("REDIS_PASSWORD={$this->database->dragonfly_password}");
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ namespace App\Actions\Database;
|
||||
|
||||
use App\Models\StandaloneKeydb;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
@@ -163,7 +162,7 @@ class StartKeydb
|
||||
$environment_variables->push("$env->key=$env->real_value");
|
||||
}
|
||||
|
||||
if ($environment_variables->filter(fn ($env) => Str::of($env)->contains('REDIS_PASSWORD'))->isEmpty()) {
|
||||
if ($environment_variables->filter(fn ($env) => str($env)->contains('REDIS_PASSWORD'))->isEmpty()) {
|
||||
$environment_variables->push("REDIS_PASSWORD={$this->database->keydb_password}");
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
namespace App\Actions\Database;
|
||||
|
||||
use App\Models\StandaloneMariadb;
|
||||
use Illuminate\Support\Str;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
@@ -157,18 +156,18 @@ class StartMariadb
|
||||
$environment_variables->push("$env->key=$env->real_value");
|
||||
}
|
||||
|
||||
if ($environment_variables->filter(fn ($env) => Str::of($env)->contains('MARIADB_ROOT_PASSWORD'))->isEmpty()) {
|
||||
if ($environment_variables->filter(fn ($env) => str($env)->contains('MARIADB_ROOT_PASSWORD'))->isEmpty()) {
|
||||
$environment_variables->push("MARIADB_ROOT_PASSWORD={$this->database->mariadb_root_password}");
|
||||
}
|
||||
|
||||
if ($environment_variables->filter(fn ($env) => Str::of($env)->contains('MARIADB_DATABASE'))->isEmpty()) {
|
||||
if ($environment_variables->filter(fn ($env) => str($env)->contains('MARIADB_DATABASE'))->isEmpty()) {
|
||||
$environment_variables->push("MARIADB_DATABASE={$this->database->mariadb_database}");
|
||||
}
|
||||
|
||||
if ($environment_variables->filter(fn ($env) => Str::of($env)->contains('MARIADB_USER'))->isEmpty()) {
|
||||
if ($environment_variables->filter(fn ($env) => str($env)->contains('MARIADB_USER'))->isEmpty()) {
|
||||
$environment_variables->push("MARIADB_USER={$this->database->mariadb_user}");
|
||||
}
|
||||
if ($environment_variables->filter(fn ($env) => Str::of($env)->contains('MARIADB_PASSWORD'))->isEmpty()) {
|
||||
if ($environment_variables->filter(fn ($env) => str($env)->contains('MARIADB_PASSWORD'))->isEmpty()) {
|
||||
$environment_variables->push("MARIADB_PASSWORD={$this->database->mariadb_password}");
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
namespace App\Actions\Database;
|
||||
|
||||
use App\Models\StandaloneMongodb;
|
||||
use Illuminate\Support\Str;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
@@ -174,15 +173,15 @@ class StartMongodb
|
||||
$environment_variables->push("$env->key=$env->real_value");
|
||||
}
|
||||
|
||||
if ($environment_variables->filter(fn ($env) => Str::of($env)->contains('MONGO_INITDB_ROOT_USERNAME'))->isEmpty()) {
|
||||
if ($environment_variables->filter(fn ($env) => str($env)->contains('MONGO_INITDB_ROOT_USERNAME'))->isEmpty()) {
|
||||
$environment_variables->push("MONGO_INITDB_ROOT_USERNAME={$this->database->mongo_initdb_root_username}");
|
||||
}
|
||||
|
||||
if ($environment_variables->filter(fn ($env) => Str::of($env)->contains('MONGO_INITDB_ROOT_PASSWORD'))->isEmpty()) {
|
||||
if ($environment_variables->filter(fn ($env) => str($env)->contains('MONGO_INITDB_ROOT_PASSWORD'))->isEmpty()) {
|
||||
$environment_variables->push("MONGO_INITDB_ROOT_PASSWORD={$this->database->mongo_initdb_root_password}");
|
||||
}
|
||||
|
||||
if ($environment_variables->filter(fn ($env) => Str::of($env)->contains('MONGO_INITDB_DATABASE'))->isEmpty()) {
|
||||
if ($environment_variables->filter(fn ($env) => str($env)->contains('MONGO_INITDB_DATABASE'))->isEmpty()) {
|
||||
$environment_variables->push("MONGO_INITDB_DATABASE={$this->database->mongo_initdb_database}");
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
namespace App\Actions\Database;
|
||||
|
||||
use App\Models\StandaloneMysql;
|
||||
use Illuminate\Support\Str;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
@@ -157,18 +156,18 @@ class StartMysql
|
||||
$environment_variables->push("$env->key=$env->real_value");
|
||||
}
|
||||
|
||||
if ($environment_variables->filter(fn ($env) => Str::of($env)->contains('MYSQL_ROOT_PASSWORD'))->isEmpty()) {
|
||||
if ($environment_variables->filter(fn ($env) => str($env)->contains('MYSQL_ROOT_PASSWORD'))->isEmpty()) {
|
||||
$environment_variables->push("MYSQL_ROOT_PASSWORD={$this->database->mysql_root_password}");
|
||||
}
|
||||
|
||||
if ($environment_variables->filter(fn ($env) => Str::of($env)->contains('MYSQL_DATABASE'))->isEmpty()) {
|
||||
if ($environment_variables->filter(fn ($env) => str($env)->contains('MYSQL_DATABASE'))->isEmpty()) {
|
||||
$environment_variables->push("MYSQL_DATABASE={$this->database->mysql_database}");
|
||||
}
|
||||
|
||||
if ($environment_variables->filter(fn ($env) => Str::of($env)->contains('MYSQL_USER'))->isEmpty()) {
|
||||
if ($environment_variables->filter(fn ($env) => str($env)->contains('MYSQL_USER'))->isEmpty()) {
|
||||
$environment_variables->push("MYSQL_USER={$this->database->mysql_user}");
|
||||
}
|
||||
if ($environment_variables->filter(fn ($env) => Str::of($env)->contains('MYSQL_PASSWORD'))->isEmpty()) {
|
||||
if ($environment_variables->filter(fn ($env) => str($env)->contains('MYSQL_PASSWORD'))->isEmpty()) {
|
||||
$environment_variables->push("MYSQL_PASSWORD={$this->database->mysql_password}");
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
namespace App\Actions\Database;
|
||||
|
||||
use App\Models\StandalonePostgresql;
|
||||
use Illuminate\Support\Str;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
@@ -179,18 +178,18 @@ class StartPostgresql
|
||||
$environment_variables->push("$env->key=$env->real_value");
|
||||
}
|
||||
|
||||
if ($environment_variables->filter(fn ($env) => Str::of($env)->contains('POSTGRES_USER'))->isEmpty()) {
|
||||
if ($environment_variables->filter(fn ($env) => str($env)->contains('POSTGRES_USER'))->isEmpty()) {
|
||||
$environment_variables->push("POSTGRES_USER={$this->database->postgres_user}");
|
||||
}
|
||||
if ($environment_variables->filter(fn ($env) => Str::of($env)->contains('PGUSER'))->isEmpty()) {
|
||||
if ($environment_variables->filter(fn ($env) => str($env)->contains('PGUSER'))->isEmpty()) {
|
||||
$environment_variables->push("PGUSER={$this->database->postgres_user}");
|
||||
}
|
||||
|
||||
if ($environment_variables->filter(fn ($env) => Str::of($env)->contains('POSTGRES_PASSWORD'))->isEmpty()) {
|
||||
if ($environment_variables->filter(fn ($env) => str($env)->contains('POSTGRES_PASSWORD'))->isEmpty()) {
|
||||
$environment_variables->push("POSTGRES_PASSWORD={$this->database->postgres_password}");
|
||||
}
|
||||
|
||||
if ($environment_variables->filter(fn ($env) => Str::of($env)->contains('POSTGRES_DB'))->isEmpty()) {
|
||||
if ($environment_variables->filter(fn ($env) => str($env)->contains('POSTGRES_DB'))->isEmpty()) {
|
||||
$environment_variables->push("POSTGRES_DB={$this->database->postgres_db}");
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ namespace App\Actions\Database;
|
||||
|
||||
use App\Models\StandaloneRedis;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
@@ -167,7 +166,7 @@ class StartRedis
|
||||
$environment_variables->push("$env->key=$env->real_value");
|
||||
}
|
||||
|
||||
if ($environment_variables->filter(fn ($env) => Str::of($env)->contains('REDIS_PASSWORD'))->isEmpty()) {
|
||||
if ($environment_variables->filter(fn ($env) => str($env)->contains('REDIS_PASSWORD'))->isEmpty()) {
|
||||
$environment_variables->push("REDIS_PASSWORD={$this->database->redis_password}");
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
namespace App\Actions\Proxy;
|
||||
|
||||
use App\Models\Server;
|
||||
use Illuminate\Support\Str;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
|
||||
class CheckConfiguration
|
||||
@@ -24,7 +23,7 @@ class CheckConfiguration
|
||||
$proxy_configuration = instant_remote_process($payload, $server, false);
|
||||
|
||||
if ($reset || ! $proxy_configuration || is_null($proxy_configuration)) {
|
||||
$proxy_configuration = Str::of(generate_default_proxy_configuration($server))->trim()->value;
|
||||
$proxy_configuration = str(generate_default_proxy_configuration($server))->trim()->value;
|
||||
}
|
||||
if (! $proxy_configuration || is_null($proxy_configuration)) {
|
||||
throw new \Exception('Could not generate proxy configuration');
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
namespace App\Actions\Proxy;
|
||||
|
||||
use App\Models\Server;
|
||||
use Illuminate\Support\Str;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
|
||||
class SaveConfiguration
|
||||
@@ -18,7 +17,7 @@ class SaveConfiguration
|
||||
$proxy_path = $server->proxyPath();
|
||||
$docker_compose_yml_base64 = base64_encode($proxy_settings);
|
||||
|
||||
$server->proxy->last_saved_settings = Str::of($docker_compose_yml_base64)->pipe('md5')->value;
|
||||
$server->proxy->last_saved_settings = str($docker_compose_yml_base64)->pipe('md5')->value;
|
||||
$server->save();
|
||||
|
||||
return instant_remote_process([
|
||||
|
||||
@@ -4,7 +4,6 @@ namespace App\Actions\Proxy;
|
||||
|
||||
use App\Events\ProxyStarted;
|
||||
use App\Models\Server;
|
||||
use Illuminate\Support\Str;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
use Spatie\Activitylog\Models\Activity;
|
||||
|
||||
@@ -27,7 +26,7 @@ class StartProxy
|
||||
}
|
||||
SaveConfiguration::run($server, $configuration);
|
||||
$docker_compose_yml_base64 = base64_encode($configuration);
|
||||
$server->proxy->last_applied_settings = Str::of($docker_compose_yml_base64)->pipe('md5')->value;
|
||||
$server->proxy->last_applied_settings = str($docker_compose_yml_base64)->pipe('md5')->value;
|
||||
$server->save();
|
||||
if ($server->isSwarm()) {
|
||||
$commands = $commands->merge([
|
||||
|
||||
19
app/Actions/Server/RunCommand.php
Normal file
19
app/Actions/Server/RunCommand.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Actions\Server;
|
||||
|
||||
use App\Enums\ActivityTypes;
|
||||
use App\Models\Server;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
|
||||
class RunCommand
|
||||
{
|
||||
use AsAction;
|
||||
|
||||
public function handle(Server $server, $command)
|
||||
{
|
||||
$activity = remote_process(command: [$command], server: $server, ignore_errors: true, type: ActivityTypes::COMMAND->value);
|
||||
|
||||
return $activity;
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@ class UpdateCoolify
|
||||
if (! $this->server) {
|
||||
return;
|
||||
}
|
||||
CleanupDocker::run($this->server, false);
|
||||
CleanupDocker::dispatch($this->server, false)->onQueue('high');
|
||||
$this->latestVersion = get_latest_version_of_coolify();
|
||||
$this->currentVersion = config('version');
|
||||
if (! $manual_update) {
|
||||
@@ -48,6 +48,7 @@ class UpdateCoolify
|
||||
private function update()
|
||||
{
|
||||
if (isDev()) {
|
||||
ray('Running in dev mode');
|
||||
remote_process([
|
||||
'sleep 10',
|
||||
], $this->server);
|
||||
|
||||
@@ -82,7 +82,7 @@ class WaitlistInvite extends Command
|
||||
if (! $already_registered) {
|
||||
$this->password = Str::password();
|
||||
User::create([
|
||||
'name' => Str::of($this->next_patient->email)->before('@'),
|
||||
'name' => str($this->next_patient->email)->before('@'),
|
||||
'email' => $this->next_patient->email,
|
||||
'password' => Hash::make($this->password),
|
||||
'force_password_reset' => true,
|
||||
|
||||
@@ -5,4 +5,5 @@ namespace App\Enums;
|
||||
enum ActivityTypes: string
|
||||
{
|
||||
case INLINE = 'inline';
|
||||
case COMMAND = 'command';
|
||||
}
|
||||
|
||||
@@ -81,8 +81,8 @@ class Controller extends BaseController
|
||||
$token = request()->get('token');
|
||||
if ($token) {
|
||||
$decrypted = Crypt::decryptString($token);
|
||||
$email = Str::of($decrypted)->before('@@@');
|
||||
$password = Str::of($decrypted)->after('@@@');
|
||||
$email = str($decrypted)->before('@@@');
|
||||
$password = str($decrypted)->after('@@@');
|
||||
$user = User::whereEmail($email)->first();
|
||||
if (! $user) {
|
||||
return redirect()->route('login');
|
||||
|
||||
@@ -965,6 +965,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
$nixpacks_php_fallback_path = new EnvironmentVariable();
|
||||
$nixpacks_php_fallback_path->key = 'NIXPACKS_PHP_FALLBACK_PATH';
|
||||
$nixpacks_php_fallback_path->value = '/index.php';
|
||||
$nixpacks_php_fallback_path->is_build_time = false;
|
||||
$nixpacks_php_fallback_path->application_id = $this->application->id;
|
||||
$nixpacks_php_fallback_path->save();
|
||||
}
|
||||
@@ -972,6 +973,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
$nixpacks_php_root_dir = new EnvironmentVariable();
|
||||
$nixpacks_php_root_dir->key = 'NIXPACKS_PHP_ROOT_DIR';
|
||||
$nixpacks_php_root_dir->value = '/app/public';
|
||||
$nixpacks_php_root_dir->is_build_time = false;
|
||||
$nixpacks_php_root_dir->application_id = $this->application->id;
|
||||
$nixpacks_php_root_dir->save();
|
||||
}
|
||||
@@ -1076,13 +1078,13 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
$this->application_deployment_queue->addLogEntry("Healthcheck logs: {$health_check_logs} | Return code: {$health_check_return_code}");
|
||||
}
|
||||
|
||||
if (Str::of($this->saved_outputs->get('health_check'))->replace('"', '')->value() === 'healthy') {
|
||||
if (str($this->saved_outputs->get('health_check'))->replace('"', '')->value() === 'healthy') {
|
||||
$this->newVersionIsHealthy = true;
|
||||
$this->application->update(['status' => 'running']);
|
||||
$this->application_deployment_queue->addLogEntry('New container is healthy.');
|
||||
break;
|
||||
}
|
||||
if (Str::of($this->saved_outputs->get('health_check'))->replace('"', '')->value() === 'unhealthy') {
|
||||
if (str($this->saved_outputs->get('health_check'))->replace('"', '')->value() === 'unhealthy') {
|
||||
$this->newVersionIsHealthy = false;
|
||||
$this->query_logs();
|
||||
break;
|
||||
@@ -1094,7 +1096,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
$sleeptime++;
|
||||
}
|
||||
}
|
||||
if (Str::of($this->saved_outputs->get('health_check'))->replace('"', '')->value() === 'starting') {
|
||||
if (str($this->saved_outputs->get('health_check'))->replace('"', '')->value() === 'starting') {
|
||||
$this->query_logs();
|
||||
}
|
||||
}
|
||||
@@ -1535,7 +1537,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
$this->execute_remote_command([
|
||||
executeInDocker($this->deployment_uuid, "cat {$this->workdir}{$this->dockerfile_location}"), 'hidden' => true, 'save' => 'dockerfile_from_repo', 'ignore_errors' => true,
|
||||
]);
|
||||
$dockerfile = collect(Str::of($this->saved_outputs->get('dockerfile_from_repo'))->trim()->explode("\n"));
|
||||
$dockerfile = collect(str($this->saved_outputs->get('dockerfile_from_repo'))->trim()->explode("\n"));
|
||||
$this->application->parseHealthcheckFromDockerfile($dockerfile);
|
||||
}
|
||||
$docker_compose = [
|
||||
@@ -2107,7 +2109,7 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
|
||||
$this->execute_remote_command([
|
||||
executeInDocker($this->deployment_uuid, "cat {$this->workdir}{$this->dockerfile_location}"), 'hidden' => true, 'save' => 'dockerfile',
|
||||
]);
|
||||
$dockerfile = collect(Str::of($this->saved_outputs->get('dockerfile'))->trim()->explode("\n"));
|
||||
$dockerfile = collect(str($this->saved_outputs->get('dockerfile'))->trim()->explode("\n"));
|
||||
if ($this->pull_request_id === 0) {
|
||||
foreach ($this->application->build_environment_variables as $env) {
|
||||
if (data_get($env, 'is_multiline') === true) {
|
||||
|
||||
@@ -20,9 +20,9 @@ class CoolifyTask implements ShouldBeEncrypted, ShouldQueue
|
||||
*/
|
||||
public function __construct(
|
||||
public Activity $activity,
|
||||
public bool $ignore_errors = false,
|
||||
public $call_event_on_finish = null,
|
||||
public $call_event_data = null
|
||||
public bool $ignore_errors,
|
||||
public $call_event_on_finish,
|
||||
public $call_event_data,
|
||||
) {}
|
||||
|
||||
/**
|
||||
|
||||
@@ -98,7 +98,7 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
|
||||
|
||||
return;
|
||||
}
|
||||
$status = Str::of(data_get($this->database, 'status'));
|
||||
$status = str(data_get($this->database, 'status'));
|
||||
if (! $status->startsWith('running') && $this->database->id !== 0) {
|
||||
ray('database not running');
|
||||
|
||||
@@ -236,7 +236,7 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
|
||||
return;
|
||||
}
|
||||
}
|
||||
$this->backup_dir = backup_dir().'/databases/'.Str::of($this->team->name)->slug().'-'.$this->team->id.'/'.$this->directory_name;
|
||||
$this->backup_dir = backup_dir().'/databases/'.str($this->team->name)->slug().'-'.$this->team->id.'/'.$this->directory_name;
|
||||
|
||||
if ($this->database->name === 'coolify-db') {
|
||||
$databasesToBackup = ['coolify'];
|
||||
|
||||
@@ -5,7 +5,6 @@ namespace App\Livewire\Project\Application;
|
||||
use App\Models\Application;
|
||||
use App\Models\LocalFileVolume;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Str;
|
||||
use Livewire\Component;
|
||||
use Visus\Cuid2\Cuid2;
|
||||
|
||||
@@ -199,8 +198,8 @@ class General extends Component
|
||||
return str($volume)->startsWith('/data/coolify');
|
||||
})->unique()->values();
|
||||
foreach ($volumes as $volume) {
|
||||
$source = Str::of($volume)->before(':');
|
||||
$target = Str::of($volume)->after(':')->beforeLast(':');
|
||||
$source = str($volume)->before(':');
|
||||
$target = str($volume)->after(':')->beforeLast(':');
|
||||
|
||||
LocalFileVolume::updateOrCreate(
|
||||
[
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
namespace App\Livewire\Project\Application\Preview;
|
||||
|
||||
use App\Models\Application;
|
||||
use Illuminate\Support\Str;
|
||||
use Livewire\Component;
|
||||
use Spatie\Url\Url;
|
||||
|
||||
@@ -32,10 +31,10 @@ class Form extends Component
|
||||
public function generate_real_url()
|
||||
{
|
||||
if (data_get($this->application, 'fqdn')) {
|
||||
$firstFqdn = Str::of($this->application->fqdn)->before(',');
|
||||
$firstFqdn = str($this->application->fqdn)->before(',');
|
||||
$url = Url::fromString($firstFqdn);
|
||||
$host = $url->getHost();
|
||||
$this->preview_url_template = Str::of($this->application->preview_url_template)->replace('{{domain}}', $host);
|
||||
$this->preview_url_template = str($this->application->preview_url_template)->replace('{{domain}}', $host);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
namespace App\Livewire\Project\Application;
|
||||
|
||||
use App\Models\Application;
|
||||
use Illuminate\Support\Str;
|
||||
use Livewire\Component;
|
||||
use Visus\Cuid2\Cuid2;
|
||||
|
||||
@@ -50,16 +49,16 @@ class Rollback extends Component
|
||||
$output = instant_remote_process([
|
||||
"docker inspect --format='{{.Config.Image}}' {$this->application->uuid}",
|
||||
], $this->application->destination->server, throwError: false);
|
||||
$current_tag = Str::of($output)->trim()->explode(':');
|
||||
$current_tag = str($output)->trim()->explode(':');
|
||||
$this->current = data_get($current_tag, 1);
|
||||
|
||||
$output = instant_remote_process([
|
||||
"docker images --format '{{.Repository}}#{{.Tag}}#{{.CreatedAt}}'",
|
||||
], $this->application->destination->server);
|
||||
$this->images = Str::of($output)->trim()->explode("\n")->filter(function ($item) use ($image) {
|
||||
return Str::of($item)->contains($image);
|
||||
$this->images = str($output)->trim()->explode("\n")->filter(function ($item) use ($image) {
|
||||
return str($item)->contains($image);
|
||||
})->map(function ($item) {
|
||||
$item = Str::of($item)->explode('#');
|
||||
$item = str($item)->explode('#');
|
||||
if ($item[1] === $this->current) {
|
||||
// $is_current = true;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ use App\Models\Application;
|
||||
use App\Models\Project;
|
||||
use App\Models\StandaloneDocker;
|
||||
use App\Models\SwarmDocker;
|
||||
use Illuminate\Support\Str;
|
||||
use Livewire\Component;
|
||||
use Visus\Cuid2\Cuid2;
|
||||
|
||||
@@ -29,9 +28,9 @@ class DockerImage extends Component
|
||||
$this->validate([
|
||||
'dockerImage' => 'required',
|
||||
]);
|
||||
$image = Str::of($this->dockerImage)->before(':');
|
||||
if (Str::of($this->dockerImage)->contains(':')) {
|
||||
$tag = Str::of($this->dockerImage)->after(':');
|
||||
$image = str($this->dockerImage)->before(':');
|
||||
if (str($this->dockerImage)->contains(':')) {
|
||||
$tag = str($this->dockerImage)->after(':');
|
||||
} else {
|
||||
$tag = 'latest';
|
||||
}
|
||||
|
||||
@@ -193,7 +193,7 @@ class GithubPrivateRepositoryDeployKey extends Component
|
||||
|
||||
return;
|
||||
}
|
||||
if (Str::of($this->repository_url)->startsWith('http')) {
|
||||
if (str($this->repository_url)->startsWith('http')) {
|
||||
$this->git_host = $this->repository_url_parsed->getHost();
|
||||
$this->git_repository = $this->repository_url_parsed->getSegment(1).'/'.$this->repository_url_parsed->getSegment(2);
|
||||
$this->git_repository = Str::finish("git@$this->git_host:$this->git_repository", '.git');
|
||||
|
||||
@@ -11,7 +11,7 @@ class EditCompose extends Component
|
||||
|
||||
public $serviceId;
|
||||
|
||||
protected $listeners = ['refreshEnvs' => 'mount'];
|
||||
protected $listeners = ['refreshEnvs', 'envsUpdated'];
|
||||
|
||||
protected $rules = [
|
||||
'service.docker_compose_raw' => 'required',
|
||||
@@ -19,6 +19,17 @@ class EditCompose extends Component
|
||||
'service.is_container_label_escape_enabled' => 'required',
|
||||
];
|
||||
|
||||
public function envsUpdated()
|
||||
{
|
||||
$this->dispatch('saveCompose', $this->service->docker_compose_raw);
|
||||
$this->refreshEnvs();
|
||||
}
|
||||
|
||||
public function refreshEnvs()
|
||||
{
|
||||
$this->service = Service::find($this->serviceId);
|
||||
}
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->service = Service::find($this->serviceId);
|
||||
|
||||
@@ -14,7 +14,6 @@ use App\Models\StandaloneMongodb;
|
||||
use App\Models\StandaloneMysql;
|
||||
use App\Models\StandalonePostgresql;
|
||||
use App\Models\StandaloneRedis;
|
||||
use Illuminate\Support\Str;
|
||||
use Livewire\Component;
|
||||
|
||||
class FileStorage extends Component
|
||||
@@ -37,9 +36,9 @@ class FileStorage extends Component
|
||||
public function mount()
|
||||
{
|
||||
$this->resource = $this->fileStorage->service;
|
||||
if (Str::of($this->fileStorage->fs_path)->startsWith('.')) {
|
||||
if (str($this->fileStorage->fs_path)->startsWith('.')) {
|
||||
$this->workdir = $this->resource->service?->workdir();
|
||||
$this->fs_path = Str::of($this->fileStorage->fs_path)->after('.');
|
||||
$this->fs_path = str($this->fileStorage->fs_path)->after('.');
|
||||
} else {
|
||||
$this->workdir = null;
|
||||
$this->fs_path = $this->fileStorage->fs_path;
|
||||
|
||||
@@ -81,7 +81,6 @@ class StackForm extends Component
|
||||
return handleError($e, $this);
|
||||
} finally {
|
||||
if (is_null($this->service->config_hash)) {
|
||||
ray('asdf');
|
||||
$this->service->isConfigurationChanged(true);
|
||||
} else {
|
||||
$this->dispatch('configurationChanged');
|
||||
|
||||
@@ -112,7 +112,7 @@ class Show extends Component
|
||||
$this->serialize();
|
||||
$this->env->save();
|
||||
$this->dispatch('success', 'Environment variable updated.');
|
||||
$this->dispatch('refreshEnvs');
|
||||
$this->dispatch('envsUpdated');
|
||||
} catch (\Exception $e) {
|
||||
return handleError($e);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Livewire\Project\Shared;
|
||||
|
||||
use App\Actions\Server\RunCommand;
|
||||
use App\Models\Application;
|
||||
use App\Models\Server;
|
||||
use App\Models\Service;
|
||||
@@ -137,7 +138,7 @@ class ExecuteContainerCommand extends Component
|
||||
} else {
|
||||
$exec = "docker exec {$container_name} {$cmd}";
|
||||
}
|
||||
$activity = remote_process([$exec], $server, ignore_errors: true);
|
||||
$activity = RunCommand::run(server: $server, command: $exec);
|
||||
$this->dispatch('activityMonitor', $activity->id);
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Livewire;
|
||||
|
||||
use App\Actions\Server\RunCommand as ServerRunCommand;
|
||||
use App\Models\Server;
|
||||
use Livewire\Component;
|
||||
|
||||
@@ -33,7 +34,7 @@ class RunCommand extends Component
|
||||
{
|
||||
$this->validate();
|
||||
try {
|
||||
$activity = remote_process([$this->command], Server::where('uuid', $this->server)->first(), ignore_errors: true);
|
||||
$activity = ServerRunCommand::run(server: Server::where('uuid', $this->server)->first(), command: $this->command);
|
||||
$this->dispatch('activityMonitor', $activity->id);
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
|
||||
@@ -6,7 +6,6 @@ use App\Actions\Proxy\CheckConfiguration;
|
||||
use App\Actions\Proxy\SaveConfiguration;
|
||||
use App\Actions\Proxy\StartProxy;
|
||||
use App\Models\Server;
|
||||
use Illuminate\Support\Str;
|
||||
use Livewire\Component;
|
||||
|
||||
class Proxy extends Component
|
||||
@@ -79,7 +78,7 @@ class Proxy extends Component
|
||||
{
|
||||
try {
|
||||
$this->proxy_settings = CheckConfiguration::run($this->server);
|
||||
if (Str::of($this->proxy_settings)->contains('--api.dashboard=true') && Str::of($this->proxy_settings)->contains('--api.insecure=true')) {
|
||||
if (str($this->proxy_settings)->contains('--api.dashboard=true') && str($this->proxy_settings)->contains('--api.insecure=true')) {
|
||||
$this->dispatch('traefikDashboardAvailable', true);
|
||||
} else {
|
||||
$this->dispatch('traefikDashboardAvailable', false);
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
namespace App\Livewire\Subscription;
|
||||
|
||||
use App\Models\Team;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Livewire\Component;
|
||||
|
||||
class Actions extends Component
|
||||
@@ -15,70 +14,6 @@ class Actions extends Component
|
||||
$this->server_limits = Team::serverLimit();
|
||||
}
|
||||
|
||||
public function cancel()
|
||||
{
|
||||
try {
|
||||
$subscription_id = currentTeam()->subscription->lemon_subscription_id;
|
||||
if (! $subscription_id) {
|
||||
throw new \Exception('No subscription found');
|
||||
}
|
||||
$response = Http::withHeaders([
|
||||
'Accept' => 'application/vnd.api+json',
|
||||
'Content-Type' => 'application/vnd.api+json',
|
||||
'Authorization' => 'Bearer '.config('subscription.lemon_squeezy_api_key'),
|
||||
])->delete('https://api.lemonsqueezy.com/v1/subscriptions/'.$subscription_id);
|
||||
$json = $response->json();
|
||||
if ($response->failed()) {
|
||||
$error = data_get($json, 'errors.0.status');
|
||||
if ($error === '404') {
|
||||
throw new \Exception('Subscription not found.');
|
||||
}
|
||||
throw new \Exception(data_get($json, 'errors.0.title', 'Something went wrong. Please try again later.'));
|
||||
} else {
|
||||
$this->dispatch('success', 'Subscription cancelled successfully. Reloading in 5s.');
|
||||
$this->dispatch('reloadWindow', 5000);
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
}
|
||||
|
||||
public function resume()
|
||||
{
|
||||
try {
|
||||
$subscription_id = currentTeam()->subscription->lemon_subscription_id;
|
||||
if (! $subscription_id) {
|
||||
throw new \Exception('No subscription found');
|
||||
}
|
||||
$response = Http::withHeaders([
|
||||
'Accept' => 'application/vnd.api+json',
|
||||
'Content-Type' => 'application/vnd.api+json',
|
||||
'Authorization' => 'Bearer '.config('subscription.lemon_squeezy_api_key'),
|
||||
])->patch('https://api.lemonsqueezy.com/v1/subscriptions/'.$subscription_id, [
|
||||
'data' => [
|
||||
'type' => 'subscriptions',
|
||||
'id' => $subscription_id,
|
||||
'attributes' => [
|
||||
'cancelled' => false,
|
||||
],
|
||||
],
|
||||
]);
|
||||
$json = $response->json();
|
||||
if ($response->failed()) {
|
||||
$error = data_get($json, 'errors.0.status');
|
||||
if ($error === '404') {
|
||||
throw new \Exception('Subscription not found.');
|
||||
}
|
||||
throw new \Exception(data_get($json, 'errors.0.title', 'Something went wrong. Please try again later.'));
|
||||
} else {
|
||||
$this->dispatch('success', 'Subscription resumed successfully. Reloading in 5s.');
|
||||
$this->dispatch('reloadWindow', 5000);
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
}
|
||||
|
||||
public function stripeCustomerPortal()
|
||||
{
|
||||
$session = getStripeCustomerPortalSession(currentTeam());
|
||||
|
||||
@@ -52,7 +52,7 @@ class InviteLink extends Component
|
||||
if (is_null($user)) {
|
||||
$password = Str::password();
|
||||
$user = User::create([
|
||||
'name' => Str::of($this->email)->before('@'),
|
||||
'name' => str($this->email)->before('@'),
|
||||
'email' => $this->email,
|
||||
'password' => Hash::make($password),
|
||||
'force_password_reset' => true,
|
||||
|
||||
@@ -28,11 +28,11 @@ class Application extends BaseModel
|
||||
}
|
||||
$application->forceFill([
|
||||
'fqdn' => $application->fqdn,
|
||||
'install_command' => Str::of($application->install_command)->trim(),
|
||||
'build_command' => Str::of($application->build_command)->trim(),
|
||||
'start_command' => Str::of($application->start_command)->trim(),
|
||||
'base_directory' => Str::of($application->base_directory)->trim(),
|
||||
'publish_directory' => Str::of($application->publish_directory)->trim(),
|
||||
'install_command' => str($application->install_command)->trim(),
|
||||
'build_command' => str($application->build_command)->trim(),
|
||||
'start_command' => str($application->start_command)->trim(),
|
||||
'base_directory' => str($application->base_directory)->trim(),
|
||||
'publish_directory' => str($application->publish_directory)->trim(),
|
||||
]);
|
||||
});
|
||||
static::created(function ($application) {
|
||||
@@ -902,9 +902,9 @@ class Application extends BaseModel
|
||||
$type = null;
|
||||
$source = null;
|
||||
if (is_string($volume)) {
|
||||
$source = Str::of($volume)->before(':');
|
||||
$source = str($volume)->before(':');
|
||||
if ($source->startsWith('./') || $source->startsWith('/') || $source->startsWith('~')) {
|
||||
$type = Str::of('bind');
|
||||
$type = str('bind');
|
||||
}
|
||||
} elseif (is_array($volume)) {
|
||||
$type = data_get_str($volume, 'type');
|
||||
|
||||
@@ -174,7 +174,7 @@ class EnvironmentVariable extends Model
|
||||
if (str($environment_variable)->startsWith('{{'.$type) && str($environment_variable)->endsWith('}}')) {
|
||||
$variable = Str::after($environment_variable, "{$type}.");
|
||||
$variable = Str::before($variable, '}}');
|
||||
$variable = Str::of($variable)->trim()->value;
|
||||
$variable = str($variable)->trim()->value;
|
||||
if (! collect(SHARED_VARIABLE_TYPES)->contains($type)) {
|
||||
return $variable;
|
||||
}
|
||||
@@ -220,7 +220,7 @@ class EnvironmentVariable extends Model
|
||||
protected function key(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
set: fn (string $value) => Str::of($value)->trim(),
|
||||
set: fn (string $value) => str($value)->trim(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class LocalPersistentVolume extends Model
|
||||
{
|
||||
@@ -33,14 +32,14 @@ class LocalPersistentVolume extends Model
|
||||
protected function name(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
set: fn (string $value) => Str::of($value)->trim()->value,
|
||||
set: fn (string $value) => str($value)->trim()->value,
|
||||
);
|
||||
}
|
||||
|
||||
protected function mountPath(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
set: fn (string $value) => Str::of($value)->trim()->start('/')->value
|
||||
set: fn (string $value) => str($value)->trim()->start('/')->value
|
||||
);
|
||||
}
|
||||
|
||||
@@ -49,7 +48,7 @@ class LocalPersistentVolume extends Model
|
||||
return Attribute::make(
|
||||
set: function (?string $value) {
|
||||
if ($value) {
|
||||
return Str::of($value)->trim()->start('/')->value;
|
||||
return str($value)->trim()->start('/')->value;
|
||||
} else {
|
||||
return $value;
|
||||
}
|
||||
|
||||
@@ -116,10 +116,14 @@ class Project extends BaseModel
|
||||
public function default_environment()
|
||||
{
|
||||
$default = $this->environments()->where('name', 'production')->first();
|
||||
if (! $default) {
|
||||
$default = $this->environments()->sortBy('created_at')->first();
|
||||
if ($default) {
|
||||
return $default->name;
|
||||
}
|
||||
$default = $this->environments()->get();
|
||||
if ($default->count() > 0) {
|
||||
return $default->sortBy('created_at')->first()->name;
|
||||
}
|
||||
|
||||
return $default;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ 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;
|
||||
use Spatie\SchemalessAttributes\Casts\SchemalessAttributes;
|
||||
use Spatie\SchemalessAttributes\SchemalessAttributesTrait;
|
||||
@@ -29,10 +28,10 @@ class Server extends BaseModel
|
||||
static::saving(function ($server) {
|
||||
$payload = [];
|
||||
if ($server->user) {
|
||||
$payload['user'] = Str::of($server->user)->trim();
|
||||
$payload['user'] = str($server->user)->trim();
|
||||
}
|
||||
if ($server->ip) {
|
||||
$payload['ip'] = Str::of($server->ip)->trim();
|
||||
$payload['ip'] = str($server->ip)->trim();
|
||||
}
|
||||
$server->forceFill($payload);
|
||||
});
|
||||
@@ -875,7 +874,7 @@ $schema://$host {
|
||||
$releaseLines = collect(explode("\n", $os_release));
|
||||
$collectedData = collect([]);
|
||||
foreach ($releaseLines as $line) {
|
||||
$item = Str::of($line)->trim();
|
||||
$item = str($line)->trim();
|
||||
$collectedData->put($item->before('=')->value(), $item->after('=')->lower()->replace('"', '')->value());
|
||||
}
|
||||
$ID = data_get($collectedData, 'ID');
|
||||
|
||||
@@ -839,29 +839,13 @@ class Service extends BaseModel
|
||||
$commands[] = "cd $workdir";
|
||||
|
||||
$json = Yaml::parse($this->docker_compose);
|
||||
$envs_from_coolify = $this->environment_variables()->get();
|
||||
foreach ($json['services'] as $service => $config) {
|
||||
$envs = collect($config['environment']);
|
||||
$envs->push("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";
|
||||
$commands[] = 'rm -f .env || true';
|
||||
|
||||
$envs_from_coolify = $this->environment_variables()->get();
|
||||
foreach ($envs_from_coolify as $env) {
|
||||
$commands[] = "echo '{$env->key}={$env->real_value}' >> .env";
|
||||
}
|
||||
@@ -880,7 +864,6 @@ class Service extends BaseModel
|
||||
{
|
||||
$networks = getTopLevelNetworks($this);
|
||||
|
||||
// ray($networks);
|
||||
return $networks;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,22 +15,7 @@ class Subscription extends Model
|
||||
|
||||
public function type()
|
||||
{
|
||||
if (isLemon()) {
|
||||
$basic = explode(',', config('subscription.lemon_squeezy_basic_plan_ids'));
|
||||
$pro = explode(',', config('subscription.lemon_squeezy_pro_plan_ids'));
|
||||
$ultimate = explode(',', config('subscription.lemon_squeezy_ultimate_plan_ids'));
|
||||
|
||||
$subscription = $this->lemon_variant_id;
|
||||
if (in_array($subscription, $basic)) {
|
||||
return 'basic';
|
||||
}
|
||||
if (in_array($subscription, $pro)) {
|
||||
return 'pro';
|
||||
}
|
||||
if (in_array($subscription, $ultimate)) {
|
||||
return 'ultimate';
|
||||
}
|
||||
} elseif (isStripe()) {
|
||||
if (isStripe()) {
|
||||
if (! $this->stripe_plan_id) {
|
||||
return 'zero';
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class DeploymentFailed extends Notification implements ShouldQueue
|
||||
{
|
||||
@@ -41,8 +40,8 @@ class DeploymentFailed extends Notification implements ShouldQueue
|
||||
$this->project_uuid = data_get($application, 'environment.project.uuid');
|
||||
$this->environment_name = data_get($application, 'environment.name');
|
||||
$this->fqdn = data_get($application, 'fqdn');
|
||||
if (Str::of($this->fqdn)->explode(',')->count() > 1) {
|
||||
$this->fqdn = Str::of($this->fqdn)->explode(',')->first();
|
||||
if (str($this->fqdn)->explode(',')->count() > 1) {
|
||||
$this->fqdn = str($this->fqdn)->explode(',')->first();
|
||||
}
|
||||
$this->deployment_url = base_url()."/project/{$this->project_uuid}/".urlencode($this->environment_name)."/application/{$this->application->uuid}/deployment/{$this->deployment_uuid}";
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class DeploymentSuccess extends Notification implements ShouldQueue
|
||||
{
|
||||
@@ -41,8 +40,8 @@ class DeploymentSuccess extends Notification implements ShouldQueue
|
||||
$this->project_uuid = data_get($application, 'environment.project.uuid');
|
||||
$this->environment_name = data_get($application, 'environment.name');
|
||||
$this->fqdn = data_get($application, 'fqdn');
|
||||
if (Str::of($this->fqdn)->explode(',')->count() > 1) {
|
||||
$this->fqdn = Str::of($this->fqdn)->explode(',')->first();
|
||||
if (str($this->fqdn)->explode(',')->count() > 1) {
|
||||
$this->fqdn = str($this->fqdn)->explode(',')->first();
|
||||
}
|
||||
$this->deployment_url = base_url()."/project/{$this->project_uuid}/".urlencode($this->environment_name)."/application/{$this->application->uuid}/deployment/{$this->deployment_uuid}";
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class StatusChanged extends Notification implements ShouldQueue
|
||||
{
|
||||
@@ -31,8 +30,8 @@ class StatusChanged extends Notification implements ShouldQueue
|
||||
$this->project_uuid = data_get($resource, 'environment.project.uuid');
|
||||
$this->environment_name = data_get($resource, 'environment.name');
|
||||
$this->fqdn = data_get($resource, 'fqdn', null);
|
||||
if (Str::of($this->fqdn)->explode(',')->count() > 1) {
|
||||
$this->fqdn = Str::of($this->fqdn)->explode(',')->first();
|
||||
if (str($this->fqdn)->explode(',')->count() > 1) {
|
||||
$this->fqdn = str($this->fqdn)->explode(',')->first();
|
||||
}
|
||||
$this->resource_url = base_url()."/project/{$this->project_uuid}/".urlencode($this->environment_name)."/application/{$this->resource->uuid}";
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ use App\Models\Server;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Process;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
trait ExecuteRemoteCommand
|
||||
{
|
||||
@@ -45,7 +44,7 @@ trait ExecuteRemoteCommand
|
||||
}
|
||||
$remote_command = generateSshCommand($this->server, $command);
|
||||
$process = Process::timeout(3600)->idleTimeout(3600)->start($remote_command, function (string $type, string $output) use ($command, $hidden, $customType, $append) {
|
||||
$output = Str::of($output)->trim();
|
||||
$output = str($output)->trim();
|
||||
if ($output->startsWith('╔')) {
|
||||
$output = "\n".$output;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ use App\Models\Service;
|
||||
use Closure;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\View\Component;
|
||||
|
||||
class Links extends Component
|
||||
@@ -26,16 +25,16 @@ class Links extends Component
|
||||
$this->links = $this->links->merge($links);
|
||||
} else {
|
||||
if ($application->fqdn) {
|
||||
$fqdns = collect(Str::of($application->fqdn)->explode(','));
|
||||
$fqdns = collect(str($application->fqdn)->explode(','));
|
||||
$fqdns->map(function ($fqdn) {
|
||||
$this->links->push(getFqdnWithoutPort($fqdn));
|
||||
});
|
||||
}
|
||||
if ($application->ports) {
|
||||
$portsCollection = collect(Str::of($application->ports)->explode(','));
|
||||
$portsCollection = collect(str($application->ports)->explode(','));
|
||||
$portsCollection->map(function ($port) {
|
||||
if (Str::of($port)->contains(':')) {
|
||||
$hostPort = Str::of($port)->before(':');
|
||||
if (str($port)->contains(':')) {
|
||||
$hostPort = str($port)->before(':');
|
||||
} else {
|
||||
$hostPort = $port;
|
||||
}
|
||||
|
||||
@@ -46,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)
|
||||
@@ -61,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)
|
||||
{
|
||||
@@ -74,7 +74,7 @@ function queue_next_deployment(Application $application)
|
||||
|
||||
dispatch(new ApplicationDeploymentJob(
|
||||
application_deployment_queue_id: $next_found->id,
|
||||
));
|
||||
))->onQueue('high');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@ function next_after_cancel(?Server $server = null)
|
||||
|
||||
dispatch(new ApplicationDeploymentJob(
|
||||
application_deployment_queue_id: $next->id,
|
||||
));
|
||||
))->onQueue('high');
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ function format_docker_envs_to_json($rawOutput)
|
||||
}
|
||||
function checkMinimumDockerEngineVersion($dockerVersion)
|
||||
{
|
||||
$majorDockerVersion = Str::of($dockerVersion)->before('.')->value();
|
||||
$majorDockerVersion = str($dockerVersion)->before('.')->value();
|
||||
if ($majorDockerVersion <= 22) {
|
||||
$dockerVersion = null;
|
||||
}
|
||||
@@ -152,7 +152,7 @@ function get_port_from_dockerfile($dockerfile): ?int
|
||||
$dockerfile_array = explode("\n", $dockerfile);
|
||||
$found_exposed_port = null;
|
||||
foreach ($dockerfile_array as $line) {
|
||||
$line_str = Str::of($line)->trim();
|
||||
$line_str = str($line)->trim();
|
||||
if ($line_str->startsWith('EXPOSE')) {
|
||||
$found_exposed_port = $line_str->replace('EXPOSE', '')->trim();
|
||||
break;
|
||||
@@ -534,7 +534,7 @@ function generateLabelsApplication(Application $application, ?ApplicationPreview
|
||||
$labels = collect([]);
|
||||
if ($pull_request_id === 0) {
|
||||
if ($application->fqdn) {
|
||||
$domains = Str::of(data_get($application, 'fqdn'))->explode(',');
|
||||
$domains = str(data_get($application, 'fqdn'))->explode(',');
|
||||
$labels = $labels->merge(fqdnLabelsForTraefik(
|
||||
uuid: $appUuid,
|
||||
domains: $domains,
|
||||
@@ -558,7 +558,7 @@ function generateLabelsApplication(Application $application, ?ApplicationPreview
|
||||
}
|
||||
} else {
|
||||
if (data_get($preview, 'fqdn')) {
|
||||
$domains = Str::of(data_get($preview, 'fqdn'))->explode(',');
|
||||
$domains = str(data_get($preview, 'fqdn'))->explode(',');
|
||||
} else {
|
||||
$domains = collect([]);
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ function githubApi(GithubApp|GitlabApp|null $source, string $endpoint, string $m
|
||||
function get_installation_path(GithubApp $source)
|
||||
{
|
||||
$github = GithubApp::where('uuid', $source->uuid)->first();
|
||||
$name = Str::of(Str::kebab($github->name));
|
||||
$name = str(Str::kebab($github->name));
|
||||
$installation_path = $github->html_url === 'https://github.com' ? 'apps' : 'github-apps';
|
||||
|
||||
return "$github->html_url/$installation_path/$name/installations/new";
|
||||
@@ -93,7 +93,7 @@ function get_installation_path(GithubApp $source)
|
||||
function get_permissions_path(GithubApp $source)
|
||||
{
|
||||
$github = GithubApp::where('uuid', $source->uuid)->first();
|
||||
$name = Str::of(Str::kebab($github->name));
|
||||
$name = str(Str::kebab($github->name));
|
||||
|
||||
return "$github->html_url/settings/apps/$name/permissions";
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ use App\Models\Application;
|
||||
use App\Models\EnvironmentVariable;
|
||||
use App\Models\ServiceApplication;
|
||||
use App\Models\ServiceDatabase;
|
||||
use Illuminate\Support\Str;
|
||||
use Spatie\Url\Url;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
@@ -38,7 +37,7 @@ function getFilesystemVolumesFromServer(ServiceApplication|ServiceDatabase|Appli
|
||||
]);
|
||||
instant_remote_process($commands, $server);
|
||||
foreach ($fileVolumes as $fileVolume) {
|
||||
$path = Str::of(data_get($fileVolume, 'fs_path'));
|
||||
$path = str(data_get($fileVolume, 'fs_path'));
|
||||
$content = data_get($fileVolume, 'content');
|
||||
if ($path->startsWith('.')) {
|
||||
$path = $path->after('.');
|
||||
@@ -68,7 +67,7 @@ function getFilesystemVolumesFromServer(ServiceApplication|ServiceDatabase|Appli
|
||||
$fileVolume->is_directory = false;
|
||||
$fileVolume->save();
|
||||
$content = base64_encode($content);
|
||||
$dir = Str::of($fileLocation)->dirname();
|
||||
$dir = str($fileLocation)->dirname();
|
||||
instant_remote_process([
|
||||
"mkdir -p $dir",
|
||||
"echo '$content' | base64 -d | tee $fileLocation",
|
||||
@@ -106,7 +105,7 @@ function updateCompose(ServiceApplication|ServiceDatabase $resource)
|
||||
$resourceFqdns = str($resource->fqdn)->explode(',');
|
||||
if ($resourceFqdns->count() === 1) {
|
||||
$resourceFqdns = $resourceFqdns->first();
|
||||
$variableName = 'SERVICE_FQDN_'.Str::of($resource->name)->upper()->replace('-', '');
|
||||
$variableName = 'SERVICE_FQDN_'.str($resource->name)->upper()->replace('-', '');
|
||||
$generatedEnv = EnvironmentVariable::where('service_id', $resource->service_id)->where('key', $variableName)->first();
|
||||
$fqdn = Url::fromString($resourceFqdns);
|
||||
$port = $fqdn->getPort();
|
||||
@@ -125,14 +124,14 @@ function updateCompose(ServiceApplication|ServiceDatabase $resource)
|
||||
$generatedEnv->save();
|
||||
}
|
||||
}
|
||||
$variableName = 'SERVICE_URL_'.Str::of($resource->name)->upper()->replace('-', '');
|
||||
$variableName = 'SERVICE_URL_'.str($resource->name)->upper()->replace('-', '');
|
||||
$generatedEnv = EnvironmentVariable::where('service_id', $resource->service_id)->where('key', $variableName)->first();
|
||||
$url = Url::fromString($fqdn);
|
||||
$port = $url->getPort();
|
||||
$path = $url->getPath();
|
||||
$url = $url->getHost();
|
||||
if ($generatedEnv) {
|
||||
$url = Str::of($fqdn)->after('://');
|
||||
$url = str($fqdn)->after('://');
|
||||
$generatedEnv->value = $url.$path;
|
||||
$generatedEnv->save();
|
||||
}
|
||||
@@ -175,7 +174,7 @@ function updateCompose(ServiceApplication|ServiceDatabase $resource)
|
||||
$port_env_url->save();
|
||||
}
|
||||
} else {
|
||||
$variableName = 'SERVICE_FQDN_'.Str::of($resource->name)->upper()->replace('-', '');
|
||||
$variableName = 'SERVICE_FQDN_'.str($resource->name)->upper()->replace('-', '');
|
||||
$generatedEnv = EnvironmentVariable::where('service_id', $resource->service_id)->where('key', $variableName)->first();
|
||||
$fqdn = Url::fromString($fqdn);
|
||||
$fqdn = $fqdn->getScheme().'://'.$fqdn->getHost().$fqdn->getPath();
|
||||
@@ -183,12 +182,12 @@ function updateCompose(ServiceApplication|ServiceDatabase $resource)
|
||||
$generatedEnv->value = $fqdn;
|
||||
$generatedEnv->save();
|
||||
}
|
||||
$variableName = 'SERVICE_URL_'.Str::of($resource->name)->upper()->replace('-', '');
|
||||
$variableName = 'SERVICE_URL_'.str($resource->name)->upper()->replace('-', '');
|
||||
$generatedEnv = EnvironmentVariable::where('service_id', $resource->service_id)->where('key', $variableName)->first();
|
||||
$url = Url::fromString($fqdn);
|
||||
$url = $url->getHost().$url->getPath();
|
||||
if ($generatedEnv) {
|
||||
$url = Str::of($fqdn)->after('://');
|
||||
$url = str($fqdn)->after('://');
|
||||
$generatedEnv->value = $url;
|
||||
$generatedEnv->save();
|
||||
}
|
||||
|
||||
@@ -469,7 +469,7 @@ function data_get_str($data, $key, $default = null): Stringable
|
||||
{
|
||||
$str = data_get($data, $key, $default) ?? $default;
|
||||
|
||||
return Str::of($str);
|
||||
return str($str);
|
||||
}
|
||||
|
||||
function generateFqdn(Server $server, string $random)
|
||||
@@ -933,12 +933,12 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
||||
$content = null;
|
||||
$isDirectory = false;
|
||||
if (is_string($volume)) {
|
||||
$source = Str::of($volume)->before(':');
|
||||
$target = Str::of($volume)->after(':')->beforeLast(':');
|
||||
$source = str($volume)->before(':');
|
||||
$target = str($volume)->after(':')->beforeLast(':');
|
||||
if ($source->startsWith('./') || $source->startsWith('/') || $source->startsWith('~')) {
|
||||
$type = Str::of('bind');
|
||||
$type = str('bind');
|
||||
} else {
|
||||
$type = Str::of('volume');
|
||||
$type = str('volume');
|
||||
}
|
||||
} elseif (is_array($volume)) {
|
||||
$type = data_get_str($volume, 'type');
|
||||
@@ -987,8 +987,8 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
||||
$slugWithoutUuid = Str::slug($source, '-');
|
||||
$name = "{$savedService->service->uuid}_{$slugWithoutUuid}";
|
||||
if (is_string($volume)) {
|
||||
$source = Str::of($volume)->before(':');
|
||||
$target = Str::of($volume)->after(':')->beforeLast(':');
|
||||
$source = str($volume)->before(':');
|
||||
$target = str($volume)->after(':')->beforeLast(':');
|
||||
$source = $name;
|
||||
$volume = "$source:$target";
|
||||
} elseif (is_array($volume)) {
|
||||
@@ -1032,7 +1032,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
||||
// Get variables from the service
|
||||
foreach ($serviceVariables as $variableName => $variable) {
|
||||
if (is_numeric($variableName)) {
|
||||
$variable = Str::of($variable);
|
||||
$variable = str($variable);
|
||||
if ($variable->contains('=')) {
|
||||
// - SESSION_SECRET=123
|
||||
// - SESSION_SECRET=
|
||||
@@ -1046,8 +1046,8 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
||||
} else {
|
||||
// SESSION_SECRET: 123
|
||||
// SESSION_SECRET:
|
||||
$key = Str::of($variableName);
|
||||
$value = Str::of($variable);
|
||||
$key = str($variableName);
|
||||
$value = str($variable);
|
||||
}
|
||||
if ($key->startsWith('SERVICE_FQDN')) {
|
||||
if ($isNew || $savedService->fqdn === null) {
|
||||
@@ -1137,7 +1137,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
||||
'key' => $key,
|
||||
'service_id' => $resource->id,
|
||||
])->first();
|
||||
$value = Str::of(replaceVariables($value));
|
||||
$value = str(replaceVariables($value));
|
||||
$key = $value;
|
||||
if ($value->startsWith('SERVICE_')) {
|
||||
$foundEnv = EnvironmentVariable::where([
|
||||
@@ -1170,7 +1170,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
||||
// }
|
||||
} else {
|
||||
if ($command->value() === 'URL') {
|
||||
$fqdn = Str::of($fqdn)->after('://')->value();
|
||||
$fqdn = str($fqdn)->after('://')->value();
|
||||
}
|
||||
EnvironmentVariable::create([
|
||||
'key' => $key,
|
||||
@@ -1254,18 +1254,6 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
||||
]);
|
||||
}
|
||||
}
|
||||
$envs_from_coolify = $resource->environment_variables()->get();
|
||||
$serviceVariables = $serviceVariables->map(function ($variable) use ($envs_from_coolify) {
|
||||
$env_variable_key = str($variable)->before('=');
|
||||
$env_variable_value = str($variable)->after('=');
|
||||
$found_env = $envs_from_coolify->where('key', $env_variable_key)->first();
|
||||
if ($found_env) {
|
||||
$env_variable_value = $found_env->value;
|
||||
}
|
||||
|
||||
return "$env_variable_key=$env_variable_value";
|
||||
});
|
||||
|
||||
}
|
||||
// Add labels to the service
|
||||
if ($savedService->serviceType()) {
|
||||
@@ -1333,6 +1321,41 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
||||
data_set($service, 'environment', $serviceVariables->toArray());
|
||||
updateCompose($savedService);
|
||||
|
||||
return $service;
|
||||
|
||||
});
|
||||
|
||||
$envs_from_coolify = $resource->environment_variables()->get();
|
||||
$services = collect($services)->map(function ($service, $serviceName) use ($resource, $envs_from_coolify) {
|
||||
$serviceVariables = collect(data_get($service, 'environment', []));
|
||||
$parsedServiceVariables = collect([]);
|
||||
foreach ($serviceVariables as $key => $value) {
|
||||
if (is_numeric($key)) {
|
||||
$value = str($value);
|
||||
if ($value->contains('=')) {
|
||||
$key = $value->before('=')->value();
|
||||
$value = $value->after('=')->value();
|
||||
} else {
|
||||
$key = $value->value();
|
||||
$value = null;
|
||||
}
|
||||
$parsedServiceVariables->put($key, $value);
|
||||
} else {
|
||||
$parsedServiceVariables->put($key, $value);
|
||||
}
|
||||
}
|
||||
$parsedServiceVariables->put('COOLIFY_CONTAINER_NAME', "$serviceName-{$resource->uuid}");
|
||||
$parsedServiceVariables = $parsedServiceVariables->map(function ($value, $key) use ($envs_from_coolify) {
|
||||
$found_env = $envs_from_coolify->where('key', $key)->first();
|
||||
if ($found_env) {
|
||||
return $found_env->value;
|
||||
}
|
||||
|
||||
return $value;
|
||||
});
|
||||
|
||||
data_set($service, 'environment', $parsedServiceVariables->toArray());
|
||||
|
||||
return $service;
|
||||
});
|
||||
$finalServices = [
|
||||
@@ -1637,7 +1660,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
||||
// Get variables from the service
|
||||
foreach ($serviceVariables as $variableName => $variable) {
|
||||
if (is_numeric($variableName)) {
|
||||
$variable = Str::of($variable);
|
||||
$variable = str($variable);
|
||||
if ($variable->contains('=')) {
|
||||
// - SESSION_SECRET=123
|
||||
// - SESSION_SECRET=
|
||||
@@ -1651,8 +1674,8 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
||||
} else {
|
||||
// SESSION_SECRET: 123
|
||||
// SESSION_SECRET:
|
||||
$key = Str::of($variableName);
|
||||
$value = Str::of($variable);
|
||||
$key = str($variableName);
|
||||
$value = str($variable);
|
||||
}
|
||||
if ($key->startsWith('SERVICE_FQDN')) {
|
||||
if ($isNew) {
|
||||
@@ -1696,7 +1719,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
||||
'application_id' => $resource->id,
|
||||
'is_preview' => false,
|
||||
])->first();
|
||||
$value = Str::of(replaceVariables($value));
|
||||
$value = str(replaceVariables($value));
|
||||
$key = $value;
|
||||
if ($value->startsWith('SERVICE_')) {
|
||||
$foundEnv = EnvironmentVariable::where([
|
||||
@@ -1718,7 +1741,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
||||
$fqdn = data_get($foundEnv, 'value');
|
||||
} else {
|
||||
if ($command?->value() === 'URL') {
|
||||
$fqdn = Str::of($fqdn)->after('://')->value();
|
||||
$fqdn = str($fqdn)->after('://')->value();
|
||||
}
|
||||
EnvironmentVariable::create([
|
||||
'key' => $key,
|
||||
|
||||
@@ -1,51 +1,8 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Team;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Stripe\Stripe;
|
||||
|
||||
function getSubscriptionLink($type)
|
||||
{
|
||||
$checkout_id = config("subscription.lemon_squeezy_checkout_id_$type");
|
||||
if (! $checkout_id) {
|
||||
return null;
|
||||
}
|
||||
$user_id = auth()->user()->id;
|
||||
$team_id = currentTeam()->id ?? null;
|
||||
$email = auth()->user()->email ?? null;
|
||||
$name = auth()->user()->name ?? null;
|
||||
$url = "https://store.coollabs.io/checkout/buy/$checkout_id?";
|
||||
if ($user_id) {
|
||||
$url .= "&checkout[custom][user_id]={$user_id}";
|
||||
}
|
||||
if (isset($team_id)) {
|
||||
$url .= "&checkout[custom][team_id]={$team_id}";
|
||||
}
|
||||
if ($email) {
|
||||
$url .= "&checkout[email]={$email}";
|
||||
}
|
||||
if ($name) {
|
||||
$url .= "&checkout[name]={$name}";
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
function getPaymentLink()
|
||||
{
|
||||
return currentTeam()->subscription->lemon_update_payment_menthod_url;
|
||||
}
|
||||
|
||||
function getRenewDate()
|
||||
{
|
||||
return Carbon::parse(currentTeam()->subscription->lemon_renews_at)->format('Y-M-d H:i:s');
|
||||
}
|
||||
|
||||
function getEndDate()
|
||||
{
|
||||
return Carbon::parse(currentTeam()->subscription->lemon_renews_at)->format('Y-M-d H:i:s');
|
||||
}
|
||||
|
||||
function isSubscriptionActive()
|
||||
{
|
||||
if (! isCloud()) {
|
||||
@@ -60,12 +17,6 @@ function isSubscriptionActive()
|
||||
if (is_null($subscription)) {
|
||||
return false;
|
||||
}
|
||||
if (isLemon()) {
|
||||
return $subscription->lemon_status === 'active';
|
||||
}
|
||||
// if (isPaddle()) {
|
||||
// return $subscription->paddle_status === 'active';
|
||||
// }
|
||||
if (isStripe()) {
|
||||
return $subscription->stripe_invoice_paid === true;
|
||||
}
|
||||
@@ -82,12 +33,6 @@ function isSubscriptionOnGracePeriod()
|
||||
if (! $subscription) {
|
||||
return false;
|
||||
}
|
||||
if (isLemon()) {
|
||||
$is_still_grace_period = $subscription->lemon_ends_at &&
|
||||
Carbon::parse($subscription->lemon_ends_at) > Carbon::now();
|
||||
|
||||
return $is_still_grace_period;
|
||||
}
|
||||
if (isStripe()) {
|
||||
return $subscription->stripe_cancel_at_period_end;
|
||||
}
|
||||
@@ -98,18 +43,10 @@ function subscriptionProvider()
|
||||
{
|
||||
return config('subscription.provider');
|
||||
}
|
||||
function isLemon()
|
||||
{
|
||||
return config('subscription.provider') === 'lemon';
|
||||
}
|
||||
function isStripe()
|
||||
{
|
||||
return config('subscription.provider') === 'stripe';
|
||||
}
|
||||
function isPaddle()
|
||||
{
|
||||
return config('subscription.provider') === 'paddle';
|
||||
}
|
||||
function getStripeCustomerPortalSession(Team $team)
|
||||
{
|
||||
Stripe::setApiKey(config('subscription.stripe_api_key'));
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
"league/flysystem-aws-s3-v3": "^3.0",
|
||||
"league/flysystem-sftp-v3": "^3.0",
|
||||
"livewire/livewire": "3.4.9",
|
||||
"log1x/laravel-webfonts": "^1.0",
|
||||
"lorisleiva/laravel-actions": "^2.7",
|
||||
"nubs/random-name-generator": "^2.2",
|
||||
"phpseclib/phpseclib": "~3.0",
|
||||
|
||||
64
composer.lock
generated
64
composer.lock
generated
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "dbce9f366320f4d58392673fe25c69f6",
|
||||
"content-hash": "168e351cec87acbea9c1c745b83eead2",
|
||||
"packages": [
|
||||
{
|
||||
"name": "amphp/amp",
|
||||
@@ -4522,6 +4522,68 @@
|
||||
],
|
||||
"time": "2024-03-14T14:03:32+00:00"
|
||||
},
|
||||
{
|
||||
"name": "log1x/laravel-webfonts",
|
||||
"version": "v1.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Log1x/laravel-webfonts.git",
|
||||
"reference": "0d38122aa7f5501394006a6715f7d97dac223507"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Log1x/laravel-webfonts/zipball/0d38122aa7f5501394006a6715f7d97dac223507",
|
||||
"reference": "0d38122aa7f5501394006a6715f7d97dac223507",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"guzzlehttp/guzzle": "^7.8",
|
||||
"laravel/prompts": "^0.1.15",
|
||||
"php": ">=8.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"illuminate/console": "^10.41",
|
||||
"illuminate/http": "^10.41",
|
||||
"illuminate/support": "^10.41",
|
||||
"laravel/pint": "^1.13"
|
||||
},
|
||||
"type": "package",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Log1x\\LaravelWebfonts\\WebfontsServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Log1x\\LaravelWebfonts\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Brandon Nifong",
|
||||
"email": "brandon@tendency.me",
|
||||
"homepage": "https://github.com/log1x"
|
||||
}
|
||||
],
|
||||
"description": "Download, install, and preload over 1500 Google fonts locally in your Laravel project",
|
||||
"support": {
|
||||
"issues": "https://github.com/Log1x/laravel-webfonts/issues",
|
||||
"source": "https://github.com/Log1x/laravel-webfonts/tree/v1.0.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/Log1x",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2024-03-28T11:53:11+00:00"
|
||||
},
|
||||
{
|
||||
"name": "lorisleiva/laravel-actions",
|
||||
"version": "v2.8.0",
|
||||
|
||||
@@ -7,7 +7,7 @@ return [
|
||||
|
||||
// The release version of your application
|
||||
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
|
||||
'release' => '4.0.0-beta.298',
|
||||
'release' => '4.0.0-beta.306',
|
||||
// When left empty or `null` the Laravel environment will be used
|
||||
'environment' => config('app.env'),
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'provider' => env('SUBSCRIPTION_PROVIDER', null), // stripe, paddle, lemon
|
||||
'provider' => env('SUBSCRIPTION_PROVIDER', null), // stripe
|
||||
|
||||
// Stripe
|
||||
'stripe_api_key' => env('STRIPE_API_KEY', null),
|
||||
'stripe_webhook_secret' => env('STRIPE_WEBHOOK_SECRET', null),
|
||||
@@ -22,29 +23,4 @@ return [
|
||||
|
||||
'stripe_price_id_dynamic_monthly' => env('STRIPE_PRICE_ID_DYNAMIC_MONTHLY', null),
|
||||
'stripe_price_id_dynamic_yearly' => env('STRIPE_PRICE_ID_DYNAMIC_YEARLY', null),
|
||||
|
||||
// Paddle
|
||||
'paddle_vendor_id' => env('PADDLE_VENDOR_ID', null),
|
||||
'paddle_vendor_auth_code' => env('PADDLE_VENDOR_AUTH_CODE', null),
|
||||
'paddle_webhook_secret' => env('PADDLE_WEBHOOK_SECRET', null),
|
||||
'paddle_public_key' => env('PADDLE_PUBLIC_KEY', null),
|
||||
'paddle_price_id_basic_monthly' => env('PADDLE_PRICE_ID_BASIC_MONTHLY', null),
|
||||
'paddle_price_id_basic_yearly' => env('PADDLE_PRICE_ID_BASIC_YEARLY', null),
|
||||
'paddle_price_id_pro_monthly' => env('PADDLE_PRICE_ID_PRO_MONTHLY', null),
|
||||
'paddle_price_id_pro_yearly' => env('PADDLE_PRICE_ID_PRO_YEARLY', null),
|
||||
'paddle_price_id_ultimate_monthly' => env('PADDLE_PRICE_ID_ULTIMATE_MONTHLY', null),
|
||||
'paddle_price_id_ultimate_yearly' => env('PADDLE_PRICE_ID_ULTIMATE_YEARLY', null),
|
||||
|
||||
// Lemon
|
||||
'lemon_squeezy_api_key' => env('LEMON_SQUEEZY_API_KEY', null),
|
||||
'lemon_squeezy_webhook_secret' => env('LEMON_SQUEEZY_WEBHOOK_SECRET', null),
|
||||
'lemon_squeezy_checkout_id_basic_monthly' => env('LEMON_SQUEEZY_CHECKOUT_ID_BASIC_MONTHLY', null),
|
||||
'lemon_squeezy_checkout_id_basic_yearly' => env('LEMON_SQUEEZY_CHECKOUT_ID_BASIC_YEARLY', null),
|
||||
'lemon_squeezy_checkout_id_pro_monthly' => env('LEMON_SQUEEZY_CHECKOUT_ID_PRO_MONTHLY', null),
|
||||
'lemon_squeezy_checkout_id_pro_yearly' => env('LEMON_SQUEEZY_CHECKOUT_ID_PRO_YEARLY', null),
|
||||
'lemon_squeezy_checkout_id_ultimate_monthly' => env('LEMON_SQUEEZY_CHECKOUT_ID_ULTIMATE_MONTHLY', null),
|
||||
'lemon_squeezy_checkout_id_ultimate_yearly' => env('LEMON_SQUEEZY_CHECKOUT_ID_ULTIMATE_YEARLY', null),
|
||||
'lemon_squeezy_basic_plan_ids' => env('LEMON_SQUEEZY_BASIC_PLAN_IDS', ''),
|
||||
'lemon_squeezy_pro_plan_ids' => env('LEMON_SQUEEZY_PRO_PLAN_IDS', ''),
|
||||
'lemon_squeezy_ultimate_plan_ids' => env('LEMON_SQUEEZY_ULTIMATE_PLAN_IDS', ''),
|
||||
];
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<?php
|
||||
|
||||
return '4.0.0-beta.298';
|
||||
return '4.0.0-beta.306';
|
||||
|
||||
@@ -69,27 +69,6 @@ services:
|
||||
- STRIPE_PRICE_ID_ULTIMATE_MONTHLY_OLD
|
||||
- STRIPE_PRICE_ID_ULTIMATE_YEARLY_OLD
|
||||
- STRIPE_EXCLUDED_PLANS
|
||||
- PADDLE_VENDOR_ID
|
||||
- PADDLE_WEBHOOK_SECRET
|
||||
- PADDLE_VENDOR_AUTH_CODE
|
||||
- PADDLE_PUBLIC_KEY
|
||||
- PADDLE_PRICE_ID_BASIC_MONTHLY
|
||||
- PADDLE_PRICE_ID_BASIC_YEARLY
|
||||
- PADDLE_PRICE_ID_PRO_MONTHLY
|
||||
- PADDLE_PRICE_ID_PRO_YEARLY
|
||||
- PADDLE_PRICE_ID_ULTIMATE_MONTHLY
|
||||
- PADDLE_PRICE_ID_ULTIMATE_YEARLY
|
||||
- LEMON_SQUEEZY_API_KEY
|
||||
- LEMON_SQUEEZY_WEBHOOK_SECRET
|
||||
- LEMON_SQUEEZY_CHECKOUT_ID_BASIC_MONTHLY
|
||||
- LEMON_SQUEEZY_CHECKOUT_ID_BASIC_YEARLY
|
||||
- LEMON_SQUEEZY_CHECKOUT_ID_PRO_MONTHLY
|
||||
- LEMON_SQUEEZY_CHECKOUT_ID_PRO_YEARLY
|
||||
- LEMON_SQUEEZY_CHECKOUT_ID_ULTIMATE_MONTHLY
|
||||
- LEMON_SQUEEZY_CHECKOUT_ID_ULTIMATE_YEARLY
|
||||
- LEMON_SQUEEZY_BASIC_PLAN_IDS
|
||||
- LEMON_SQUEEZY_PRO_PLAN_IDS
|
||||
- LEMON_SQUEEZY_ULTIMATE_PLAN_IDS
|
||||
ports:
|
||||
- "${APP_PORT:-8000}:80"
|
||||
expose:
|
||||
|
||||
30
lang/cs.json
Normal file
30
lang/cs.json
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"auth.login": "Přihlásit se",
|
||||
"auth.login.azure": "Přihlásit se pomocí Microsoftu",
|
||||
"auth.login.bitbucket": "Přihlásit se pomocí Bitbucketu",
|
||||
"auth.login.github": "Přihlásit se pomocí GitHubu",
|
||||
"auth.login.gitlab": "Přihlásit se pomocí Gitlabu",
|
||||
"auth.login.google": "Přihlásit se pomocí Google",
|
||||
"auth.already_registered": "Již jste registrováni?",
|
||||
"auth.confirm_password": "Potvrďte heslo",
|
||||
"auth.forgot_password": "Zapomněli jste heslo",
|
||||
"auth.forgot_password_send_email": "Poslat e-mail pro resetování hesla",
|
||||
"auth.register_now": "Registrovat se",
|
||||
"auth.logout": "Odhlásit se",
|
||||
"auth.register": "Registrovat se",
|
||||
"auth.registration_disabled": "Registrace je zakázána. Kontaktujte prosím administrátora.",
|
||||
"auth.reset_password": "Obnovit heslo",
|
||||
"auth.failed": "Tyto údaje neodpovídají našim záznamům.",
|
||||
"auth.failed.callback": "Nepodařilo se zpracovat zpětné volání od poskytovatele přihlášení.",
|
||||
"auth.failed.password": "Zadané heslo je nesprávné.",
|
||||
"auth.failed.email": "Nemůžeme najít uživatele s touto e-mailovou adresou.",
|
||||
"auth.throttle": "Příliš mnoho pokusů o přihlášení. Zkuste to prosím znovu za :seconds sekund.",
|
||||
"input.name": "Jméno",
|
||||
"input.email": "E-mail",
|
||||
"input.password": "Heslo",
|
||||
"input.password.again": "Heslo znovu",
|
||||
"input.code": "Jednorázový kód",
|
||||
"input.recovery_code": "Obnovovací kód",
|
||||
"button.save": "Uložit",
|
||||
"repository.url": "<span class='text-helper'>Příklady</span><br>Pro veřejné repozitáře, použijte <span class='text-helper'>https://...</span>.<br>Pro soukromé repozitáře, použijte <span class='text-helper'>git@...</span>.<br><br>https://github.com/coollabsio/coolify-examples <span class='text-helper'>main</span> branch bude zvolena<br>https://github.com/coollabsio/coolify-examples/tree/nodejs-fastify <span class='text-helper'>nodejs-fastify</span> branch bude vybrána.<br>https://gitea.com/sedlav/expressjs.git <span class='text-helper'>main</span> branch vybrána.<br>https://gitlab.com/andrasbacsai/nodejs-example.git <span class='text-helper'>main</span> branch bude vybrána."
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 10 KiB |
18
other/logos/blacksmith.svg
Normal file
18
other/logos/blacksmith.svg
Normal file
@@ -0,0 +1,18 @@
|
||||
|
||||
<svg width="500" height="62" viewBox="0 0 500 62" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M93.0578 0H101.918C101.9 7.56173 101.918 14.7077 101.97 22.2693C105.483 18.628 109.791 16.8508 114.895 16.9378C120.189 16.8952 124.862 18.5505 128.914 21.9034C132.741 25.5912 134.913 30.1037 135.428 35.4412C136.18 41.2349 135.138 46.671 132.301 51.7493C128.695 57.2448 123.605 60.3287 117.031 61.0009C112.204 61.5389 107.792 60.4586 103.794 57.7602C103.156 57.257 102.548 56.7168 101.97 56.1399C101.918 57.6378 101.9 59.1363 101.918 60.6351H93.0578V46.4178C93.5587 43.3221 94.9832 40.7434 97.3313 38.6819C94.957 36.6721 93.5325 34.1284 93.0578 31.0505V0ZM111.82 24.7782C119.282 24.5024 123.92 27.9871 125.735 35.2321C126.466 38.8811 126.153 42.4355 124.797 45.8951C122.104 51.35 117.708 53.8067 111.611 53.2651C107.399 52.9021 104.255 50.8984 102.178 47.2541C101.844 46.0348 101.497 44.8152 101.136 43.5952C100.406 41.6257 99.2072 40.0054 97.5398 38.7342C99.8148 36.8727 101.222 34.4858 101.761 31.5732C103.024 28.6346 105.16 26.631 108.172 25.5623C109.377 25.1811 110.593 24.9198 111.82 24.7782Z" fill="white"/>
|
||||
<path d="M468.713 0H459.853C459.836 11.1858 459.853 22.3714 459.905 33.557C460.364 36.6739 461.771 39.2525 464.127 41.2929C461.771 43.3333 460.364 45.9118 459.905 49.0287C459.853 53.0359 459.836 57.0432 459.853 61.0507H468.713C468.731 57.0781 468.713 53.1057 468.661 49.1333C468.233 45.9729 466.825 43.3594 464.44 41.2929C466.141 39.811 467.374 37.9991 468.14 35.8568C468.576 34.2795 469.063 32.7114 469.599 31.1526C471.611 26.6578 475.085 24.3928 480.022 24.3576C482.93 24.2492 485.432 25.19 487.527 27.1801C489.547 29.7393 490.555 32.6664 490.55 35.9614C490.602 44.3244 490.62 52.6875 490.602 61.0507H499.983C500.031 51.6755 499.979 42.3019 499.826 32.9298C499.661 31.229 499.348 29.5564 498.888 27.9119C497.762 23.7875 495.381 20.6339 491.748 18.4511C488.173 16.6468 484.387 15.915 480.387 16.2558C475.604 16.6067 471.73 18.6452 468.765 22.3713C468.713 14.9143 468.695 7.45719 468.713 0Z" fill="white"/>
|
||||
<path d="M432.685 48.9195V25.027H425.036V16.8623H432.685V4.57233H442.053V16.8623H452.796V25.027H442.053V47.9741C442.053 51.4118 443.256 52.701 446.78 52.701H453.311V60.8657H444.717C436.294 60.8657 432.685 56.9122 432.685 48.9195Z" fill="white"/>
|
||||
<path d="M226.002 60.6327C212.681 60.6327 204.172 51.9524 204.172 38.2013C204.172 24.6222 212.939 15.5981 226.26 15.5981C237.605 15.5981 244.652 21.872 246.457 31.8415H236.745C235.542 26.6848 231.846 23.5049 226.088 23.5049C218.611 23.5049 213.712 29.521 213.712 38.2013C213.712 46.7957 218.611 52.7259 226.088 52.7259C231.76 52.7259 235.542 49.46 236.659 44.3893H246.457C244.738 54.3588 237.261 60.6327 226.002 60.6327Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M199.194 52.0383H201.085V60.1171H196.186C190.17 60.1171 188.107 57.4528 188.107 53.0697C185.185 57.5387 180.716 60.6327 173.583 60.6327C163.957 60.6327 157.254 55.9058 157.254 47.7411C157.254 38.717 163.785 33.6463 176.075 33.6463H187.162V30.982C187.162 26.0832 183.638 23.0752 177.536 23.0752C172.036 23.0752 168.34 25.6535 167.653 29.521H158.543C159.488 20.9266 166.879 15.5981 177.966 15.5981C189.654 15.5981 196.358 21.1844 196.358 31.5836V49.2022C196.358 51.4367 197.304 52.0383 199.194 52.0383ZM187.162 42.0688V40.5218H175.646C169.887 40.5218 166.707 42.6704 166.707 47.1395C166.707 50.8351 169.801 53.4134 174.872 53.4134C182.607 53.4134 187.076 48.8584 187.162 42.0688Z" fill="white"/>
|
||||
<path d="M299.159 45.5925H290.049C290.307 55.1323 298.386 60.6327 310.16 60.6327C320.817 60.6327 328.81 55.3042 328.81 46.8817C328.81 37.0841 320.645 35.0214 310.59 33.8182C304.23 33.1306 300.019 32.615 300.019 28.4896C300.019 24.9659 303.628 22.7314 309.129 22.7314C314.629 22.7314 318.411 25.5676 318.926 29.6069H328.036C327.435 20.5828 319.786 15.598 308.957 15.598C298.386 15.5121 290.909 20.9266 290.909 29.2631C290.909 38.3732 298.816 40.5218 308.871 41.725L309.545 41.81C315.927 42.6125 319.7 43.0869 319.7 47.6552C319.7 51.1789 315.918 53.4134 310.16 53.4134C303.457 53.4134 299.503 50.1475 299.159 45.5925Z" fill="white"/>
|
||||
<path d="M150.551 0H141.736V31.7437C141.736 35.377 143.369 38.7982 146.144 40.9782C143.369 43.1582 141.736 46.5794 141.736 50.2127V60.6016H150.551V50.2127C150.551 46.5794 148.918 43.1582 146.144 40.9782C148.918 38.7982 150.551 35.377 150.551 31.7437V0Z" fill="white"/>
|
||||
<path d="M409.901 16.8345H418.715V31.8426C418.715 35.4759 417.083 38.8972 414.308 41.0772C411.534 38.8972 409.901 35.4759 409.901 31.8426V16.8345Z" fill="white"/>
|
||||
<path d="M414.308 41.0772C417.083 43.2571 418.715 46.6784 418.715 50.3117V60.7005H409.901V50.3117C409.901 46.6784 411.534 43.2571 414.308 41.0772Z" fill="white"/>
|
||||
<path d="M262.398 0H253.584L253.514 24.0881C253.514 27.7214 255.147 31.3505 257.922 33.5304C255.147 35.7104 253.514 38.9238 253.514 42.5571L253.584 60.6016H262.398L262.329 42.5571C262.329 38.9238 260.696 35.7104 257.922 33.5304C260.696 31.3505 262.329 27.7214 262.329 24.0881L262.398 0Z" fill="white"/>
|
||||
<path d="M276.675 16.2241C280.359 16.1892 284.042 16.2241 287.724 16.3286C282.257 22.3171 276.733 28.2584 271.151 34.1525C276.581 42.2157 281.993 50.3353 287.389 58.4297L287.392 58.4343L287.402 58.4496L288.766 60.4963H277.718C275.533 57.282 273.362 54.0588 271.203 50.8264C267.716 45.0332 264.189 39.2661 260.624 33.5252C266.034 27.8033 271.385 22.0362 276.675 16.2241Z" fill="white"/>
|
||||
<path d="M414.308 11.4341C417.351 11.4341 419.817 8.96756 419.817 5.9249C419.817 2.88223 417.351 0.415667 414.308 0.415667C411.265 0.415667 408.799 2.88223 408.799 5.9249C408.799 8.96756 411.265 11.4341 414.308 11.4341Z" fill="white"/>
|
||||
<path d="M354.895 16.2542C358.451 16.0176 361.791 16.753 364.916 18.4605C366.963 19.8309 368.582 21.5925 369.773 23.7452C372.505 19.6097 376.34 17.1982 381.276 16.5107C385.58 15.8328 389.67 16.4827 393.546 18.4605C396.922 20.6189 399.121 23.6461 400.141 27.5421C400.706 29.7642 401.012 32.0218 401.061 34.3148C401.112 43.1056 401.13 51.8964 401.112 60.6873H391.399C391.437 51.4511 391.386 42.2156 391.245 32.9808C390.978 30.5307 390.041 28.3929 388.433 26.5672C386.896 25.1403 385.072 24.4391 382.963 24.4636C377.949 24.5997 374.711 27.0625 373.249 31.852C372.758 33.7694 372.553 35.7191 372.636 37.7011C372.585 45.3631 372.567 53.0252 372.585 60.6873H362.871C362.888 52.2385 362.871 43.7897 362.82 35.3409C362.847 32.7158 362.234 30.253 360.979 27.9525C358.681 24.9256 355.664 23.8482 351.93 24.7201C349.246 25.3215 347.218 26.8095 345.846 29.1839C344.889 30.9043 344.378 32.7514 344.312 34.7252C343.658 37.2555 342.345 39.3591 340.375 41.0362C342.935 43.1807 344.35 45.9343 344.619 49.2968C344.67 53.0935 344.687 56.8903 344.67 60.6873H335.876C335.859 56.822 335.876 52.9567 335.928 49.0916C336.256 45.8143 337.671 43.1293 340.171 41.0362C337.934 39.1303 336.554 36.7188 336.03 33.8017C335.88 28.1604 335.829 22.5165 335.876 16.8699H344.67C344.653 18.2386 344.67 19.6068 344.721 20.9746C347.517 18.1096 350.908 16.5361 354.895 16.2542Z" fill="white"/>
|
||||
<path d="M0.509564 10.8453C-1.07569 7.67952 1.2298 3.95471 4.77453 3.95471H69.2141C72.7589 3.95471 75.0643 7.67952 73.4791 10.8453L66.3265 25.1291C65.5188 26.7422 63.8677 27.7611 62.0616 27.7611H11.9271C10.121 27.7611 8.46986 26.7422 7.66213 25.1291L0.509564 10.8453Z" fill="white"/>
|
||||
<path d="M55.5976 49.4381C57.1828 52.6039 54.8773 56.3287 51.3326 56.3287L22.6559 56.3287C19.1111 56.3287 16.8056 52.6039 18.3909 49.4381L25.5435 35.1543C26.3512 33.5413 28.0023 32.5224 29.8084 32.5224H44.18C45.9861 32.5224 47.6373 33.5413 48.445 35.1543L55.5976 49.4381Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.4 KiB |
16
public/js/apexcharts.js
Normal file
16
public/js/apexcharts.js
Normal file
File diff suppressed because one or more lines are too long
@@ -1,7 +1,11 @@
|
||||
@import 'fonts';
|
||||
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
|
||||
|
||||
html,
|
||||
body {
|
||||
@apply h-full bg-neutral-50 text-neutral-800 dark:bg-base dark:text-neutral-400;
|
||||
|
||||
72
resources/css/fonts.css
Normal file
72
resources/css/fonts.css
Normal file
@@ -0,0 +1,72 @@
|
||||
@font-face {
|
||||
font-display: swap;
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 100;
|
||||
src: url('../fonts/inter-v13-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-100.woff2') format('woff2');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-display: swap;
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 200;
|
||||
src: url('../fonts/inter-v13-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-200.woff2') format('woff2');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-display: swap;
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
src: url('../fonts/inter-v13-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-300.woff2') format('woff2');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-display: swap;
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
src: url('../fonts/inter-v13-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-500.woff2') format('woff2');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-display: swap;
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
src: url('../fonts/inter-v13-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-600.woff2') format('woff2');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-display: swap;
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: url('../fonts/inter-v13-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-700.woff2') format('woff2');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-display: swap;
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 800;
|
||||
src: url('../fonts/inter-v13-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-800.woff2') format('woff2');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-display: swap;
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 900;
|
||||
src: url('../fonts/inter-v13-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-900.woff2') format('woff2');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-display: swap;
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: url('../fonts/inter-v13-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-regular.woff2') format('woff2');
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -61,8 +61,7 @@
|
||||
@endif
|
||||
<template x-teleport="body">
|
||||
<div x-show="modalOpen"
|
||||
class="fixed top-0 lg:pt-10 left-0 z-[99] flex items-start justify-center w-screen h-screen"
|
||||
style="zoom:1.1;" x-cloak>
|
||||
class="fixed top-0 lg:pt-10 left-0 z-[99] flex items-start justify-center w-screen h-screen" x-cloak>
|
||||
<div x-show="modalOpen" x-transition:enter="ease-out duration-100" x-transition:enter-start="opacity-0"
|
||||
x-transition:enter-end="opacity-100" x-transition:leave="ease-in duration-100"
|
||||
x-transition:leave-start="opacity-100" x-transition:leave-end="opacity-0" @click="modalOpen=false"
|
||||
|
||||
@@ -5,9 +5,10 @@
|
||||
'disabled' => false,
|
||||
'action' => 'delete',
|
||||
'content' => null,
|
||||
'closeOutside' => true
|
||||
'closeOutside' => true,
|
||||
])
|
||||
<div x-data="{ modalOpen: false }" :class="{ 'z-40': modalOpen }" @keydown.window.escape="modalOpen=false" class="relative w-auto h-auto">
|
||||
<div x-data="{ modalOpen: false }" :class="{ 'z-40': modalOpen }" @keydown.window.escape="modalOpen=false"
|
||||
class="relative w-auto h-auto">
|
||||
@if ($content)
|
||||
<div @click="modalOpen=true">
|
||||
{{ $content }}
|
||||
@@ -22,13 +23,15 @@
|
||||
@endif
|
||||
@endif
|
||||
<template x-teleport="body">
|
||||
<div x-show="modalOpen" class="fixed top-0 left-0 lg:px-0 px-4 z-[99] flex items-center justify-center w-screen h-screen" style="zoom:1.1;"
|
||||
x-cloak>
|
||||
<div x-show="modalOpen"
|
||||
class="fixed top-0 left-0 lg:px-0 px-4 z-[99] flex items-center justify-center w-screen h-screen" x-cloak>
|
||||
<div x-show="modalOpen" x-transition:enter="ease-out duration-100" x-transition:enter-start="opacity-0"
|
||||
x-transition:enter-end="opacity-100" x-transition:leave="ease-in duration-100"
|
||||
x-transition:leave-start="opacity-100" x-transition:leave-end="opacity-0"
|
||||
class="absolute inset-0 w-full h-full bg-black bg-opacity-20 backdrop-blur-sm"></div>
|
||||
<div x-show="modalOpen" x-trap.inert.noscroll="modalOpen" @if ($closeOutside) @click.outside="modalOpen=false" @endif x-transition:enter="ease-out duration-100"
|
||||
<div x-show="modalOpen" x-trap.inert.noscroll="modalOpen"
|
||||
@if ($closeOutside) @click.outside="modalOpen=false" @endif
|
||||
x-transition:enter="ease-out duration-100"
|
||||
x-transition:enter-start="opacity-0 -translate-y-2 sm:scale-95"
|
||||
x-transition:enter-end="opacity-100 translate-y-0 sm:scale-100"
|
||||
x-transition:leave="ease-in duration-100"
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
<x-slot:basic>
|
||||
<x-forms.button x-show="selected === 'monthly'" x-cloak aria-describedby="tier-basic" class="w-full h-10 buyme"
|
||||
x-on:click="subscribe('basic-monthly')"> Subscribe
|
||||
</x-forms.button>
|
||||
|
||||
<x-forms.button x-show="selected === 'yearly'" x-cloak aria-describedby="tier-basic" class="w-full h-10 buyme"
|
||||
x-on:click="subscribe('basic-yearly')"> Subscribe
|
||||
</x-forms.button>
|
||||
</x-slot:basic>
|
||||
<x-slot:pro>
|
||||
<x-forms.button x-show="selected === 'monthly'" x-cloak aria-describedby="tier-pro" class="w-full h-10 buyme"
|
||||
x-on:click="subscribe('pro-monthly')"> Subscribe
|
||||
</x-forms.button>
|
||||
|
||||
<x-forms.button x-show="selected === 'yearly'" x-cloak aria-describedby="tier-pro" class="w-full h-10 buyme"
|
||||
x-on:click="subscribe('pro-yearly')"> Subscribe
|
||||
</x-forms.button>
|
||||
</x-slot:pro>
|
||||
<x-slot:ultimate>
|
||||
<x-forms.button x-show="selected === 'monthly'" x-cloak aria-describedby="tier-ultimate" class="w-full h-10 buyme"
|
||||
x-on:click="subscribe('ultimate-monthly')"> Subscribe
|
||||
</x-forms.button>
|
||||
|
||||
<x-forms.button x-show="selected === 'yearly'" x-cloak aria-describedby="tier-ultimate" class="w-full h-10 buyme"
|
||||
x-on:click="subscribe('ultimate-yearly')"> Subscribe
|
||||
</x-forms.button>
|
||||
</x-slot:ultimate>
|
||||
<x-slot:other>
|
||||
<script src="https://cdn.paddle.com/paddle/v2/paddle.js"></script>
|
||||
<script type="text/javascript">
|
||||
Paddle.Environment.set("{{ isDev() ? 'sandbox' : 'production' }}");
|
||||
Paddle.Setup({
|
||||
seller: {{ config('subscription.paddle_vendor_id') }},
|
||||
checkout: {
|
||||
settings: {
|
||||
displayMode: "overlay",
|
||||
theme: "light",
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function subscribe(type) {
|
||||
let priceId = null
|
||||
switch (type) {
|
||||
case 'basic-monthly':
|
||||
priceId = "{{ config('subscription.paddle_price_id_basic_monthly') }}"
|
||||
break;
|
||||
case 'basic-yearly':
|
||||
priceId = "{{ config('subscription.paddle_price_id_basic_yearly') }}"
|
||||
break;
|
||||
case 'pro-monthly':
|
||||
priceId = "{{ config('subscription.paddle_price_id_pro_monthly') }}"
|
||||
break;
|
||||
case 'pro-yearly':
|
||||
priceId = "{{ config('subscription.paddle_price_id_pro_yearly') }}"
|
||||
break;
|
||||
case 'ultimate-monthly':
|
||||
priceId = "{{ config('subscription.paddle_price_id_ultimate_monthly') }}"
|
||||
break;
|
||||
case 'ultimate-yearly':
|
||||
priceId = "{{ config('subscription.paddle_price_id_ultimate_yearly') }}"
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
Paddle.Checkout.open({
|
||||
customer: {
|
||||
email: '{{ auth()->user()->email }}',
|
||||
},
|
||||
customData: {
|
||||
"team_id": "{{ currentTeam()->id }}",
|
||||
},
|
||||
items: [{
|
||||
priceId,
|
||||
quantity: 1
|
||||
}],
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</x-slot:other>
|
||||
@@ -34,15 +34,16 @@
|
||||
<div>
|
||||
</div>
|
||||
</div>
|
||||
{{-- <div class="p-4 rounded bg-coolgray-400">
|
||||
<div class="p-4 rounded bg-coolgray-400">
|
||||
<h2 id="tier-hobby" class="flex items-start gap-4 text-4xl font-bold tracking-tight">Unlimited Trial
|
||||
<x-forms.button><a class="font-bold dark:text-white hover:no-underline"
|
||||
href="https://github.com/coollabsio/coolify">Get Started</a></x-forms.button>
|
||||
</h2>
|
||||
<p class="mt-4 text-sm leading-6">Start self-hosting <span class="dark:text-warning">without limits</span> with
|
||||
<p class="mt-4 text-sm leading-6">Start self-hosting <span class="dark:text-warning">without limits</span>
|
||||
with
|
||||
our
|
||||
OSS version. Same features as the paid version, but you have to manage by yourself.</p>
|
||||
</div> --}}
|
||||
</div>
|
||||
|
||||
<div class="flow-root mt-12">
|
||||
<div class="pb-10 text-xl text-center">For the detailed list of features, please visit our landing page: <a
|
||||
@@ -78,8 +79,8 @@
|
||||
</p>
|
||||
<ul role="list" class="space-y-3 text-sm leading-6 ">
|
||||
<li class="flex">
|
||||
<svg class="flex-none w-5 h-6 mr-3 dark:text-warning" viewBox="0 0 20 20" fill="currentColor"
|
||||
aria-hidden="true">
|
||||
<svg class="flex-none w-5 h-6 mr-3 dark:text-warning" viewBox="0 0 20 20"
|
||||
fill="currentColor" aria-hidden="true">
|
||||
<path fill-rule="evenodd"
|
||||
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.775 0 001.137-.089l4-5.5z"
|
||||
clip-rule="evenodd" />
|
||||
@@ -141,13 +142,14 @@
|
||||
{{ $pro }}
|
||||
@endisset
|
||||
@endif
|
||||
<p class="h-20 mt-10 text-sm leading-6 dark:text-white">Expand your business or set up your own hosting
|
||||
<p class="h-20 mt-10 text-sm leading-6 dark:text-white">Expand your business or set up your own
|
||||
hosting
|
||||
environment.
|
||||
</p>
|
||||
<ul role="list" class="mt-6 space-y-3 text-sm leading-6 ">
|
||||
<li class="flex ">
|
||||
<svg class="flex-none w-5 h-6 mr-3 dark:text-warning" viewBox="0 0 20 20" fill="currentColor"
|
||||
aria-hidden="true">
|
||||
<svg class="flex-none w-5 h-6 mr-3 dark:text-warning" viewBox="0 0 20 20"
|
||||
fill="currentColor" aria-hidden="true">
|
||||
<path fill-rule="evenodd"
|
||||
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z"
|
||||
clip-rule="evenodd" />
|
||||
@@ -188,7 +190,7 @@
|
||||
</div>
|
||||
<div class="pt-16 lg:px-8 lg:pt-0 xl:px-12">
|
||||
<h3 id="tier-ultimate" class="text-base font-semibold leading-7 dark:text-white">Ultimate</h3>
|
||||
<p class="flex items-baseline mt-6 gap-x-1">
|
||||
<p class="flex items-baseline mt-6 gap-x-1">
|
||||
<span x-show="selected === 'monthly'" x-cloak>
|
||||
<span class="text-4xl font-bold tracking-tight dark:text-white">Custom</span>
|
||||
{{-- <span class="text-sm font-semibold leading-6 ">pay-as-you-go</span> --}}
|
||||
@@ -198,7 +200,7 @@
|
||||
{{-- <span class="text-sm font-semibold leading-6 ">/month + VAT</span> --}}
|
||||
</span>
|
||||
</p>
|
||||
<span x-show="selected === 'monthly'" x-cloak>
|
||||
<span x-show="selected === 'monthly'" x-cloak>
|
||||
<span>pay-as-you-go</span>
|
||||
</span>
|
||||
<span x-show="selected === 'yearly'" x-cloak>
|
||||
@@ -213,8 +215,8 @@
|
||||
single location.</p>
|
||||
<ul role="list" class="mt-6 space-y-3 text-sm leading-6 ">
|
||||
<li class="flex ">
|
||||
<svg class="flex-none w-5 h-6 mr-3 dark:text-warning" viewBox="0 0 20 20" fill="currentColor"
|
||||
aria-hidden="true">
|
||||
<svg class="flex-none w-5 h-6 mr-3 dark:text-warning" viewBox="0 0 20 20"
|
||||
fill="currentColor" aria-hidden="true">
|
||||
<path fill-rule="evenodd"
|
||||
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z"
|
||||
clip-rule="evenodd" />
|
||||
|
||||
@@ -46,13 +46,6 @@
|
||||
stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
|
||||
</svg>
|
||||
</button>
|
||||
{{-- <div class="flex-1 text-xl font-bold leading-6 dark:text-white">Dashboard</div> --}}
|
||||
{{-- <a href="#">
|
||||
<span class="sr-only">Your profile</span>
|
||||
<img class="w-8 h-8 rounded-full bg-gray-50"
|
||||
src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80"
|
||||
alt="">
|
||||
</a> --}}
|
||||
</div>
|
||||
|
||||
<main class="lg:pl-48">
|
||||
|
||||
@@ -4,32 +4,22 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="preconnect" href="https://api.fonts.coollabs.io" crossorigin>
|
||||
<link rel="dns-prefetch" href="https://api.fonts.coollabs.io" />
|
||||
<link rel="preload" href="https://api.fonts.coollabs.io/css2?family=Inter:wght@400;500;600;700;800&display=swap"
|
||||
as="style" />
|
||||
<link rel="preload" href="https://cdn.fonts.coollabs.io/inter/normal/400.woff2" as="style" />
|
||||
<link rel="preload" href="https://cdn.fonts.coollabs.io/inter/normal/500.woff2" as="style" />
|
||||
<link rel="preload" href="https://cdn.fonts.coollabs.io/inter/normal/600.woff2" as="style" />
|
||||
<link rel="preload" href="https://cdn.fonts.coollabs.io/inter/normal/700.woff2" as="style" />
|
||||
<link rel="preload" href="https://cdn.fonts.coollabs.io/inter/normal/800.woff2" as="style" />
|
||||
<link href="https://api.fonts.coollabs.io/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
||||
<meta name="robots" content="noindex">
|
||||
@use('App\Models\InstanceSettings')
|
||||
@php
|
||||
|
||||
$instanceSettings = InstanceSettings::first();
|
||||
$name = null;
|
||||
$instanceSettings = InstanceSettings::first();
|
||||
$name = null;
|
||||
|
||||
if($instanceSettings) {
|
||||
$displayName = $instanceSettings->getTitleDisplayName();
|
||||
if ($instanceSettings) {
|
||||
$displayName = $instanceSettings->getTitleDisplayName();
|
||||
|
||||
if(strlen($displayName) > 0) {
|
||||
$name = $displayName . ' ';
|
||||
if (strlen($displayName) > 0) {
|
||||
$name = $displayName . ' ';
|
||||
}
|
||||
}
|
||||
}
|
||||
@endphp
|
||||
<title>{{ $name }}{{ $title ?? 'Coolify' }}</title>
|
||||
<title>{{ $name }}{{ $title ?? 'Coolify' }}</title>
|
||||
@env('local')
|
||||
<link rel="icon" href="{{ asset('favicon-dev.png') }}" type="image/x-icon" />
|
||||
@else
|
||||
@@ -46,13 +36,9 @@
|
||||
<script defer data-domain="app.coolify.io" src="https://analytics.coollabs.io/js/plausible.js"></script>
|
||||
@endif
|
||||
@auth
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/laravel-echo/1.15.3/echo.iife.min.js"
|
||||
integrity="sha512-aPAh2oRUr3ALz2MwVWkd6lmdgBQC0wSr0R++zclNjXZreT/JrwDPZQwA/p6R3wOCTcXKIHgA9pQGEQBWQmdLaA=="
|
||||
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/pusher/8.3.0/pusher.min.js"
|
||||
integrity="sha512-tXL5mrkSoP49uQf2jO0LbvzMyFgki//znmq0wYXGq94gVF6TU0QlrSbwGuPpKTeN1mIjReeqKZ4/NJPjHN1d2Q=="
|
||||
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/apexcharts"></script>
|
||||
<script type="text/javascript" src="{{ URL::asset('js/echo.js') }}"></script>
|
||||
<script type="text/javascript" src="{{ URL::asset('js/pusher.js') }}"></script>
|
||||
<script type="text/javascript" src="{{ URL::asset('js/apexcharts.js') }}"></script>
|
||||
@endauth
|
||||
</head>
|
||||
@section('body')
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<div class="grid grid-cols-1 gap-2 xl:grid-cols-2">
|
||||
@foreach ($projects as $project)
|
||||
<div class="gap-2 border border-transparent cursor-pointer box group"
|
||||
onclick="window.location.href = '{{ route('project.resource.index', ['project_uuid' => data_get($project, 'uuid'), 'environment_name' => $project->default_environment()->name]) }}'">
|
||||
onclick="gotoProject('{{ $project->uuid }}','{{ $project->default_environment() }}')">
|
||||
<div class="flex flex-1 mx-6">
|
||||
<div class="flex flex-col justify-center flex-1">
|
||||
<div class="box-title">{{ $project->name }}</div>
|
||||
@@ -160,7 +160,10 @@
|
||||
@endif
|
||||
|
||||
<script>
|
||||
function gotoProject(uuid, environment = 'production') {
|
||||
function gotoProject(uuid, environment) {
|
||||
if (!environment) {
|
||||
window.location.href = '/project/' + uuid;
|
||||
}
|
||||
window.location.href = '/project/' + uuid + '/' + environment;
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -68,9 +68,9 @@
|
||||
@foreach (data_get($application, 'previews') as $previewName => $preview)
|
||||
<div class="flex flex-col w-full p-4 border dark:border-coolgray-200">
|
||||
<div class="flex gap-2">PR #{{ data_get($preview, 'pull_request_id') }} |
|
||||
@if (Str::of(data_get($preview, 'status'))->startsWith('running'))
|
||||
@if (str(data_get($preview, 'status'))->startsWith('running'))
|
||||
<x-status.running :status="data_get($preview, 'status')" />
|
||||
@elseif(Str::of(data_get($preview, 'status'))->startsWith('restarting'))
|
||||
@elseif(str(data_get($preview, 'status'))->startsWith('restarting'))
|
||||
<x-status.restarting :status="data_get($preview, 'status')" />
|
||||
@else
|
||||
<x-status.stopped :status="data_get($preview, 'status')" />
|
||||
|
||||
@@ -27,7 +27,8 @@
|
||||
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input placeholder="coollabsio/coolify-example" id="application.git_repository" label="Repository" />
|
||||
<x-forms.input placeholder="coollabsio/coolify-example" id="application.git_repository"
|
||||
label="Repository" />
|
||||
<x-forms.input placeholder="main" id="application.git_branch" label="Branch" />
|
||||
</div>
|
||||
<div class="flex items-end gap-2">
|
||||
@@ -35,14 +36,14 @@
|
||||
label="Commit SHA" />
|
||||
</div>
|
||||
</div>
|
||||
@if(data_get($application, 'private_key_id'))
|
||||
@if (data_get($application, 'private_key_id'))
|
||||
<h3 class="pt-4">Deploy Key</h3>
|
||||
<div class="py-2 pt-4">Currently attached Private Key: <span
|
||||
class="dark:text-warning">{{ data_get($application, 'private_key.name') }}</span>
|
||||
</div>
|
||||
|
||||
<h4 class="py-2 ">Select another Private Key</h4>
|
||||
<div class="flex gap-2">
|
||||
<div class="flex flex-wrap gap-2">
|
||||
@foreach ($private_keys as $key)
|
||||
<x-forms.button wire:click.defer="setPrivateKey('{{ $key->id }}')">{{ $key->name }}
|
||||
</x-forms.button>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<x-forms.button type="submit">
|
||||
Save
|
||||
</x-forms.button>
|
||||
@if (Str::of($status)->startsWith('running'))
|
||||
@if (str($status)->startsWith('running'))
|
||||
<livewire:project.database.backup-now :backup="$backup" />
|
||||
@endif
|
||||
@if ($backup->database_id !== 0)
|
||||
|
||||
@@ -12,12 +12,12 @@
|
||||
<div class="grid gap-2 lg:grid-cols-2">
|
||||
@forelse ($projects as $project)
|
||||
<div class="box group" x-data x-on:click="goto('{{ $project->uuid }}')">
|
||||
<a class="flex flex-col justify-center flex-1 mx-6"
|
||||
href="{{ route('project.resource.index', ['project_uuid' => data_get($project, 'uuid'), 'environment_name' => $project->default_environment()->name]) }}">
|
||||
<div class="flex flex-col justify-center flex-1 mx-6"
|
||||
onclick="gotoProject('{{ $project->uuid }}','{{ $project->default_environment() }}')">
|
||||
<div class="box-title">{{ $project->name }}</div>
|
||||
<div class="box-description ">
|
||||
{{ $project->description }}</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="flex items-center justify-center gap-2 pt-4 pb-2 mr-4 text-xs lg:py-0 lg:justify-normal">
|
||||
<a class="mx-4 font-bold hover:underline"
|
||||
href="{{ route('project.edit', ['project_uuid' => data_get($project, 'uuid')]) }}">
|
||||
@@ -36,5 +36,12 @@
|
||||
function goto(uuid) {
|
||||
window.location.href = '/project/' + uuid;
|
||||
}
|
||||
|
||||
function gotoProject(uuid, environment) {
|
||||
if (!environment) {
|
||||
window.location.href = '/project/' + uuid;
|
||||
}
|
||||
window.location.href = '/project/' + uuid + '/' + environment;
|
||||
}
|
||||
</script>
|
||||
</div>
|
||||
|
||||
@@ -54,11 +54,11 @@
|
||||
<div class="grid grid-cols-1 gap-2 pt-4 xl:grid-cols-1">
|
||||
@foreach ($applications as $application)
|
||||
<div @class([
|
||||
'border-l border-dashed border-red-500 ' => Str::of(
|
||||
'border-l border-dashed border-red-500 ' => str(
|
||||
$application->status)->contains(['exited']),
|
||||
'border-l border-dashed border-success' => Str::of(
|
||||
'border-l border-dashed border-success' => str(
|
||||
$application->status)->contains(['running']),
|
||||
'border-l border-dashed border-warning' => Str::of(
|
||||
'border-l border-dashed border-warning' => str(
|
||||
$application->status)->contains(['starting']),
|
||||
'flex gap-2 box-without-bg-without-border dark:bg-coolgray-100 bg-white dark:hover:text-neutral-300 group',
|
||||
])>
|
||||
@@ -123,12 +123,12 @@
|
||||
@endforeach
|
||||
@foreach ($databases as $database)
|
||||
<div @class([
|
||||
'border-l border-dashed border-red-500' => Str::of(
|
||||
$database->status)->contains(['exited']),
|
||||
'border-l border-dashed border-success' => Str::of(
|
||||
$database->status)->contains(['running']),
|
||||
'border-l border-dashed border-warning' => Str::of(
|
||||
$database->status)->contains(['restarting']),
|
||||
'border-l border-dashed border-red-500' => str($database->status)->contains(
|
||||
['exited']),
|
||||
'border-l border-dashed border-success' => str($database->status)->contains(
|
||||
['running']),
|
||||
'border-l border-dashed border-warning' => str($database->status)->contains(
|
||||
['restarting']),
|
||||
'flex gap-2 box-without-bg-without-border dark:bg-coolgray-100 bg-white dark:hover:text-neutral-300 group',
|
||||
])>
|
||||
<div class="flex flex-row w-full">
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div>
|
||||
<div class="flex gap-2">
|
||||
<h2>Service Stack</h2>
|
||||
<x-forms.button type="submit">Save</x-forms.button>
|
||||
<x-forms.button wire:target='submit' type="submit">Save</x-forms.button>
|
||||
<x-modal-input buttonTitle="Edit Compose File" title="Edit Docker Compose" :closeOutside="false">
|
||||
<livewire:project.service.edit-compose serviceId="{{ $service->id }}" />
|
||||
</x-modal-input>
|
||||
|
||||
@@ -119,7 +119,7 @@
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<h3>Memory (MB)</h3>
|
||||
<h3>Memory (%)</h3>
|
||||
<div wire:ignore id="{!! $chartId !!}-memory"></div>
|
||||
|
||||
<script>
|
||||
@@ -176,7 +176,7 @@
|
||||
}
|
||||
},
|
||||
series: [{
|
||||
name: "Memory (MB)",
|
||||
name: "Memory (%)",
|
||||
data: []
|
||||
}],
|
||||
noData: {
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
</x-slot>
|
||||
<x-server.navbar :server="$server" :parameters="$parameters" />
|
||||
<livewire:server.form :server="$server" />
|
||||
<livewire:server.delete :server="$server" />
|
||||
@if ($server->isFunctional() && $server->isMetricsEnabled())
|
||||
<div class="pt-10">
|
||||
<livewire:server.charts :server="$server" />
|
||||
</div>
|
||||
@endif
|
||||
<livewire:server.delete :server="$server" />
|
||||
</div>
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
@else
|
||||
To configure automatic backup for your Coolify instance, you first need to add as a database resource
|
||||
into Coolify.
|
||||
<x-forms.button wire:click="add_coolify_database">Add Database</x-forms.button>
|
||||
<x-forms.button class="mt-2" wire:click="add_coolify_database">Add Database</x-forms.button>
|
||||
@endif
|
||||
</div>
|
||||
<div class="py-4">
|
||||
|
||||
@@ -2,12 +2,11 @@
|
||||
@if (subscriptionProvider() === 'stripe')
|
||||
<div class="pt-4">
|
||||
<h2>Your current plan</h2>
|
||||
<div class="pb-4">Tier: <strong
|
||||
class="dark:text-warning">
|
||||
<div class="pb-4">Tier: <strong class="dark:text-warning">
|
||||
@if (data_get(currentTeam(), 'subscription')->type() == 'dynamic')
|
||||
Pay-as-you-go
|
||||
Pay-as-you-go
|
||||
@else
|
||||
{{ data_get(currentTeam(), 'subscription')->type() }}
|
||||
{{ data_get(currentTeam(), 'subscription')->type() }}
|
||||
@endif
|
||||
|
||||
</strong></div>
|
||||
@@ -50,35 +49,4 @@
|
||||
target="_blank">contact us.</a>
|
||||
</div>
|
||||
@endif
|
||||
{{-- @if (subscriptionProvider() === 'lemon')
|
||||
<div>Status: {{ currentTeam()->subscription->lemon_status }}</div>
|
||||
<div>Type: {{ currentTeam()->subscription->lemon_variant_name }}</div>
|
||||
@if (currentTeam()->subscription->lemon_status === 'cancelled')
|
||||
<div class="pb-4">Subscriptions ends at: {{ getRenewDate() }}</div>
|
||||
<div class="py-4">If you would like to change the subscription to a lower/higher plan, <a
|
||||
class="underline dark:text-white" href="{{ config('coolify.contact') }}" target="_blank">please
|
||||
contact
|
||||
us.</a></div>
|
||||
@else
|
||||
<div class="pb-4">Renews at: {{ getRenewDate() }}</div>
|
||||
@endif
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex gap-2">
|
||||
@if (currentTeam()->subscription->lemon_status === 'cancelled')
|
||||
<x-forms.button class="bg-coollabs-gradient" wire:click='resume'>Resume Subscription
|
||||
</x-forms.button>
|
||||
@else
|
||||
<x-forms.button wire:click='cancel'>Cancel Subscription</x-forms.button>
|
||||
@endif
|
||||
</div>
|
||||
<div>
|
||||
<x-forms.button><a class="dark:text-white hover:no-underline" href="{{ getPaymentLink() }}">Update Payment
|
||||
Details</a>
|
||||
</x-forms.button>
|
||||
<a class="dark:text-white hover:no-underline"
|
||||
href="https://app.lemonsqueezy.com/my-orders"><x-forms.button>Manage My
|
||||
Subscription</x-forms.button></a>
|
||||
</div>
|
||||
</div>
|
||||
@endif --}}
|
||||
</div>
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
<x-pricing-plans>
|
||||
@if (config('subscription.provider') === 'stripe')
|
||||
<x-slot:basic>
|
||||
<x-forms.button x-show="selected === 'monthly'" x-cloak aria-describedby="tier-basic" class="w-full h-10 buyme"
|
||||
wire:click="subscribeStripe('basic-monthly')">
|
||||
{{ $isTrial ? 'Start Trial' : 'Subscribe' }}
|
||||
</x-forms.button>
|
||||
|
||||
<x-forms.button x-show="selected === 'yearly'" x-cloak aria-describedby="tier-basic" class="w-full h-10 buyme"
|
||||
wire:click="subscribeStripe('basic-yearly')">
|
||||
{{ $isTrial ? 'Start Trial' : 'Subscribe' }}
|
||||
</x-forms.button>
|
||||
</x-slot:basic>
|
||||
<x-slot:pro>
|
||||
<x-forms.button x-show="selected === 'monthly'" x-cloak aria-describedby="tier-pro" class="w-full h-10 buyme"
|
||||
wire:click="subscribeStripe('pro-monthly')">
|
||||
{{ $isTrial ? 'Start Trial' : 'Subscribe' }}
|
||||
</x-forms.button>
|
||||
|
||||
<x-forms.button x-show="selected === 'yearly'" x-cloak aria-describedby="tier-pro" class="w-full h-10 buyme"
|
||||
wire:click="subscribeStripe('pro-yearly')"> {{ $isTrial ? 'Start Trial' : 'Subscribe' }}
|
||||
</x-forms.button>
|
||||
</x-slot:pro>
|
||||
<x-slot:ultimate>
|
||||
<x-forms.button x-show="selected === 'monthly'" x-cloak aria-describedby="tier-ultimate" class="w-full h-10 buyme"
|
||||
wire:click="subscribeStripe('ultimate-monthly')">
|
||||
{{ $isTrial ? 'Start Trial' : 'Subscribe' }}
|
||||
</x-forms.button>
|
||||
|
||||
<x-forms.button x-show="selected === 'yearly'" x-cloak aria-describedby="tier-ultimate" class="w-full h-10 buyme"
|
||||
wire:click="subscribeStripe('ultimate-yearly')"> {{ $isTrial ? 'Start Trial' : 'Subscribe' }}
|
||||
</x-forms.button>
|
||||
</x-slot:ultimate>
|
||||
@endif
|
||||
@if (config('subscription.provider') === 'paddle')
|
||||
<x-paddle />
|
||||
@endif
|
||||
@if (config('subscription.provider') === 'lemon')
|
||||
<x-slot:basic>
|
||||
<x-forms.button x-show="selected === 'monthly'" x-cloak aria-describedby="tier-basic"
|
||||
class="w-full h-10 buyme" wire:click="getSubscriptionLink('basic-monthly')"> Subscribe
|
||||
</x-forms.button>
|
||||
|
||||
<x-forms.button x-show="selected === 'yearly'" x-cloak aria-describedby="tier-basic"
|
||||
class="w-full h-10 buyme" wire:click="getSubscriptionLink('basic-yearly')"> Subscribe
|
||||
</x-forms.button>
|
||||
</x-slot:basic>
|
||||
<x-slot:pro>
|
||||
<x-forms.button x-show="selected === 'monthly'" x-cloak aria-describedby="tier-pro"
|
||||
class="w-full h-10 buyme" wire:click="getSubscriptionLink('pro-monthly')"> Subscribe
|
||||
</x-forms.button>
|
||||
|
||||
<x-forms.button x-show="selected === 'yearly'" x-cloak aria-describedby="tier-pro" class="w-full h-10 buyme"
|
||||
wire:click="getSubscriptionLink('pro-yearly')"> Subscribe
|
||||
</x-forms.button>
|
||||
</x-slot:pro>
|
||||
<x-slot:ultimate>
|
||||
<x-forms.button x-show="selected === 'monthly'" x-cloak aria-describedby="tier-ultimate"
|
||||
class="w-full h-10 buyme" wire:click="getSubscriptionLink('ultimate-monthly')"> Subscribe
|
||||
</x-forms.button>
|
||||
|
||||
<x-forms.button x-show="selected === 'yearly'" x-cloak aria-describedby="tier-ultimate"
|
||||
class="w-full h-10 buyme" wire:click="getSubscriptionLink('ultimate-yearly')"> Subscribe
|
||||
</x-forms.button>
|
||||
</x-slot:ultimate>
|
||||
@endif
|
||||
</x-pricing-plans>
|
||||
@@ -25,7 +25,7 @@
|
||||
<div>This is the default team. You can't delete it.</div>
|
||||
@elseif(auth()->user()->teams()->get()->count() === 1 || auth()->user()->currentTeam()->personal_team)
|
||||
<div>You can't delete your last / personal team.</div>
|
||||
@elseif(currentTeam()->subscription && currentTeam()->subscription?->lemon_status !== 'cancelled')
|
||||
@elseif(currentTeam()->subscription)
|
||||
<div>Please cancel your subscription <a class="underline dark:text-white"
|
||||
href="{{ route('subscription.show') }}">here</a> before delete this team.</div>
|
||||
@else
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
<template x-teleport="body">
|
||||
<div x-show="modalOpen"
|
||||
class="fixed top-0 lg:pt-10 left-0 z-[99] flex items-start justify-center w-screen h-screen" style="zoom:1.1;"
|
||||
class="fixed top-0 lg:pt-10 left-0 z-[99] flex items-start justify-center w-screen h-screen"
|
||||
x-cloak>
|
||||
<div x-show="modalOpen" x-transition:enter="ease-out duration-100"
|
||||
x-transition:enter-start="opacity-0" x-transition:enter-end="opacity-100"
|
||||
@@ -58,23 +58,26 @@
|
||||
<div class="relative w-auto pb-8">
|
||||
<p>Are you sure you would like to upgrade your instance to {{ $latestVersion }}?</p>
|
||||
<br />
|
||||
<p>You can review the changelogs <a class="font-bold underline"
|
||||
<p>You can review the changelogs <a class="font-bold underline dark:text-white"
|
||||
href="https://github.com/coollabsio/coolify/releases" target="_blank">here</a>.</p>
|
||||
<br />
|
||||
<p>If something goes wrong and you cannot upgrade your instance, You can check the following <a class="font-bold underline"
|
||||
href="https://coolify.io/docs/upgrade" target="_blank">guide</a> on what to do.</p>
|
||||
<p>If something goes wrong and you cannot upgrade your instance, You can check the following
|
||||
<a class="font-bold underline dark:text-white" href="https://coolify.io/docs/upgrade"
|
||||
target="_blank">guide</a> on what to do.
|
||||
</p>
|
||||
@if ($showProgress)
|
||||
<div class="flex flex-col pt-4">
|
||||
<h4>Progress <x-loading /></h4>
|
||||
<h2>Progress <x-loading /></h2>
|
||||
<div x-html="currentStatus"></div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
<div class="flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2">
|
||||
<div class="flex gap-4">
|
||||
@if (!$showProgress)
|
||||
<x-forms.button @click="modalOpen=false"
|
||||
class="w-24 dark:bg-coolgray-200 dark:hover:bg-coolgray-300">Cancel
|
||||
</x-forms.button>
|
||||
<div class="flex-1"></div>
|
||||
<x-forms.button @click="confirmed" class="w-24" isHighlighted type="button">Continue
|
||||
</x-forms.button>
|
||||
@endif
|
||||
@@ -96,6 +99,10 @@
|
||||
this.$wire.$call('upgrade')
|
||||
this.upgrade();
|
||||
this.$wire.showProgress = true;
|
||||
window.addEventListener('beforeunload', (event) => {
|
||||
event.preventDefault();
|
||||
event.returnValue = '';
|
||||
});
|
||||
},
|
||||
revive() {
|
||||
if (checkHealthInterval) return true;
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
<?php
|
||||
|
||||
use App\Actions\CoolifyTask\RunRemoteProcess;
|
||||
use App\Actions\CoolifyTask\TidyOutput;
|
||||
use App\Models\Server;
|
||||
use App\Models\User;
|
||||
use Database\Seeders\DatabaseSeeder;
|
||||
use Illuminate\Foundation\Testing\DatabaseMigrations;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
uses(DatabaseMigrations::class);
|
||||
|
||||
beforeEach(function () {
|
||||
$this->seed(DatabaseSeeder::class);
|
||||
});
|
||||
|
||||
it('starts a docker container correctly', function () {
|
||||
|
||||
|
||||
test()->actingAs(User::factory([
|
||||
'uuid' => Str::uuid(),
|
||||
'email' => Str::uuid() . '@example.com',
|
||||
])->create());
|
||||
|
||||
$coolifyNamePrefix = 'coolify_test_';
|
||||
|
||||
|
||||
$format = '{"ID":"{{ .ID }}", "Image": "{{ .Image }}", "Names":"{{ .Names }}"}';
|
||||
$areThereCoolifyTestContainers = "docker ps --filter=\"name={$coolifyNamePrefix}*\" --format '{$format}' ";
|
||||
|
||||
// Generate a known name
|
||||
$containerName = 'coolify_test_' . now()->format('Ymd_his');
|
||||
$host = Server::where('name', 'testing-local-docker-container')->first();
|
||||
|
||||
remote_process([
|
||||
"docker rm -f $(docker ps --filter='name={$coolifyNamePrefix}*' -aq) > /dev/null 2>&1"
|
||||
], $host);
|
||||
|
||||
// Assert there's no containers start with coolify_test_*
|
||||
$activity = remote_process([$areThereCoolifyTestContainers], $host);
|
||||
$tidyOutput = RunRemoteProcess::decodeOutput($activity);
|
||||
$containers = format_docker_command_output_to_json($tidyOutput);
|
||||
expect($containers)->toBeEmpty();
|
||||
|
||||
// start a container nginx -d --name = $containerName
|
||||
$activity = remote_process(["docker run -d --rm --name {$containerName} nginx"], $host);
|
||||
expect($activity->getExtraProperty('exitCode'))->toBe(0);
|
||||
|
||||
// docker ps name = $container
|
||||
$activity = remote_process([$areThereCoolifyTestContainers], $host);
|
||||
$tidyOutput = RunRemoteProcess::decodeOutput($activity);
|
||||
$containers = format_docker_command_output_to_json($tidyOutput);
|
||||
expect($containers->where('Names', $containerName)->count())->toBe(1);
|
||||
|
||||
// Stop testing containers
|
||||
$activity = remote_process([
|
||||
"docker ps --filter='name={$coolifyNamePrefix}*' -aq && " .
|
||||
"docker rm -f $(docker ps --filter='name={$coolifyNamePrefix}*' -aq)"
|
||||
], $host);
|
||||
expect($activity->getExtraProperty('exitCode'))->toBe(0);
|
||||
});
|
||||
@@ -1,32 +0,0 @@
|
||||
<?php
|
||||
|
||||
use App\Actions\CoolifyTask\RunRemoteProcess;
|
||||
use App\Models\Server;
|
||||
use Database\Seeders\DatabaseSeeder;
|
||||
use Illuminate\Foundation\Testing\DatabaseMigrations;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
uses(DatabaseMigrations::class);
|
||||
|
||||
beforeEach(function () {
|
||||
$this->seed(DatabaseSeeder::class);
|
||||
});
|
||||
|
||||
it('outputs correctly', function () {
|
||||
|
||||
$host = Server::where('name', 'testing-local-docker-container')->first();
|
||||
|
||||
$activity = remote_process([
|
||||
'pwd',
|
||||
'x=1; while [ $x -le 3 ]; do sleep 0.1 && echo "Welcome $x times" $(( x++ )); done',
|
||||
], $host);
|
||||
|
||||
|
||||
$tidyOutput = RunRemoteProcess::decodeOutput($activity);
|
||||
|
||||
expect($tidyOutput)
|
||||
->toContain('Welcome 1 times')
|
||||
->toContain('Welcome 3 times')
|
||||
->not()->toBeJson();
|
||||
});
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"coolify": {
|
||||
"v4": {
|
||||
"version": "4.0.0-beta.298"
|
||||
"version": "4.0.0-beta.306"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user