mirror of
https://github.com/ershisan99/coolify.git
synced 2026-01-01 20:59:24 +00:00
Compare commits
29 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 |
@@ -3,6 +3,7 @@
|
|||||||
namespace App\Actions\CoolifyTask;
|
namespace App\Actions\CoolifyTask;
|
||||||
|
|
||||||
use App\Data\CoolifyTaskArgs;
|
use App\Data\CoolifyTaskArgs;
|
||||||
|
use App\Enums\ActivityTypes;
|
||||||
use App\Jobs\CoolifyTask;
|
use App\Jobs\CoolifyTask;
|
||||||
use Spatie\Activitylog\Models\Activity;
|
use Spatie\Activitylog\Models\Activity;
|
||||||
|
|
||||||
@@ -40,8 +41,18 @@ class PrepareCoolifyTask
|
|||||||
|
|
||||||
public function __invoke(): Activity
|
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);
|
$job = new CoolifyTask(
|
||||||
dispatch($job);
|
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();
|
$this->activity->refresh();
|
||||||
|
|
||||||
return $this->activity;
|
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)
|
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.');
|
throw new \RuntimeException('Incompatible Activity to run a remote command.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
namespace App\Actions\Database;
|
namespace App\Actions\Database;
|
||||||
|
|
||||||
use App\Models\StandaloneClickhouse;
|
use App\Models\StandaloneClickhouse;
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use Lorisleiva\Actions\Concerns\AsAction;
|
use Lorisleiva\Actions\Concerns\AsAction;
|
||||||
use Symfony\Component\Yaml\Yaml;
|
use Symfony\Component\Yaml\Yaml;
|
||||||
|
|
||||||
@@ -155,11 +154,11 @@ class StartClickhouse
|
|||||||
$environment_variables->push("$env->key=$env->real_value");
|
$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}");
|
$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}");
|
$environment_variables->push("CLICKHOUSE_ADMIN_PASSWORD={$this->database->clickhouse_admin_password}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
namespace App\Actions\Database;
|
namespace App\Actions\Database;
|
||||||
|
|
||||||
use App\Models\StandaloneDragonfly;
|
use App\Models\StandaloneDragonfly;
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use Lorisleiva\Actions\Concerns\AsAction;
|
use Lorisleiva\Actions\Concerns\AsAction;
|
||||||
use Symfony\Component\Yaml\Yaml;
|
use Symfony\Component\Yaml\Yaml;
|
||||||
|
|
||||||
@@ -155,7 +154,7 @@ class StartDragonfly
|
|||||||
$environment_variables->push("$env->key=$env->real_value");
|
$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}");
|
$environment_variables->push("REDIS_PASSWORD={$this->database->dragonfly_password}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ namespace App\Actions\Database;
|
|||||||
|
|
||||||
use App\Models\StandaloneKeydb;
|
use App\Models\StandaloneKeydb;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use Lorisleiva\Actions\Concerns\AsAction;
|
use Lorisleiva\Actions\Concerns\AsAction;
|
||||||
use Symfony\Component\Yaml\Yaml;
|
use Symfony\Component\Yaml\Yaml;
|
||||||
|
|
||||||
@@ -163,7 +162,7 @@ class StartKeydb
|
|||||||
$environment_variables->push("$env->key=$env->real_value");
|
$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}");
|
$environment_variables->push("REDIS_PASSWORD={$this->database->keydb_password}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
namespace App\Actions\Database;
|
namespace App\Actions\Database;
|
||||||
|
|
||||||
use App\Models\StandaloneMariadb;
|
use App\Models\StandaloneMariadb;
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use Lorisleiva\Actions\Concerns\AsAction;
|
use Lorisleiva\Actions\Concerns\AsAction;
|
||||||
use Symfony\Component\Yaml\Yaml;
|
use Symfony\Component\Yaml\Yaml;
|
||||||
|
|
||||||
@@ -157,18 +156,18 @@ class StartMariadb
|
|||||||
$environment_variables->push("$env->key=$env->real_value");
|
$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}");
|
$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}");
|
$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}");
|
$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}");
|
$environment_variables->push("MARIADB_PASSWORD={$this->database->mariadb_password}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
namespace App\Actions\Database;
|
namespace App\Actions\Database;
|
||||||
|
|
||||||
use App\Models\StandaloneMongodb;
|
use App\Models\StandaloneMongodb;
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use Lorisleiva\Actions\Concerns\AsAction;
|
use Lorisleiva\Actions\Concerns\AsAction;
|
||||||
use Symfony\Component\Yaml\Yaml;
|
use Symfony\Component\Yaml\Yaml;
|
||||||
|
|
||||||
@@ -174,15 +173,15 @@ class StartMongodb
|
|||||||
$environment_variables->push("$env->key=$env->real_value");
|
$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}");
|
$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}");
|
$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}");
|
$environment_variables->push("MONGO_INITDB_DATABASE={$this->database->mongo_initdb_database}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
namespace App\Actions\Database;
|
namespace App\Actions\Database;
|
||||||
|
|
||||||
use App\Models\StandaloneMysql;
|
use App\Models\StandaloneMysql;
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use Lorisleiva\Actions\Concerns\AsAction;
|
use Lorisleiva\Actions\Concerns\AsAction;
|
||||||
use Symfony\Component\Yaml\Yaml;
|
use Symfony\Component\Yaml\Yaml;
|
||||||
|
|
||||||
@@ -157,18 +156,18 @@ class StartMysql
|
|||||||
$environment_variables->push("$env->key=$env->real_value");
|
$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}");
|
$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}");
|
$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}");
|
$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}");
|
$environment_variables->push("MYSQL_PASSWORD={$this->database->mysql_password}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
namespace App\Actions\Database;
|
namespace App\Actions\Database;
|
||||||
|
|
||||||
use App\Models\StandalonePostgresql;
|
use App\Models\StandalonePostgresql;
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use Lorisleiva\Actions\Concerns\AsAction;
|
use Lorisleiva\Actions\Concerns\AsAction;
|
||||||
use Symfony\Component\Yaml\Yaml;
|
use Symfony\Component\Yaml\Yaml;
|
||||||
|
|
||||||
@@ -179,18 +178,18 @@ class StartPostgresql
|
|||||||
$environment_variables->push("$env->key=$env->real_value");
|
$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}");
|
$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}");
|
$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}");
|
$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}");
|
$environment_variables->push("POSTGRES_DB={$this->database->postgres_db}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ namespace App\Actions\Database;
|
|||||||
|
|
||||||
use App\Models\StandaloneRedis;
|
use App\Models\StandaloneRedis;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use Lorisleiva\Actions\Concerns\AsAction;
|
use Lorisleiva\Actions\Concerns\AsAction;
|
||||||
use Symfony\Component\Yaml\Yaml;
|
use Symfony\Component\Yaml\Yaml;
|
||||||
|
|
||||||
@@ -167,7 +166,7 @@ class StartRedis
|
|||||||
$environment_variables->push("$env->key=$env->real_value");
|
$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}");
|
$environment_variables->push("REDIS_PASSWORD={$this->database->redis_password}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
namespace App\Actions\Proxy;
|
namespace App\Actions\Proxy;
|
||||||
|
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use Lorisleiva\Actions\Concerns\AsAction;
|
use Lorisleiva\Actions\Concerns\AsAction;
|
||||||
|
|
||||||
class CheckConfiguration
|
class CheckConfiguration
|
||||||
@@ -24,7 +23,7 @@ class CheckConfiguration
|
|||||||
$proxy_configuration = instant_remote_process($payload, $server, false);
|
$proxy_configuration = instant_remote_process($payload, $server, false);
|
||||||
|
|
||||||
if ($reset || ! $proxy_configuration || is_null($proxy_configuration)) {
|
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)) {
|
if (! $proxy_configuration || is_null($proxy_configuration)) {
|
||||||
throw new \Exception('Could not generate proxy configuration');
|
throw new \Exception('Could not generate proxy configuration');
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
namespace App\Actions\Proxy;
|
namespace App\Actions\Proxy;
|
||||||
|
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use Lorisleiva\Actions\Concerns\AsAction;
|
use Lorisleiva\Actions\Concerns\AsAction;
|
||||||
|
|
||||||
class SaveConfiguration
|
class SaveConfiguration
|
||||||
@@ -18,7 +17,7 @@ class SaveConfiguration
|
|||||||
$proxy_path = $server->proxyPath();
|
$proxy_path = $server->proxyPath();
|
||||||
$docker_compose_yml_base64 = base64_encode($proxy_settings);
|
$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();
|
$server->save();
|
||||||
|
|
||||||
return instant_remote_process([
|
return instant_remote_process([
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ namespace App\Actions\Proxy;
|
|||||||
|
|
||||||
use App\Events\ProxyStarted;
|
use App\Events\ProxyStarted;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use Lorisleiva\Actions\Concerns\AsAction;
|
use Lorisleiva\Actions\Concerns\AsAction;
|
||||||
use Spatie\Activitylog\Models\Activity;
|
use Spatie\Activitylog\Models\Activity;
|
||||||
|
|
||||||
@@ -27,7 +26,7 @@ class StartProxy
|
|||||||
}
|
}
|
||||||
SaveConfiguration::run($server, $configuration);
|
SaveConfiguration::run($server, $configuration);
|
||||||
$docker_compose_yml_base64 = base64_encode($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();
|
$server->save();
|
||||||
if ($server->isSwarm()) {
|
if ($server->isSwarm()) {
|
||||||
$commands = $commands->merge([
|
$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) {
|
if (! $this->server) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
CleanupDocker::run($this->server, false);
|
CleanupDocker::dispatch($this->server, false)->onQueue('high');
|
||||||
$this->latestVersion = get_latest_version_of_coolify();
|
$this->latestVersion = get_latest_version_of_coolify();
|
||||||
$this->currentVersion = config('version');
|
$this->currentVersion = config('version');
|
||||||
if (! $manual_update) {
|
if (! $manual_update) {
|
||||||
@@ -48,6 +48,7 @@ class UpdateCoolify
|
|||||||
private function update()
|
private function update()
|
||||||
{
|
{
|
||||||
if (isDev()) {
|
if (isDev()) {
|
||||||
|
ray('Running in dev mode');
|
||||||
remote_process([
|
remote_process([
|
||||||
'sleep 10',
|
'sleep 10',
|
||||||
], $this->server);
|
], $this->server);
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ class WaitlistInvite extends Command
|
|||||||
if (! $already_registered) {
|
if (! $already_registered) {
|
||||||
$this->password = Str::password();
|
$this->password = Str::password();
|
||||||
User::create([
|
User::create([
|
||||||
'name' => Str::of($this->next_patient->email)->before('@'),
|
'name' => str($this->next_patient->email)->before('@'),
|
||||||
'email' => $this->next_patient->email,
|
'email' => $this->next_patient->email,
|
||||||
'password' => Hash::make($this->password),
|
'password' => Hash::make($this->password),
|
||||||
'force_password_reset' => true,
|
'force_password_reset' => true,
|
||||||
|
|||||||
@@ -5,4 +5,5 @@ namespace App\Enums;
|
|||||||
enum ActivityTypes: string
|
enum ActivityTypes: string
|
||||||
{
|
{
|
||||||
case INLINE = 'inline';
|
case INLINE = 'inline';
|
||||||
|
case COMMAND = 'command';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,8 +81,8 @@ class Controller extends BaseController
|
|||||||
$token = request()->get('token');
|
$token = request()->get('token');
|
||||||
if ($token) {
|
if ($token) {
|
||||||
$decrypted = Crypt::decryptString($token);
|
$decrypted = Crypt::decryptString($token);
|
||||||
$email = Str::of($decrypted)->before('@@@');
|
$email = str($decrypted)->before('@@@');
|
||||||
$password = Str::of($decrypted)->after('@@@');
|
$password = str($decrypted)->after('@@@');
|
||||||
$user = User::whereEmail($email)->first();
|
$user = User::whereEmail($email)->first();
|
||||||
if (! $user) {
|
if (! $user) {
|
||||||
return redirect()->route('login');
|
return redirect()->route('login');
|
||||||
|
|||||||
@@ -965,6 +965,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
$nixpacks_php_fallback_path = new EnvironmentVariable();
|
$nixpacks_php_fallback_path = new EnvironmentVariable();
|
||||||
$nixpacks_php_fallback_path->key = 'NIXPACKS_PHP_FALLBACK_PATH';
|
$nixpacks_php_fallback_path->key = 'NIXPACKS_PHP_FALLBACK_PATH';
|
||||||
$nixpacks_php_fallback_path->value = '/index.php';
|
$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->application_id = $this->application->id;
|
||||||
$nixpacks_php_fallback_path->save();
|
$nixpacks_php_fallback_path->save();
|
||||||
}
|
}
|
||||||
@@ -972,6 +973,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
$nixpacks_php_root_dir = new EnvironmentVariable();
|
$nixpacks_php_root_dir = new EnvironmentVariable();
|
||||||
$nixpacks_php_root_dir->key = 'NIXPACKS_PHP_ROOT_DIR';
|
$nixpacks_php_root_dir->key = 'NIXPACKS_PHP_ROOT_DIR';
|
||||||
$nixpacks_php_root_dir->value = '/app/public';
|
$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->application_id = $this->application->id;
|
||||||
$nixpacks_php_root_dir->save();
|
$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}");
|
$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->newVersionIsHealthy = true;
|
||||||
$this->application->update(['status' => 'running']);
|
$this->application->update(['status' => 'running']);
|
||||||
$this->application_deployment_queue->addLogEntry('New container is healthy.');
|
$this->application_deployment_queue->addLogEntry('New container is healthy.');
|
||||||
break;
|
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->newVersionIsHealthy = false;
|
||||||
$this->query_logs();
|
$this->query_logs();
|
||||||
break;
|
break;
|
||||||
@@ -1094,7 +1096,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
$sleeptime++;
|
$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();
|
$this->query_logs();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1535,7 +1537,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
$this->execute_remote_command([
|
$this->execute_remote_command([
|
||||||
executeInDocker($this->deployment_uuid, "cat {$this->workdir}{$this->dockerfile_location}"), 'hidden' => true, 'save' => 'dockerfile_from_repo', 'ignore_errors' => true,
|
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);
|
$this->application->parseHealthcheckFromDockerfile($dockerfile);
|
||||||
}
|
}
|
||||||
$docker_compose = [
|
$docker_compose = [
|
||||||
@@ -2107,7 +2109,7 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
|
|||||||
$this->execute_remote_command([
|
$this->execute_remote_command([
|
||||||
executeInDocker($this->deployment_uuid, "cat {$this->workdir}{$this->dockerfile_location}"), 'hidden' => true, 'save' => 'dockerfile',
|
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) {
|
if ($this->pull_request_id === 0) {
|
||||||
foreach ($this->application->build_environment_variables as $env) {
|
foreach ($this->application->build_environment_variables as $env) {
|
||||||
if (data_get($env, 'is_multiline') === true) {
|
if (data_get($env, 'is_multiline') === true) {
|
||||||
|
|||||||
@@ -20,9 +20,9 @@ class CoolifyTask implements ShouldBeEncrypted, ShouldQueue
|
|||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
public Activity $activity,
|
public Activity $activity,
|
||||||
public bool $ignore_errors = false,
|
public bool $ignore_errors,
|
||||||
public $call_event_on_finish = null,
|
public $call_event_on_finish,
|
||||||
public $call_event_data = null
|
public $call_event_data,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$status = Str::of(data_get($this->database, 'status'));
|
$status = str(data_get($this->database, 'status'));
|
||||||
if (! $status->startsWith('running') && $this->database->id !== 0) {
|
if (! $status->startsWith('running') && $this->database->id !== 0) {
|
||||||
ray('database not running');
|
ray('database not running');
|
||||||
|
|
||||||
@@ -236,7 +236,7 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
return;
|
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') {
|
if ($this->database->name === 'coolify-db') {
|
||||||
$databasesToBackup = ['coolify'];
|
$databasesToBackup = ['coolify'];
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ namespace App\Livewire\Project\Application;
|
|||||||
use App\Models\Application;
|
use App\Models\Application;
|
||||||
use App\Models\LocalFileVolume;
|
use App\Models\LocalFileVolume;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
use Visus\Cuid2\Cuid2;
|
use Visus\Cuid2\Cuid2;
|
||||||
|
|
||||||
@@ -199,8 +198,8 @@ class General extends Component
|
|||||||
return str($volume)->startsWith('/data/coolify');
|
return str($volume)->startsWith('/data/coolify');
|
||||||
})->unique()->values();
|
})->unique()->values();
|
||||||
foreach ($volumes as $volume) {
|
foreach ($volumes as $volume) {
|
||||||
$source = Str::of($volume)->before(':');
|
$source = str($volume)->before(':');
|
||||||
$target = Str::of($volume)->after(':')->beforeLast(':');
|
$target = str($volume)->after(':')->beforeLast(':');
|
||||||
|
|
||||||
LocalFileVolume::updateOrCreate(
|
LocalFileVolume::updateOrCreate(
|
||||||
[
|
[
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
namespace App\Livewire\Project\Application\Preview;
|
namespace App\Livewire\Project\Application\Preview;
|
||||||
|
|
||||||
use App\Models\Application;
|
use App\Models\Application;
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
use Spatie\Url\Url;
|
use Spatie\Url\Url;
|
||||||
|
|
||||||
@@ -32,10 +31,10 @@ class Form extends Component
|
|||||||
public function generate_real_url()
|
public function generate_real_url()
|
||||||
{
|
{
|
||||||
if (data_get($this->application, 'fqdn')) {
|
if (data_get($this->application, 'fqdn')) {
|
||||||
$firstFqdn = Str::of($this->application->fqdn)->before(',');
|
$firstFqdn = str($this->application->fqdn)->before(',');
|
||||||
$url = Url::fromString($firstFqdn);
|
$url = Url::fromString($firstFqdn);
|
||||||
$host = $url->getHost();
|
$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;
|
namespace App\Livewire\Project\Application;
|
||||||
|
|
||||||
use App\Models\Application;
|
use App\Models\Application;
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
use Visus\Cuid2\Cuid2;
|
use Visus\Cuid2\Cuid2;
|
||||||
|
|
||||||
@@ -50,16 +49,16 @@ class Rollback extends Component
|
|||||||
$output = instant_remote_process([
|
$output = instant_remote_process([
|
||||||
"docker inspect --format='{{.Config.Image}}' {$this->application->uuid}",
|
"docker inspect --format='{{.Config.Image}}' {$this->application->uuid}",
|
||||||
], $this->application->destination->server, throwError: false);
|
], $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);
|
$this->current = data_get($current_tag, 1);
|
||||||
|
|
||||||
$output = instant_remote_process([
|
$output = instant_remote_process([
|
||||||
"docker images --format '{{.Repository}}#{{.Tag}}#{{.CreatedAt}}'",
|
"docker images --format '{{.Repository}}#{{.Tag}}#{{.CreatedAt}}'",
|
||||||
], $this->application->destination->server);
|
], $this->application->destination->server);
|
||||||
$this->images = Str::of($output)->trim()->explode("\n")->filter(function ($item) use ($image) {
|
$this->images = str($output)->trim()->explode("\n")->filter(function ($item) use ($image) {
|
||||||
return Str::of($item)->contains($image);
|
return str($item)->contains($image);
|
||||||
})->map(function ($item) {
|
})->map(function ($item) {
|
||||||
$item = Str::of($item)->explode('#');
|
$item = str($item)->explode('#');
|
||||||
if ($item[1] === $this->current) {
|
if ($item[1] === $this->current) {
|
||||||
// $is_current = true;
|
// $is_current = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ use App\Models\Application;
|
|||||||
use App\Models\Project;
|
use App\Models\Project;
|
||||||
use App\Models\StandaloneDocker;
|
use App\Models\StandaloneDocker;
|
||||||
use App\Models\SwarmDocker;
|
use App\Models\SwarmDocker;
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
use Visus\Cuid2\Cuid2;
|
use Visus\Cuid2\Cuid2;
|
||||||
|
|
||||||
@@ -29,9 +28,9 @@ class DockerImage extends Component
|
|||||||
$this->validate([
|
$this->validate([
|
||||||
'dockerImage' => 'required',
|
'dockerImage' => 'required',
|
||||||
]);
|
]);
|
||||||
$image = Str::of($this->dockerImage)->before(':');
|
$image = str($this->dockerImage)->before(':');
|
||||||
if (Str::of($this->dockerImage)->contains(':')) {
|
if (str($this->dockerImage)->contains(':')) {
|
||||||
$tag = Str::of($this->dockerImage)->after(':');
|
$tag = str($this->dockerImage)->after(':');
|
||||||
} else {
|
} else {
|
||||||
$tag = 'latest';
|
$tag = 'latest';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -193,7 +193,7 @@ class GithubPrivateRepositoryDeployKey extends Component
|
|||||||
|
|
||||||
return;
|
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_host = $this->repository_url_parsed->getHost();
|
||||||
$this->git_repository = $this->repository_url_parsed->getSegment(1).'/'.$this->repository_url_parsed->getSegment(2);
|
$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');
|
$this->git_repository = Str::finish("git@$this->git_host:$this->git_repository", '.git');
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ class EditCompose extends Component
|
|||||||
|
|
||||||
public $serviceId;
|
public $serviceId;
|
||||||
|
|
||||||
protected $listeners = ['refreshEnvs' => 'mount'];
|
protected $listeners = ['refreshEnvs', 'envsUpdated'];
|
||||||
|
|
||||||
protected $rules = [
|
protected $rules = [
|
||||||
'service.docker_compose_raw' => 'required',
|
'service.docker_compose_raw' => 'required',
|
||||||
@@ -19,6 +19,17 @@ class EditCompose extends Component
|
|||||||
'service.is_container_label_escape_enabled' => 'required',
|
'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()
|
public function mount()
|
||||||
{
|
{
|
||||||
$this->service = Service::find($this->serviceId);
|
$this->service = Service::find($this->serviceId);
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ use App\Models\StandaloneMongodb;
|
|||||||
use App\Models\StandaloneMysql;
|
use App\Models\StandaloneMysql;
|
||||||
use App\Models\StandalonePostgresql;
|
use App\Models\StandalonePostgresql;
|
||||||
use App\Models\StandaloneRedis;
|
use App\Models\StandaloneRedis;
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class FileStorage extends Component
|
class FileStorage extends Component
|
||||||
@@ -37,9 +36,9 @@ class FileStorage extends Component
|
|||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
$this->resource = $this->fileStorage->service;
|
$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->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 {
|
} else {
|
||||||
$this->workdir = null;
|
$this->workdir = null;
|
||||||
$this->fs_path = $this->fileStorage->fs_path;
|
$this->fs_path = $this->fileStorage->fs_path;
|
||||||
|
|||||||
@@ -81,7 +81,6 @@ class StackForm extends Component
|
|||||||
return handleError($e, $this);
|
return handleError($e, $this);
|
||||||
} finally {
|
} finally {
|
||||||
if (is_null($this->service->config_hash)) {
|
if (is_null($this->service->config_hash)) {
|
||||||
ray('asdf');
|
|
||||||
$this->service->isConfigurationChanged(true);
|
$this->service->isConfigurationChanged(true);
|
||||||
} else {
|
} else {
|
||||||
$this->dispatch('configurationChanged');
|
$this->dispatch('configurationChanged');
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ class Show extends Component
|
|||||||
$this->serialize();
|
$this->serialize();
|
||||||
$this->env->save();
|
$this->env->save();
|
||||||
$this->dispatch('success', 'Environment variable updated.');
|
$this->dispatch('success', 'Environment variable updated.');
|
||||||
$this->dispatch('refreshEnvs');
|
$this->dispatch('envsUpdated');
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
return handleError($e);
|
return handleError($e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Livewire\Project\Shared;
|
namespace App\Livewire\Project\Shared;
|
||||||
|
|
||||||
|
use App\Actions\Server\RunCommand;
|
||||||
use App\Models\Application;
|
use App\Models\Application;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use App\Models\Service;
|
use App\Models\Service;
|
||||||
@@ -137,7 +138,7 @@ class ExecuteContainerCommand extends Component
|
|||||||
} else {
|
} else {
|
||||||
$exec = "docker exec {$container_name} {$cmd}";
|
$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);
|
$this->dispatch('activityMonitor', $activity->id);
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return handleError($e, $this);
|
return handleError($e, $this);
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Livewire;
|
namespace App\Livewire;
|
||||||
|
|
||||||
|
use App\Actions\Server\RunCommand as ServerRunCommand;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
@@ -33,7 +34,7 @@ class RunCommand extends Component
|
|||||||
{
|
{
|
||||||
$this->validate();
|
$this->validate();
|
||||||
try {
|
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);
|
$this->dispatch('activityMonitor', $activity->id);
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return handleError($e, $this);
|
return handleError($e, $this);
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ use App\Actions\Proxy\CheckConfiguration;
|
|||||||
use App\Actions\Proxy\SaveConfiguration;
|
use App\Actions\Proxy\SaveConfiguration;
|
||||||
use App\Actions\Proxy\StartProxy;
|
use App\Actions\Proxy\StartProxy;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class Proxy extends Component
|
class Proxy extends Component
|
||||||
@@ -79,7 +78,7 @@ class Proxy extends Component
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$this->proxy_settings = CheckConfiguration::run($this->server);
|
$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);
|
$this->dispatch('traefikDashboardAvailable', true);
|
||||||
} else {
|
} else {
|
||||||
$this->dispatch('traefikDashboardAvailable', false);
|
$this->dispatch('traefikDashboardAvailable', false);
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
namespace App\Livewire\Subscription;
|
namespace App\Livewire\Subscription;
|
||||||
|
|
||||||
use App\Models\Team;
|
use App\Models\Team;
|
||||||
use Illuminate\Support\Facades\Http;
|
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class Actions extends Component
|
class Actions extends Component
|
||||||
@@ -15,70 +14,6 @@ class Actions extends Component
|
|||||||
$this->server_limits = Team::serverLimit();
|
$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()
|
public function stripeCustomerPortal()
|
||||||
{
|
{
|
||||||
$session = getStripeCustomerPortalSession(currentTeam());
|
$session = getStripeCustomerPortalSession(currentTeam());
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ class InviteLink extends Component
|
|||||||
if (is_null($user)) {
|
if (is_null($user)) {
|
||||||
$password = Str::password();
|
$password = Str::password();
|
||||||
$user = User::create([
|
$user = User::create([
|
||||||
'name' => Str::of($this->email)->before('@'),
|
'name' => str($this->email)->before('@'),
|
||||||
'email' => $this->email,
|
'email' => $this->email,
|
||||||
'password' => Hash::make($password),
|
'password' => Hash::make($password),
|
||||||
'force_password_reset' => true,
|
'force_password_reset' => true,
|
||||||
|
|||||||
@@ -28,11 +28,11 @@ class Application extends BaseModel
|
|||||||
}
|
}
|
||||||
$application->forceFill([
|
$application->forceFill([
|
||||||
'fqdn' => $application->fqdn,
|
'fqdn' => $application->fqdn,
|
||||||
'install_command' => Str::of($application->install_command)->trim(),
|
'install_command' => str($application->install_command)->trim(),
|
||||||
'build_command' => Str::of($application->build_command)->trim(),
|
'build_command' => str($application->build_command)->trim(),
|
||||||
'start_command' => Str::of($application->start_command)->trim(),
|
'start_command' => str($application->start_command)->trim(),
|
||||||
'base_directory' => Str::of($application->base_directory)->trim(),
|
'base_directory' => str($application->base_directory)->trim(),
|
||||||
'publish_directory' => Str::of($application->publish_directory)->trim(),
|
'publish_directory' => str($application->publish_directory)->trim(),
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
static::created(function ($application) {
|
static::created(function ($application) {
|
||||||
@@ -902,9 +902,9 @@ class Application extends BaseModel
|
|||||||
$type = null;
|
$type = null;
|
||||||
$source = null;
|
$source = null;
|
||||||
if (is_string($volume)) {
|
if (is_string($volume)) {
|
||||||
$source = Str::of($volume)->before(':');
|
$source = str($volume)->before(':');
|
||||||
if ($source->startsWith('./') || $source->startsWith('/') || $source->startsWith('~')) {
|
if ($source->startsWith('./') || $source->startsWith('/') || $source->startsWith('~')) {
|
||||||
$type = Str::of('bind');
|
$type = str('bind');
|
||||||
}
|
}
|
||||||
} elseif (is_array($volume)) {
|
} elseif (is_array($volume)) {
|
||||||
$type = data_get_str($volume, 'type');
|
$type = data_get_str($volume, 'type');
|
||||||
|
|||||||
@@ -174,7 +174,7 @@ class EnvironmentVariable extends Model
|
|||||||
if (str($environment_variable)->startsWith('{{'.$type) && str($environment_variable)->endsWith('}}')) {
|
if (str($environment_variable)->startsWith('{{'.$type) && str($environment_variable)->endsWith('}}')) {
|
||||||
$variable = Str::after($environment_variable, "{$type}.");
|
$variable = Str::after($environment_variable, "{$type}.");
|
||||||
$variable = Str::before($variable, '}}');
|
$variable = Str::before($variable, '}}');
|
||||||
$variable = Str::of($variable)->trim()->value;
|
$variable = str($variable)->trim()->value;
|
||||||
if (! collect(SHARED_VARIABLE_TYPES)->contains($type)) {
|
if (! collect(SHARED_VARIABLE_TYPES)->contains($type)) {
|
||||||
return $variable;
|
return $variable;
|
||||||
}
|
}
|
||||||
@@ -220,7 +220,7 @@ class EnvironmentVariable extends Model
|
|||||||
protected function key(): Attribute
|
protected function key(): Attribute
|
||||||
{
|
{
|
||||||
return Attribute::make(
|
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\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Support\Str;
|
|
||||||
|
|
||||||
class LocalPersistentVolume extends Model
|
class LocalPersistentVolume extends Model
|
||||||
{
|
{
|
||||||
@@ -33,14 +32,14 @@ class LocalPersistentVolume extends Model
|
|||||||
protected function name(): Attribute
|
protected function name(): Attribute
|
||||||
{
|
{
|
||||||
return Attribute::make(
|
return Attribute::make(
|
||||||
set: fn (string $value) => Str::of($value)->trim()->value,
|
set: fn (string $value) => str($value)->trim()->value,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function mountPath(): Attribute
|
protected function mountPath(): Attribute
|
||||||
{
|
{
|
||||||
return Attribute::make(
|
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(
|
return Attribute::make(
|
||||||
set: function (?string $value) {
|
set: function (?string $value) {
|
||||||
if ($value) {
|
if ($value) {
|
||||||
return Str::of($value)->trim()->start('/')->value;
|
return str($value)->trim()->start('/')->value;
|
||||||
} else {
|
} else {
|
||||||
return $value;
|
return $value;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ use Illuminate\Support\Collection;
|
|||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Support\Facades\Process;
|
use Illuminate\Support\Facades\Process;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use Illuminate\Support\Stringable;
|
use Illuminate\Support\Stringable;
|
||||||
use Spatie\SchemalessAttributes\Casts\SchemalessAttributes;
|
use Spatie\SchemalessAttributes\Casts\SchemalessAttributes;
|
||||||
use Spatie\SchemalessAttributes\SchemalessAttributesTrait;
|
use Spatie\SchemalessAttributes\SchemalessAttributesTrait;
|
||||||
@@ -29,10 +28,10 @@ class Server extends BaseModel
|
|||||||
static::saving(function ($server) {
|
static::saving(function ($server) {
|
||||||
$payload = [];
|
$payload = [];
|
||||||
if ($server->user) {
|
if ($server->user) {
|
||||||
$payload['user'] = Str::of($server->user)->trim();
|
$payload['user'] = str($server->user)->trim();
|
||||||
}
|
}
|
||||||
if ($server->ip) {
|
if ($server->ip) {
|
||||||
$payload['ip'] = Str::of($server->ip)->trim();
|
$payload['ip'] = str($server->ip)->trim();
|
||||||
}
|
}
|
||||||
$server->forceFill($payload);
|
$server->forceFill($payload);
|
||||||
});
|
});
|
||||||
@@ -875,7 +874,7 @@ $schema://$host {
|
|||||||
$releaseLines = collect(explode("\n", $os_release));
|
$releaseLines = collect(explode("\n", $os_release));
|
||||||
$collectedData = collect([]);
|
$collectedData = collect([]);
|
||||||
foreach ($releaseLines as $line) {
|
foreach ($releaseLines as $line) {
|
||||||
$item = Str::of($line)->trim();
|
$item = str($line)->trim();
|
||||||
$collectedData->put($item->before('=')->value(), $item->after('=')->lower()->replace('"', '')->value());
|
$collectedData->put($item->before('=')->value(), $item->after('=')->lower()->replace('"', '')->value());
|
||||||
}
|
}
|
||||||
$ID = data_get($collectedData, 'ID');
|
$ID = data_get($collectedData, 'ID');
|
||||||
|
|||||||
@@ -839,29 +839,13 @@ class Service extends BaseModel
|
|||||||
$commands[] = "cd $workdir";
|
$commands[] = "cd $workdir";
|
||||||
|
|
||||||
$json = Yaml::parse($this->docker_compose);
|
$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);
|
$this->docker_compose = Yaml::dump($json, 10, 2, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK);
|
||||||
$docker_compose_base64 = base64_encode($this->docker_compose);
|
$docker_compose_base64 = base64_encode($this->docker_compose);
|
||||||
|
|
||||||
$commands[] = "echo $docker_compose_base64 | base64 -d | tee docker-compose.yml > /dev/null";
|
$commands[] = "echo $docker_compose_base64 | base64 -d | tee docker-compose.yml > /dev/null";
|
||||||
$commands[] = 'rm -f .env || true';
|
$commands[] = 'rm -f .env || true';
|
||||||
|
|
||||||
|
$envs_from_coolify = $this->environment_variables()->get();
|
||||||
foreach ($envs_from_coolify as $env) {
|
foreach ($envs_from_coolify as $env) {
|
||||||
$commands[] = "echo '{$env->key}={$env->real_value}' >> .env";
|
$commands[] = "echo '{$env->key}={$env->real_value}' >> .env";
|
||||||
}
|
}
|
||||||
@@ -880,7 +864,6 @@ class Service extends BaseModel
|
|||||||
{
|
{
|
||||||
$networks = getTopLevelNetworks($this);
|
$networks = getTopLevelNetworks($this);
|
||||||
|
|
||||||
// ray($networks);
|
|
||||||
return $networks;
|
return $networks;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,22 +15,7 @@ class Subscription extends Model
|
|||||||
|
|
||||||
public function type()
|
public function type()
|
||||||
{
|
{
|
||||||
if (isLemon()) {
|
if (isStripe()) {
|
||||||
$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 (! $this->stripe_plan_id) {
|
if (! $this->stripe_plan_id) {
|
||||||
return 'zero';
|
return 'zero';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ use Illuminate\Bus\Queueable;
|
|||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Notifications\Messages\MailMessage;
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
use Illuminate\Notifications\Notification;
|
use Illuminate\Notifications\Notification;
|
||||||
use Illuminate\Support\Str;
|
|
||||||
|
|
||||||
class DeploymentFailed extends Notification implements ShouldQueue
|
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->project_uuid = data_get($application, 'environment.project.uuid');
|
||||||
$this->environment_name = data_get($application, 'environment.name');
|
$this->environment_name = data_get($application, 'environment.name');
|
||||||
$this->fqdn = data_get($application, 'fqdn');
|
$this->fqdn = data_get($application, 'fqdn');
|
||||||
if (Str::of($this->fqdn)->explode(',')->count() > 1) {
|
if (str($this->fqdn)->explode(',')->count() > 1) {
|
||||||
$this->fqdn = Str::of($this->fqdn)->explode(',')->first();
|
$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}";
|
$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\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Notifications\Messages\MailMessage;
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
use Illuminate\Notifications\Notification;
|
use Illuminate\Notifications\Notification;
|
||||||
use Illuminate\Support\Str;
|
|
||||||
|
|
||||||
class DeploymentSuccess extends Notification implements ShouldQueue
|
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->project_uuid = data_get($application, 'environment.project.uuid');
|
||||||
$this->environment_name = data_get($application, 'environment.name');
|
$this->environment_name = data_get($application, 'environment.name');
|
||||||
$this->fqdn = data_get($application, 'fqdn');
|
$this->fqdn = data_get($application, 'fqdn');
|
||||||
if (Str::of($this->fqdn)->explode(',')->count() > 1) {
|
if (str($this->fqdn)->explode(',')->count() > 1) {
|
||||||
$this->fqdn = Str::of($this->fqdn)->explode(',')->first();
|
$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}";
|
$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\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Notifications\Messages\MailMessage;
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
use Illuminate\Notifications\Notification;
|
use Illuminate\Notifications\Notification;
|
||||||
use Illuminate\Support\Str;
|
|
||||||
|
|
||||||
class StatusChanged extends Notification implements ShouldQueue
|
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->project_uuid = data_get($resource, 'environment.project.uuid');
|
||||||
$this->environment_name = data_get($resource, 'environment.name');
|
$this->environment_name = data_get($resource, 'environment.name');
|
||||||
$this->fqdn = data_get($resource, 'fqdn', null);
|
$this->fqdn = data_get($resource, 'fqdn', null);
|
||||||
if (Str::of($this->fqdn)->explode(',')->count() > 1) {
|
if (str($this->fqdn)->explode(',')->count() > 1) {
|
||||||
$this->fqdn = Str::of($this->fqdn)->explode(',')->first();
|
$this->fqdn = str($this->fqdn)->explode(',')->first();
|
||||||
}
|
}
|
||||||
$this->resource_url = base_url()."/project/{$this->project_uuid}/".urlencode($this->environment_name)."/application/{$this->resource->uuid}";
|
$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 Carbon\Carbon;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Facades\Process;
|
use Illuminate\Support\Facades\Process;
|
||||||
use Illuminate\Support\Str;
|
|
||||||
|
|
||||||
trait ExecuteRemoteCommand
|
trait ExecuteRemoteCommand
|
||||||
{
|
{
|
||||||
@@ -45,7 +44,7 @@ trait ExecuteRemoteCommand
|
|||||||
}
|
}
|
||||||
$remote_command = generateSshCommand($this->server, $command);
|
$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) {
|
$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('╔')) {
|
if ($output->startsWith('╔')) {
|
||||||
$output = "\n".$output;
|
$output = "\n".$output;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ use App\Models\Service;
|
|||||||
use Closure;
|
use Closure;
|
||||||
use Illuminate\Contracts\View\View;
|
use Illuminate\Contracts\View\View;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use Illuminate\View\Component;
|
use Illuminate\View\Component;
|
||||||
|
|
||||||
class Links extends Component
|
class Links extends Component
|
||||||
@@ -26,16 +25,16 @@ class Links extends Component
|
|||||||
$this->links = $this->links->merge($links);
|
$this->links = $this->links->merge($links);
|
||||||
} else {
|
} else {
|
||||||
if ($application->fqdn) {
|
if ($application->fqdn) {
|
||||||
$fqdns = collect(Str::of($application->fqdn)->explode(','));
|
$fqdns = collect(str($application->fqdn)->explode(','));
|
||||||
$fqdns->map(function ($fqdn) {
|
$fqdns->map(function ($fqdn) {
|
||||||
$this->links->push(getFqdnWithoutPort($fqdn));
|
$this->links->push(getFqdnWithoutPort($fqdn));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if ($application->ports) {
|
if ($application->ports) {
|
||||||
$portsCollection = collect(Str::of($application->ports)->explode(','));
|
$portsCollection = collect(str($application->ports)->explode(','));
|
||||||
$portsCollection->map(function ($port) {
|
$portsCollection->map(function ($port) {
|
||||||
if (Str::of($port)->contains(':')) {
|
if (str($port)->contains(':')) {
|
||||||
$hostPort = Str::of($port)->before(':');
|
$hostPort = str($port)->before(':');
|
||||||
} else {
|
} else {
|
||||||
$hostPort = $port;
|
$hostPort = $port;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ function format_docker_envs_to_json($rawOutput)
|
|||||||
}
|
}
|
||||||
function checkMinimumDockerEngineVersion($dockerVersion)
|
function checkMinimumDockerEngineVersion($dockerVersion)
|
||||||
{
|
{
|
||||||
$majorDockerVersion = Str::of($dockerVersion)->before('.')->value();
|
$majorDockerVersion = str($dockerVersion)->before('.')->value();
|
||||||
if ($majorDockerVersion <= 22) {
|
if ($majorDockerVersion <= 22) {
|
||||||
$dockerVersion = null;
|
$dockerVersion = null;
|
||||||
}
|
}
|
||||||
@@ -152,7 +152,7 @@ function get_port_from_dockerfile($dockerfile): ?int
|
|||||||
$dockerfile_array = explode("\n", $dockerfile);
|
$dockerfile_array = explode("\n", $dockerfile);
|
||||||
$found_exposed_port = null;
|
$found_exposed_port = null;
|
||||||
foreach ($dockerfile_array as $line) {
|
foreach ($dockerfile_array as $line) {
|
||||||
$line_str = Str::of($line)->trim();
|
$line_str = str($line)->trim();
|
||||||
if ($line_str->startsWith('EXPOSE')) {
|
if ($line_str->startsWith('EXPOSE')) {
|
||||||
$found_exposed_port = $line_str->replace('EXPOSE', '')->trim();
|
$found_exposed_port = $line_str->replace('EXPOSE', '')->trim();
|
||||||
break;
|
break;
|
||||||
@@ -534,7 +534,7 @@ function generateLabelsApplication(Application $application, ?ApplicationPreview
|
|||||||
$labels = collect([]);
|
$labels = collect([]);
|
||||||
if ($pull_request_id === 0) {
|
if ($pull_request_id === 0) {
|
||||||
if ($application->fqdn) {
|
if ($application->fqdn) {
|
||||||
$domains = Str::of(data_get($application, 'fqdn'))->explode(',');
|
$domains = str(data_get($application, 'fqdn'))->explode(',');
|
||||||
$labels = $labels->merge(fqdnLabelsForTraefik(
|
$labels = $labels->merge(fqdnLabelsForTraefik(
|
||||||
uuid: $appUuid,
|
uuid: $appUuid,
|
||||||
domains: $domains,
|
domains: $domains,
|
||||||
@@ -558,7 +558,7 @@ function generateLabelsApplication(Application $application, ?ApplicationPreview
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (data_get($preview, 'fqdn')) {
|
if (data_get($preview, 'fqdn')) {
|
||||||
$domains = Str::of(data_get($preview, 'fqdn'))->explode(',');
|
$domains = str(data_get($preview, 'fqdn'))->explode(',');
|
||||||
} else {
|
} else {
|
||||||
$domains = collect([]);
|
$domains = collect([]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ function githubApi(GithubApp|GitlabApp|null $source, string $endpoint, string $m
|
|||||||
function get_installation_path(GithubApp $source)
|
function get_installation_path(GithubApp $source)
|
||||||
{
|
{
|
||||||
$github = GithubApp::where('uuid', $source->uuid)->first();
|
$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';
|
$installation_path = $github->html_url === 'https://github.com' ? 'apps' : 'github-apps';
|
||||||
|
|
||||||
return "$github->html_url/$installation_path/$name/installations/new";
|
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)
|
function get_permissions_path(GithubApp $source)
|
||||||
{
|
{
|
||||||
$github = GithubApp::where('uuid', $source->uuid)->first();
|
$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";
|
return "$github->html_url/settings/apps/$name/permissions";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ use App\Models\Application;
|
|||||||
use App\Models\EnvironmentVariable;
|
use App\Models\EnvironmentVariable;
|
||||||
use App\Models\ServiceApplication;
|
use App\Models\ServiceApplication;
|
||||||
use App\Models\ServiceDatabase;
|
use App\Models\ServiceDatabase;
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use Spatie\Url\Url;
|
use Spatie\Url\Url;
|
||||||
use Symfony\Component\Yaml\Yaml;
|
use Symfony\Component\Yaml\Yaml;
|
||||||
|
|
||||||
@@ -38,7 +37,7 @@ function getFilesystemVolumesFromServer(ServiceApplication|ServiceDatabase|Appli
|
|||||||
]);
|
]);
|
||||||
instant_remote_process($commands, $server);
|
instant_remote_process($commands, $server);
|
||||||
foreach ($fileVolumes as $fileVolume) {
|
foreach ($fileVolumes as $fileVolume) {
|
||||||
$path = Str::of(data_get($fileVolume, 'fs_path'));
|
$path = str(data_get($fileVolume, 'fs_path'));
|
||||||
$content = data_get($fileVolume, 'content');
|
$content = data_get($fileVolume, 'content');
|
||||||
if ($path->startsWith('.')) {
|
if ($path->startsWith('.')) {
|
||||||
$path = $path->after('.');
|
$path = $path->after('.');
|
||||||
@@ -68,7 +67,7 @@ function getFilesystemVolumesFromServer(ServiceApplication|ServiceDatabase|Appli
|
|||||||
$fileVolume->is_directory = false;
|
$fileVolume->is_directory = false;
|
||||||
$fileVolume->save();
|
$fileVolume->save();
|
||||||
$content = base64_encode($content);
|
$content = base64_encode($content);
|
||||||
$dir = Str::of($fileLocation)->dirname();
|
$dir = str($fileLocation)->dirname();
|
||||||
instant_remote_process([
|
instant_remote_process([
|
||||||
"mkdir -p $dir",
|
"mkdir -p $dir",
|
||||||
"echo '$content' | base64 -d | tee $fileLocation",
|
"echo '$content' | base64 -d | tee $fileLocation",
|
||||||
@@ -106,7 +105,7 @@ function updateCompose(ServiceApplication|ServiceDatabase $resource)
|
|||||||
$resourceFqdns = str($resource->fqdn)->explode(',');
|
$resourceFqdns = str($resource->fqdn)->explode(',');
|
||||||
if ($resourceFqdns->count() === 1) {
|
if ($resourceFqdns->count() === 1) {
|
||||||
$resourceFqdns = $resourceFqdns->first();
|
$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();
|
$generatedEnv = EnvironmentVariable::where('service_id', $resource->service_id)->where('key', $variableName)->first();
|
||||||
$fqdn = Url::fromString($resourceFqdns);
|
$fqdn = Url::fromString($resourceFqdns);
|
||||||
$port = $fqdn->getPort();
|
$port = $fqdn->getPort();
|
||||||
@@ -125,14 +124,14 @@ function updateCompose(ServiceApplication|ServiceDatabase $resource)
|
|||||||
$generatedEnv->save();
|
$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();
|
$generatedEnv = EnvironmentVariable::where('service_id', $resource->service_id)->where('key', $variableName)->first();
|
||||||
$url = Url::fromString($fqdn);
|
$url = Url::fromString($fqdn);
|
||||||
$port = $url->getPort();
|
$port = $url->getPort();
|
||||||
$path = $url->getPath();
|
$path = $url->getPath();
|
||||||
$url = $url->getHost();
|
$url = $url->getHost();
|
||||||
if ($generatedEnv) {
|
if ($generatedEnv) {
|
||||||
$url = Str::of($fqdn)->after('://');
|
$url = str($fqdn)->after('://');
|
||||||
$generatedEnv->value = $url.$path;
|
$generatedEnv->value = $url.$path;
|
||||||
$generatedEnv->save();
|
$generatedEnv->save();
|
||||||
}
|
}
|
||||||
@@ -175,7 +174,7 @@ function updateCompose(ServiceApplication|ServiceDatabase $resource)
|
|||||||
$port_env_url->save();
|
$port_env_url->save();
|
||||||
}
|
}
|
||||||
} else {
|
} 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();
|
$generatedEnv = EnvironmentVariable::where('service_id', $resource->service_id)->where('key', $variableName)->first();
|
||||||
$fqdn = Url::fromString($fqdn);
|
$fqdn = Url::fromString($fqdn);
|
||||||
$fqdn = $fqdn->getScheme().'://'.$fqdn->getHost().$fqdn->getPath();
|
$fqdn = $fqdn->getScheme().'://'.$fqdn->getHost().$fqdn->getPath();
|
||||||
@@ -183,12 +182,12 @@ function updateCompose(ServiceApplication|ServiceDatabase $resource)
|
|||||||
$generatedEnv->value = $fqdn;
|
$generatedEnv->value = $fqdn;
|
||||||
$generatedEnv->save();
|
$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();
|
$generatedEnv = EnvironmentVariable::where('service_id', $resource->service_id)->where('key', $variableName)->first();
|
||||||
$url = Url::fromString($fqdn);
|
$url = Url::fromString($fqdn);
|
||||||
$url = $url->getHost().$url->getPath();
|
$url = $url->getHost().$url->getPath();
|
||||||
if ($generatedEnv) {
|
if ($generatedEnv) {
|
||||||
$url = Str::of($fqdn)->after('://');
|
$url = str($fqdn)->after('://');
|
||||||
$generatedEnv->value = $url;
|
$generatedEnv->value = $url;
|
||||||
$generatedEnv->save();
|
$generatedEnv->save();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -469,7 +469,7 @@ function data_get_str($data, $key, $default = null): Stringable
|
|||||||
{
|
{
|
||||||
$str = data_get($data, $key, $default) ?? $default;
|
$str = data_get($data, $key, $default) ?? $default;
|
||||||
|
|
||||||
return Str::of($str);
|
return str($str);
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateFqdn(Server $server, string $random)
|
function generateFqdn(Server $server, string $random)
|
||||||
@@ -933,12 +933,12 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
$content = null;
|
$content = null;
|
||||||
$isDirectory = false;
|
$isDirectory = false;
|
||||||
if (is_string($volume)) {
|
if (is_string($volume)) {
|
||||||
$source = Str::of($volume)->before(':');
|
$source = str($volume)->before(':');
|
||||||
$target = Str::of($volume)->after(':')->beforeLast(':');
|
$target = str($volume)->after(':')->beforeLast(':');
|
||||||
if ($source->startsWith('./') || $source->startsWith('/') || $source->startsWith('~')) {
|
if ($source->startsWith('./') || $source->startsWith('/') || $source->startsWith('~')) {
|
||||||
$type = Str::of('bind');
|
$type = str('bind');
|
||||||
} else {
|
} else {
|
||||||
$type = Str::of('volume');
|
$type = str('volume');
|
||||||
}
|
}
|
||||||
} elseif (is_array($volume)) {
|
} elseif (is_array($volume)) {
|
||||||
$type = data_get_str($volume, 'type');
|
$type = data_get_str($volume, 'type');
|
||||||
@@ -987,8 +987,8 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
$slugWithoutUuid = Str::slug($source, '-');
|
$slugWithoutUuid = Str::slug($source, '-');
|
||||||
$name = "{$savedService->service->uuid}_{$slugWithoutUuid}";
|
$name = "{$savedService->service->uuid}_{$slugWithoutUuid}";
|
||||||
if (is_string($volume)) {
|
if (is_string($volume)) {
|
||||||
$source = Str::of($volume)->before(':');
|
$source = str($volume)->before(':');
|
||||||
$target = Str::of($volume)->after(':')->beforeLast(':');
|
$target = str($volume)->after(':')->beforeLast(':');
|
||||||
$source = $name;
|
$source = $name;
|
||||||
$volume = "$source:$target";
|
$volume = "$source:$target";
|
||||||
} elseif (is_array($volume)) {
|
} elseif (is_array($volume)) {
|
||||||
@@ -1032,7 +1032,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
// Get variables from the service
|
// Get variables from the service
|
||||||
foreach ($serviceVariables as $variableName => $variable) {
|
foreach ($serviceVariables as $variableName => $variable) {
|
||||||
if (is_numeric($variableName)) {
|
if (is_numeric($variableName)) {
|
||||||
$variable = Str::of($variable);
|
$variable = str($variable);
|
||||||
if ($variable->contains('=')) {
|
if ($variable->contains('=')) {
|
||||||
// - SESSION_SECRET=123
|
// - SESSION_SECRET=123
|
||||||
// - SESSION_SECRET=
|
// - SESSION_SECRET=
|
||||||
@@ -1046,8 +1046,8 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
} else {
|
} else {
|
||||||
// SESSION_SECRET: 123
|
// SESSION_SECRET: 123
|
||||||
// SESSION_SECRET:
|
// SESSION_SECRET:
|
||||||
$key = Str::of($variableName);
|
$key = str($variableName);
|
||||||
$value = Str::of($variable);
|
$value = str($variable);
|
||||||
}
|
}
|
||||||
if ($key->startsWith('SERVICE_FQDN')) {
|
if ($key->startsWith('SERVICE_FQDN')) {
|
||||||
if ($isNew || $savedService->fqdn === null) {
|
if ($isNew || $savedService->fqdn === null) {
|
||||||
@@ -1137,7 +1137,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
'key' => $key,
|
'key' => $key,
|
||||||
'service_id' => $resource->id,
|
'service_id' => $resource->id,
|
||||||
])->first();
|
])->first();
|
||||||
$value = Str::of(replaceVariables($value));
|
$value = str(replaceVariables($value));
|
||||||
$key = $value;
|
$key = $value;
|
||||||
if ($value->startsWith('SERVICE_')) {
|
if ($value->startsWith('SERVICE_')) {
|
||||||
$foundEnv = EnvironmentVariable::where([
|
$foundEnv = EnvironmentVariable::where([
|
||||||
@@ -1170,7 +1170,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
// }
|
// }
|
||||||
} else {
|
} else {
|
||||||
if ($command->value() === 'URL') {
|
if ($command->value() === 'URL') {
|
||||||
$fqdn = Str::of($fqdn)->after('://')->value();
|
$fqdn = str($fqdn)->after('://')->value();
|
||||||
}
|
}
|
||||||
EnvironmentVariable::create([
|
EnvironmentVariable::create([
|
||||||
'key' => $key,
|
'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
|
// Add labels to the service
|
||||||
if ($savedService->serviceType()) {
|
if ($savedService->serviceType()) {
|
||||||
@@ -1333,6 +1321,41 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
data_set($service, 'environment', $serviceVariables->toArray());
|
data_set($service, 'environment', $serviceVariables->toArray());
|
||||||
updateCompose($savedService);
|
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;
|
return $service;
|
||||||
});
|
});
|
||||||
$finalServices = [
|
$finalServices = [
|
||||||
@@ -1637,7 +1660,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
// Get variables from the service
|
// Get variables from the service
|
||||||
foreach ($serviceVariables as $variableName => $variable) {
|
foreach ($serviceVariables as $variableName => $variable) {
|
||||||
if (is_numeric($variableName)) {
|
if (is_numeric($variableName)) {
|
||||||
$variable = Str::of($variable);
|
$variable = str($variable);
|
||||||
if ($variable->contains('=')) {
|
if ($variable->contains('=')) {
|
||||||
// - SESSION_SECRET=123
|
// - SESSION_SECRET=123
|
||||||
// - SESSION_SECRET=
|
// - SESSION_SECRET=
|
||||||
@@ -1651,8 +1674,8 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
} else {
|
} else {
|
||||||
// SESSION_SECRET: 123
|
// SESSION_SECRET: 123
|
||||||
// SESSION_SECRET:
|
// SESSION_SECRET:
|
||||||
$key = Str::of($variableName);
|
$key = str($variableName);
|
||||||
$value = Str::of($variable);
|
$value = str($variable);
|
||||||
}
|
}
|
||||||
if ($key->startsWith('SERVICE_FQDN')) {
|
if ($key->startsWith('SERVICE_FQDN')) {
|
||||||
if ($isNew) {
|
if ($isNew) {
|
||||||
@@ -1696,7 +1719,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
'application_id' => $resource->id,
|
'application_id' => $resource->id,
|
||||||
'is_preview' => false,
|
'is_preview' => false,
|
||||||
])->first();
|
])->first();
|
||||||
$value = Str::of(replaceVariables($value));
|
$value = str(replaceVariables($value));
|
||||||
$key = $value;
|
$key = $value;
|
||||||
if ($value->startsWith('SERVICE_')) {
|
if ($value->startsWith('SERVICE_')) {
|
||||||
$foundEnv = EnvironmentVariable::where([
|
$foundEnv = EnvironmentVariable::where([
|
||||||
@@ -1718,7 +1741,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
$fqdn = data_get($foundEnv, 'value');
|
$fqdn = data_get($foundEnv, 'value');
|
||||||
} else {
|
} else {
|
||||||
if ($command?->value() === 'URL') {
|
if ($command?->value() === 'URL') {
|
||||||
$fqdn = Str::of($fqdn)->after('://')->value();
|
$fqdn = str($fqdn)->after('://')->value();
|
||||||
}
|
}
|
||||||
EnvironmentVariable::create([
|
EnvironmentVariable::create([
|
||||||
'key' => $key,
|
'key' => $key,
|
||||||
|
|||||||
@@ -1,51 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use App\Models\Team;
|
use App\Models\Team;
|
||||||
use Illuminate\Support\Carbon;
|
|
||||||
use Stripe\Stripe;
|
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()
|
function isSubscriptionActive()
|
||||||
{
|
{
|
||||||
if (! isCloud()) {
|
if (! isCloud()) {
|
||||||
@@ -60,12 +17,6 @@ function isSubscriptionActive()
|
|||||||
if (is_null($subscription)) {
|
if (is_null($subscription)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (isLemon()) {
|
|
||||||
return $subscription->lemon_status === 'active';
|
|
||||||
}
|
|
||||||
// if (isPaddle()) {
|
|
||||||
// return $subscription->paddle_status === 'active';
|
|
||||||
// }
|
|
||||||
if (isStripe()) {
|
if (isStripe()) {
|
||||||
return $subscription->stripe_invoice_paid === true;
|
return $subscription->stripe_invoice_paid === true;
|
||||||
}
|
}
|
||||||
@@ -82,12 +33,6 @@ function isSubscriptionOnGracePeriod()
|
|||||||
if (! $subscription) {
|
if (! $subscription) {
|
||||||
return false;
|
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()) {
|
if (isStripe()) {
|
||||||
return $subscription->stripe_cancel_at_period_end;
|
return $subscription->stripe_cancel_at_period_end;
|
||||||
}
|
}
|
||||||
@@ -98,18 +43,10 @@ function subscriptionProvider()
|
|||||||
{
|
{
|
||||||
return config('subscription.provider');
|
return config('subscription.provider');
|
||||||
}
|
}
|
||||||
function isLemon()
|
|
||||||
{
|
|
||||||
return config('subscription.provider') === 'lemon';
|
|
||||||
}
|
|
||||||
function isStripe()
|
function isStripe()
|
||||||
{
|
{
|
||||||
return config('subscription.provider') === 'stripe';
|
return config('subscription.provider') === 'stripe';
|
||||||
}
|
}
|
||||||
function isPaddle()
|
|
||||||
{
|
|
||||||
return config('subscription.provider') === 'paddle';
|
|
||||||
}
|
|
||||||
function getStripeCustomerPortalSession(Team $team)
|
function getStripeCustomerPortalSession(Team $team)
|
||||||
{
|
{
|
||||||
Stripe::setApiKey(config('subscription.stripe_api_key'));
|
Stripe::setApiKey(config('subscription.stripe_api_key'));
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
"league/flysystem-aws-s3-v3": "^3.0",
|
"league/flysystem-aws-s3-v3": "^3.0",
|
||||||
"league/flysystem-sftp-v3": "^3.0",
|
"league/flysystem-sftp-v3": "^3.0",
|
||||||
"livewire/livewire": "3.4.9",
|
"livewire/livewire": "3.4.9",
|
||||||
|
"log1x/laravel-webfonts": "^1.0",
|
||||||
"lorisleiva/laravel-actions": "^2.7",
|
"lorisleiva/laravel-actions": "^2.7",
|
||||||
"nubs/random-name-generator": "^2.2",
|
"nubs/random-name-generator": "^2.2",
|
||||||
"phpseclib/phpseclib": "~3.0",
|
"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",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "dbce9f366320f4d58392673fe25c69f6",
|
"content-hash": "168e351cec87acbea9c1c745b83eead2",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "amphp/amp",
|
"name": "amphp/amp",
|
||||||
@@ -4522,6 +4522,68 @@
|
|||||||
],
|
],
|
||||||
"time": "2024-03-14T14:03:32+00:00"
|
"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",
|
"name": "lorisleiva/laravel-actions",
|
||||||
"version": "v2.8.0",
|
"version": "v2.8.0",
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ return [
|
|||||||
|
|
||||||
// The release version of your application
|
// The release version of your application
|
||||||
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
|
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
|
||||||
'release' => '4.0.0-beta.301',
|
'release' => '4.0.0-beta.306',
|
||||||
// When left empty or `null` the Laravel environment will be used
|
// When left empty or `null` the Laravel environment will be used
|
||||||
'environment' => config('app.env'),
|
'environment' => config('app.env'),
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'provider' => env('SUBSCRIPTION_PROVIDER', null), // stripe, paddle, lemon
|
'provider' => env('SUBSCRIPTION_PROVIDER', null), // stripe
|
||||||
|
|
||||||
// Stripe
|
// Stripe
|
||||||
'stripe_api_key' => env('STRIPE_API_KEY', null),
|
'stripe_api_key' => env('STRIPE_API_KEY', null),
|
||||||
'stripe_webhook_secret' => env('STRIPE_WEBHOOK_SECRET', 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_monthly' => env('STRIPE_PRICE_ID_DYNAMIC_MONTHLY', null),
|
||||||
'stripe_price_id_dynamic_yearly' => env('STRIPE_PRICE_ID_DYNAMIC_YEARLY', 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
|
<?php
|
||||||
|
|
||||||
return '4.0.0-beta.301';
|
return '4.0.0-beta.306';
|
||||||
|
|||||||
@@ -69,27 +69,6 @@ services:
|
|||||||
- STRIPE_PRICE_ID_ULTIMATE_MONTHLY_OLD
|
- STRIPE_PRICE_ID_ULTIMATE_MONTHLY_OLD
|
||||||
- STRIPE_PRICE_ID_ULTIMATE_YEARLY_OLD
|
- STRIPE_PRICE_ID_ULTIMATE_YEARLY_OLD
|
||||||
- STRIPE_EXCLUDED_PLANS
|
- 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:
|
ports:
|
||||||
- "${APP_PORT:-8000}:80"
|
- "${APP_PORT:-8000}:80"
|
||||||
expose:
|
expose:
|
||||||
|
|||||||
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 base;
|
||||||
@tailwind components;
|
@tailwind components;
|
||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
html,
|
html,
|
||||||
body {
|
body {
|
||||||
@apply h-full bg-neutral-50 text-neutral-800 dark:bg-base dark:text-neutral-400;
|
@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.
@@ -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>
|
||||||
</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
|
<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"
|
<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>
|
href="https://github.com/coollabsio/coolify">Get Started</a></x-forms.button>
|
||||||
</h2>
|
</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
|
our
|
||||||
OSS version. Same features as the paid version, but you have to manage by yourself.</p>
|
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="flow-root mt-12">
|
||||||
<div class="pb-10 text-xl text-center">For the detailed list of features, please visit our landing page: <a
|
<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>
|
</p>
|
||||||
<ul role="list" class="space-y-3 text-sm leading-6 ">
|
<ul role="list" class="space-y-3 text-sm leading-6 ">
|
||||||
<li class="flex">
|
<li class="flex">
|
||||||
<svg class="flex-none w-5 h-6 mr-3 dark:text-warning" viewBox="0 0 20 20" fill="currentColor"
|
<svg class="flex-none w-5 h-6 mr-3 dark:text-warning" viewBox="0 0 20 20"
|
||||||
aria-hidden="true">
|
fill="currentColor" aria-hidden="true">
|
||||||
<path fill-rule="evenodd"
|
<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"
|
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" />
|
clip-rule="evenodd" />
|
||||||
@@ -141,13 +142,14 @@
|
|||||||
{{ $pro }}
|
{{ $pro }}
|
||||||
@endisset
|
@endisset
|
||||||
@endif
|
@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.
|
environment.
|
||||||
</p>
|
</p>
|
||||||
<ul role="list" class="mt-6 space-y-3 text-sm leading-6 ">
|
<ul role="list" class="mt-6 space-y-3 text-sm leading-6 ">
|
||||||
<li class="flex ">
|
<li class="flex ">
|
||||||
<svg class="flex-none w-5 h-6 mr-3 dark:text-warning" viewBox="0 0 20 20" fill="currentColor"
|
<svg class="flex-none w-5 h-6 mr-3 dark:text-warning" viewBox="0 0 20 20"
|
||||||
aria-hidden="true">
|
fill="currentColor" aria-hidden="true">
|
||||||
<path fill-rule="evenodd"
|
<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"
|
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" />
|
clip-rule="evenodd" />
|
||||||
@@ -188,7 +190,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="pt-16 lg:px-8 lg:pt-0 xl:px-12">
|
<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>
|
<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 x-show="selected === 'monthly'" x-cloak>
|
||||||
<span class="text-4xl font-bold tracking-tight dark:text-white">Custom</span>
|
<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> --}}
|
{{-- <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 class="text-sm font-semibold leading-6 ">/month + VAT</span> --}}
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
<span x-show="selected === 'monthly'" x-cloak>
|
<span x-show="selected === 'monthly'" x-cloak>
|
||||||
<span>pay-as-you-go</span>
|
<span>pay-as-you-go</span>
|
||||||
</span>
|
</span>
|
||||||
<span x-show="selected === 'yearly'" x-cloak>
|
<span x-show="selected === 'yearly'" x-cloak>
|
||||||
@@ -213,8 +215,8 @@
|
|||||||
single location.</p>
|
single location.</p>
|
||||||
<ul role="list" class="mt-6 space-y-3 text-sm leading-6 ">
|
<ul role="list" class="mt-6 space-y-3 text-sm leading-6 ">
|
||||||
<li class="flex ">
|
<li class="flex ">
|
||||||
<svg class="flex-none w-5 h-6 mr-3 dark:text-warning" viewBox="0 0 20 20" fill="currentColor"
|
<svg class="flex-none w-5 h-6 mr-3 dark:text-warning" viewBox="0 0 20 20"
|
||||||
aria-hidden="true">
|
fill="currentColor" aria-hidden="true">
|
||||||
<path fill-rule="evenodd"
|
<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"
|
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" />
|
clip-rule="evenodd" />
|
||||||
|
|||||||
@@ -46,13 +46,6 @@
|
|||||||
stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
|
stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</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>
|
</div>
|
||||||
|
|
||||||
<main class="lg:pl-48">
|
<main class="lg:pl-48">
|
||||||
|
|||||||
@@ -4,32 +4,22 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<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">
|
<meta name="robots" content="noindex">
|
||||||
@use('App\Models\InstanceSettings')
|
@use('App\Models\InstanceSettings')
|
||||||
@php
|
@php
|
||||||
|
|
||||||
$instanceSettings = InstanceSettings::first();
|
$instanceSettings = InstanceSettings::first();
|
||||||
$name = null;
|
$name = null;
|
||||||
|
|
||||||
if($instanceSettings) {
|
if ($instanceSettings) {
|
||||||
$displayName = $instanceSettings->getTitleDisplayName();
|
$displayName = $instanceSettings->getTitleDisplayName();
|
||||||
|
|
||||||
if(strlen($displayName) > 0) {
|
if (strlen($displayName) > 0) {
|
||||||
$name = $displayName . ' ';
|
$name = $displayName . ' ';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
@endphp
|
@endphp
|
||||||
<title>{{ $name }}{{ $title ?? 'Coolify' }}</title>
|
<title>{{ $name }}{{ $title ?? 'Coolify' }}</title>
|
||||||
@env('local')
|
@env('local')
|
||||||
<link rel="icon" href="{{ asset('favicon-dev.png') }}" type="image/x-icon" />
|
<link rel="icon" href="{{ asset('favicon-dev.png') }}" type="image/x-icon" />
|
||||||
@else
|
@else
|
||||||
@@ -46,13 +36,9 @@
|
|||||||
<script defer data-domain="app.coolify.io" src="https://analytics.coollabs.io/js/plausible.js"></script>
|
<script defer data-domain="app.coolify.io" src="https://analytics.coollabs.io/js/plausible.js"></script>
|
||||||
@endif
|
@endif
|
||||||
@auth
|
@auth
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/laravel-echo/1.15.3/echo.iife.min.js"
|
<script type="text/javascript" src="{{ URL::asset('js/echo.js') }}"></script>
|
||||||
integrity="sha512-aPAh2oRUr3ALz2MwVWkd6lmdgBQC0wSr0R++zclNjXZreT/JrwDPZQwA/p6R3wOCTcXKIHgA9pQGEQBWQmdLaA=="
|
<script type="text/javascript" src="{{ URL::asset('js/pusher.js') }}"></script>
|
||||||
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
<script type="text/javascript" src="{{ URL::asset('js/apexcharts.js') }}"></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>
|
|
||||||
@endauth
|
@endauth
|
||||||
</head>
|
</head>
|
||||||
@section('body')
|
@section('body')
|
||||||
|
|||||||
@@ -68,9 +68,9 @@
|
|||||||
@foreach (data_get($application, 'previews') as $previewName => $preview)
|
@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 flex-col w-full p-4 border dark:border-coolgray-200">
|
||||||
<div class="flex gap-2">PR #{{ data_get($preview, 'pull_request_id') }} |
|
<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')" />
|
<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')" />
|
<x-status.restarting :status="data_get($preview, 'status')" />
|
||||||
@else
|
@else
|
||||||
<x-status.stopped :status="data_get($preview, 'status')" />
|
<x-status.stopped :status="data_get($preview, 'status')" />
|
||||||
|
|||||||
@@ -27,7 +27,8 @@
|
|||||||
|
|
||||||
<div class="flex flex-col gap-2">
|
<div class="flex flex-col gap-2">
|
||||||
<div class="flex 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" />
|
<x-forms.input placeholder="main" id="application.git_branch" label="Branch" />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-end gap-2">
|
<div class="flex items-end gap-2">
|
||||||
@@ -35,14 +36,14 @@
|
|||||||
label="Commit SHA" />
|
label="Commit SHA" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@if(data_get($application, 'private_key_id'))
|
@if (data_get($application, 'private_key_id'))
|
||||||
<h3 class="pt-4">Deploy Key</h3>
|
<h3 class="pt-4">Deploy Key</h3>
|
||||||
<div class="py-2 pt-4">Currently attached Private Key: <span
|
<div class="py-2 pt-4">Currently attached Private Key: <span
|
||||||
class="dark:text-warning">{{ data_get($application, 'private_key.name') }}</span>
|
class="dark:text-warning">{{ data_get($application, 'private_key.name') }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h4 class="py-2 ">Select another Private Key</h4>
|
<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)
|
@foreach ($private_keys as $key)
|
||||||
<x-forms.button wire:click.defer="setPrivateKey('{{ $key->id }}')">{{ $key->name }}
|
<x-forms.button wire:click.defer="setPrivateKey('{{ $key->id }}')">{{ $key->name }}
|
||||||
</x-forms.button>
|
</x-forms.button>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<x-forms.button type="submit">
|
<x-forms.button type="submit">
|
||||||
Save
|
Save
|
||||||
</x-forms.button>
|
</x-forms.button>
|
||||||
@if (Str::of($status)->startsWith('running'))
|
@if (str($status)->startsWith('running'))
|
||||||
<livewire:project.database.backup-now :backup="$backup" />
|
<livewire:project.database.backup-now :backup="$backup" />
|
||||||
@endif
|
@endif
|
||||||
@if ($backup->database_id !== 0)
|
@if ($backup->database_id !== 0)
|
||||||
|
|||||||
@@ -54,11 +54,11 @@
|
|||||||
<div class="grid grid-cols-1 gap-2 pt-4 xl:grid-cols-1">
|
<div class="grid grid-cols-1 gap-2 pt-4 xl:grid-cols-1">
|
||||||
@foreach ($applications as $application)
|
@foreach ($applications as $application)
|
||||||
<div @class([
|
<div @class([
|
||||||
'border-l border-dashed border-red-500 ' => Str::of(
|
'border-l border-dashed border-red-500 ' => str(
|
||||||
$application->status)->contains(['exited']),
|
$application->status)->contains(['exited']),
|
||||||
'border-l border-dashed border-success' => Str::of(
|
'border-l border-dashed border-success' => str(
|
||||||
$application->status)->contains(['running']),
|
$application->status)->contains(['running']),
|
||||||
'border-l border-dashed border-warning' => Str::of(
|
'border-l border-dashed border-warning' => str(
|
||||||
$application->status)->contains(['starting']),
|
$application->status)->contains(['starting']),
|
||||||
'flex gap-2 box-without-bg-without-border dark:bg-coolgray-100 bg-white dark:hover:text-neutral-300 group',
|
'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
|
@endforeach
|
||||||
@foreach ($databases as $database)
|
@foreach ($databases as $database)
|
||||||
<div @class([
|
<div @class([
|
||||||
'border-l border-dashed border-red-500' => Str::of(
|
'border-l border-dashed border-red-500' => str($database->status)->contains(
|
||||||
$database->status)->contains(['exited']),
|
['exited']),
|
||||||
'border-l border-dashed border-success' => Str::of(
|
'border-l border-dashed border-success' => str($database->status)->contains(
|
||||||
$database->status)->contains(['running']),
|
['running']),
|
||||||
'border-l border-dashed border-warning' => Str::of(
|
'border-l border-dashed border-warning' => str($database->status)->contains(
|
||||||
$database->status)->contains(['restarting']),
|
['restarting']),
|
||||||
'flex gap-2 box-without-bg-without-border dark:bg-coolgray-100 bg-white dark:hover:text-neutral-300 group',
|
'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">
|
<div class="flex flex-row w-full">
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
<h2>Service Stack</h2>
|
<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">
|
<x-modal-input buttonTitle="Edit Compose File" title="Edit Docker Compose" :closeOutside="false">
|
||||||
<livewire:project.service.edit-compose serviceId="{{ $service->id }}" />
|
<livewire:project.service.edit-compose serviceId="{{ $service->id }}" />
|
||||||
</x-modal-input>
|
</x-modal-input>
|
||||||
|
|||||||
@@ -2,12 +2,11 @@
|
|||||||
@if (subscriptionProvider() === 'stripe')
|
@if (subscriptionProvider() === 'stripe')
|
||||||
<div class="pt-4">
|
<div class="pt-4">
|
||||||
<h2>Your current plan</h2>
|
<h2>Your current plan</h2>
|
||||||
<div class="pb-4">Tier: <strong
|
<div class="pb-4">Tier: <strong class="dark:text-warning">
|
||||||
class="dark:text-warning">
|
|
||||||
@if (data_get(currentTeam(), 'subscription')->type() == 'dynamic')
|
@if (data_get(currentTeam(), 'subscription')->type() == 'dynamic')
|
||||||
Pay-as-you-go
|
Pay-as-you-go
|
||||||
@else
|
@else
|
||||||
{{ data_get(currentTeam(), 'subscription')->type() }}
|
{{ data_get(currentTeam(), 'subscription')->type() }}
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
</strong></div>
|
</strong></div>
|
||||||
@@ -50,35 +49,4 @@
|
|||||||
target="_blank">contact us.</a>
|
target="_blank">contact us.</a>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@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>
|
</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>
|
<div>This is the default team. You can't delete it.</div>
|
||||||
@elseif(auth()->user()->teams()->get()->count() === 1 || auth()->user()->currentTeam()->personal_team)
|
@elseif(auth()->user()->teams()->get()->count() === 1 || auth()->user()->currentTeam()->personal_team)
|
||||||
<div>You can't delete your last / personal team.</div>
|
<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"
|
<div>Please cancel your subscription <a class="underline dark:text-white"
|
||||||
href="{{ route('subscription.show') }}">here</a> before delete this team.</div>
|
href="{{ route('subscription.show') }}">here</a> before delete this team.</div>
|
||||||
@else
|
@else
|
||||||
|
|||||||
@@ -58,25 +58,26 @@
|
|||||||
<div class="relative w-auto pb-8">
|
<div class="relative w-auto pb-8">
|
||||||
<p>Are you sure you would like to upgrade your instance to {{ $latestVersion }}?</p>
|
<p>Are you sure you would like to upgrade your instance to {{ $latestVersion }}?</p>
|
||||||
<br />
|
<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>
|
href="https://github.com/coollabsio/coolify/releases" target="_blank">here</a>.</p>
|
||||||
<br />
|
<br />
|
||||||
<p>If something goes wrong and you cannot upgrade your instance, You can check the following
|
<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"
|
<a class="font-bold underline dark:text-white" href="https://coolify.io/docs/upgrade"
|
||||||
target="_blank">guide</a> on what to do.
|
target="_blank">guide</a> on what to do.
|
||||||
</p>
|
</p>
|
||||||
@if ($showProgress)
|
@if ($showProgress)
|
||||||
<div class="flex flex-col pt-4">
|
<div class="flex flex-col pt-4">
|
||||||
<h4>Progress <x-loading /></h4>
|
<h2>Progress <x-loading /></h2>
|
||||||
<div x-html="currentStatus"></div>
|
<div x-html="currentStatus"></div>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2">
|
<div class="flex gap-4">
|
||||||
@if (!$showProgress)
|
@if (!$showProgress)
|
||||||
<x-forms.button @click="modalOpen=false"
|
<x-forms.button @click="modalOpen=false"
|
||||||
class="w-24 dark:bg-coolgray-200 dark:hover:bg-coolgray-300">Cancel
|
class="w-24 dark:bg-coolgray-200 dark:hover:bg-coolgray-300">Cancel
|
||||||
</x-forms.button>
|
</x-forms.button>
|
||||||
|
<div class="flex-1"></div>
|
||||||
<x-forms.button @click="confirmed" class="w-24" isHighlighted type="button">Continue
|
<x-forms.button @click="confirmed" class="w-24" isHighlighted type="button">Continue
|
||||||
</x-forms.button>
|
</x-forms.button>
|
||||||
@endif
|
@endif
|
||||||
@@ -98,6 +99,10 @@
|
|||||||
this.$wire.$call('upgrade')
|
this.$wire.$call('upgrade')
|
||||||
this.upgrade();
|
this.upgrade();
|
||||||
this.$wire.showProgress = true;
|
this.$wire.showProgress = true;
|
||||||
|
window.addEventListener('beforeunload', (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
event.returnValue = '';
|
||||||
|
});
|
||||||
},
|
},
|
||||||
revive() {
|
revive() {
|
||||||
if (checkHealthInterval) return true;
|
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": {
|
"coolify": {
|
||||||
"v4": {
|
"v4": {
|
||||||
"version": "4.0.0-beta.301"
|
"version": "4.0.0-beta.306"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user