diff --git a/app/Livewire/Project/Service/Navbar.php b/app/Livewire/Project/Service/Navbar.php
index 70b3b5db6..fa76ee26f 100644
--- a/app/Livewire/Project/Service/Navbar.php
+++ b/app/Livewire/Project/Service/Navbar.php
@@ -39,6 +39,7 @@ class Navbar extends Component
return [
"echo-private:user.{$userId},ServiceStatusChanged" => 'serviceStarted',
+ "envsUpdated" => '$refresh',
];
}
diff --git a/app/Livewire/Project/Shared/EnvironmentVariable/Show.php b/app/Livewire/Project/Shared/EnvironmentVariable/Show.php
index 463ceecad..0538a6bdb 100644
--- a/app/Livewire/Project/Shared/EnvironmentVariable/Show.php
+++ b/app/Livewire/Project/Shared/EnvironmentVariable/Show.php
@@ -37,6 +37,7 @@ class Show extends Component
'env.is_literal' => 'required|boolean',
'env.is_shown_once' => 'required|boolean',
'env.real_value' => 'nullable',
+ 'env.is_required' => 'required|boolean',
];
protected $validationAttributes = [
@@ -46,6 +47,7 @@ class Show extends Component
'env.is_multiline' => 'Multiline',
'env.is_literal' => 'Literal',
'env.is_shown_once' => 'Shown Once',
+ 'env.is_required' => 'Required',
];
public function refresh()
@@ -109,14 +111,14 @@ class Show extends Component
} else {
$this->validate();
}
- // if (str($this->env->value)->startsWith('{{') && str($this->env->value)->endsWith('}}')) {
- // $type = str($this->env->value)->after('{{')->before('.')->value;
- // if (! collect(SHARED_VARIABLE_TYPES)->contains($type)) {
- // $this->dispatch('error', 'Invalid shared variable type.', 'Valid types are: team, project, environment.');
- // return;
- // }
- // }
+ if ($this->env->is_required && str($this->env->real_value)->isEmpty()) {
+ $oldValue = $this->env->getOriginal('value');
+ $this->env->value = $oldValue;
+ $this->dispatch('error', 'Required environment variable cannot be empty.');
+
+ return;
+ }
$this->serialize();
$this->env->save();
$this->dispatch('success', 'Environment variable updated.');
diff --git a/app/Livewire/Server/Form.php b/app/Livewire/Server/Form.php
index c4f25c79d..fe7fc6020 100644
--- a/app/Livewire/Server/Form.php
+++ b/app/Livewire/Server/Form.php
@@ -245,7 +245,6 @@ class Form extends Component
$newTimezone = $this->server->settings->server_timezone;
if ($currentTimezone !== $newTimezone || $currentTimezone === '') {
$this->server->settings->server_timezone = $newTimezone;
- $this->server->settings->save();
}
$this->server->settings->save();
$this->server->save();
@@ -255,14 +254,6 @@ class Form extends Component
return handleError($e, $this);
}
}
-
- public function updatedServerSettingsServerTimezone($value)
- {
- $this->server->settings->server_timezone = $value;
- $this->server->settings->save();
- $this->dispatch('success', 'Server timezone updated.');
- }
-
public function manualCleanup()
{
try {
diff --git a/app/Livewire/Settings/Index.php b/app/Livewire/Settings/Index.php
index 754f0929b..eb492e691 100644
--- a/app/Livewire/Settings/Index.php
+++ b/app/Livewire/Settings/Index.php
@@ -28,6 +28,7 @@ class Index extends Component
protected string $dynamic_config_path = '/data/coolify/proxy/dynamic';
protected Server $server;
+ public $timezones;
protected $rules = [
'settings.fqdn' => 'nullable',
@@ -53,9 +54,9 @@ class Index extends Component
'settings.is_auto_update_enabled' => 'Auto Update Enabled',
'auto_update_frequency' => 'Auto Update Frequency',
'update_check_frequency' => 'Update Check Frequency',
+ 'settings.instance_timezone' => 'Instance Timezone',
];
- public $timezones;
public function mount()
{
@@ -170,12 +171,6 @@ class Index extends Component
}
}
- public function updatedSettingsInstanceTimezone($value)
- {
- $this->settings->instance_timezone = $value;
- $this->settings->save();
- $this->dispatch('success', 'Instance timezone updated.');
- }
public function render()
{
diff --git a/app/Models/EnvironmentVariable.php b/app/Models/EnvironmentVariable.php
index 9f8e4b342..531c8fa40 100644
--- a/app/Models/EnvironmentVariable.php
+++ b/app/Models/EnvironmentVariable.php
@@ -44,7 +44,7 @@ class EnvironmentVariable extends Model
'version' => 'string',
];
- protected $appends = ['real_value', 'is_shared'];
+ protected $appends = ['real_value', 'is_shared', 'is_really_required'];
protected static function booted()
{
@@ -130,6 +130,13 @@ class EnvironmentVariable extends Model
);
}
+ protected function isReallyRequired(): Attribute
+ {
+ return Attribute::make(
+ get: fn () => $this->is_required && str($this->real_value)->isEmpty(),
+ );
+ }
+
protected function isShared(): Attribute
{
return Attribute::make(
diff --git a/app/Models/Service.php b/app/Models/Service.php
index 490d931b3..16e11ecb6 100644
--- a/app/Models/Service.php
+++ b/app/Models/Service.php
@@ -319,7 +319,7 @@ class Service extends BaseModel
if ($password) {
$data = $data->merge([
'Password' => [
- 'key' => 'LABEL_STUDIO_PASSWORD',
+ 'key' => data_get($password, 'key'),
'value' => data_get($password, 'value'),
'rules' => 'required',
'isPassword' => true,
@@ -359,7 +359,7 @@ class Service extends BaseModel
if ($email) {
$data = $data->merge([
'Admin Email' => [
- 'key' => 'LANGFUSE_INIT_USER_EMAIL',
+ 'key' => data_get($email, 'key'),
'value' => data_get($email, 'value'),
'rules' => 'required|email',
],
@@ -370,7 +370,7 @@ class Service extends BaseModel
if ($password) {
$data = $data->merge([
'Admin Password' => [
- 'key' => 'LANGFUSE_INIT_USER_PASSWORD',
+ 'key' => data_get($password, 'key'),
'value' => data_get($password, 'value'),
'rules' => 'required',
'isPassword' => true,
@@ -487,7 +487,7 @@ class Service extends BaseModel
if ($admin_password) {
$data = $data->merge([
'Admin Password' => [
- 'key' => 'SERVICE_PASSWORD_TOLGEE',
+ 'key' => data_get($admin_password, 'key'),
'value' => data_get($admin_password, 'value'),
'rules' => 'required',
'isPassword' => true,
@@ -534,7 +534,7 @@ class Service extends BaseModel
if ($admin_password) {
$data = $data->merge([
'Admin Password' => [
- 'key' => 'SERVICE_PASSWORD_UNLEASH',
+ 'key' => data_get($admin_password, 'key'),
'value' => data_get($admin_password, 'value'),
'rules' => 'required',
'isPassword' => true,
@@ -557,7 +557,7 @@ class Service extends BaseModel
if ($admin_password) {
$data = $data->merge([
'Admin Password' => [
- 'key' => 'GF_SECURITY_ADMIN_PASSWORD',
+ 'key' => data_get($admin_password, 'key'),
'value' => data_get($admin_password, 'value'),
'rules' => 'required',
'isPassword' => true,
@@ -919,7 +919,7 @@ class Service extends BaseModel
if ($admin_user) {
$data = $data->merge([
'User' => [
- 'key' => 'SERVICE_USER_ADMIN',
+ 'key' => data_get($admin_user, 'key'),
'value' => data_get($admin_user, 'value', 'admin'),
'readonly' => true,
'rules' => 'required',
@@ -929,7 +929,7 @@ class Service extends BaseModel
if ($admin_password) {
$data = $data->merge([
'Password' => [
- 'key' => 'SERVICE_PASSWORD_ADMIN',
+ 'key' => data_get($admin_password, 'key'),
'value' => data_get($admin_password, 'value'),
'rules' => 'required',
'isPassword' => true,
@@ -939,7 +939,7 @@ class Service extends BaseModel
if ($admin_email) {
$data = $data->merge([
'Email' => [
- 'key' => 'ADMIN_EMAIL',
+ 'key' => data_get($admin_email, 'key'),
'value' => data_get($admin_email, 'value'),
'rules' => 'required|email',
],
@@ -1232,7 +1232,6 @@ class Service extends BaseModel
public function environment_variables(): HasMany
{
-
return $this->hasMany(EnvironmentVariable::class)->orderByRaw("LOWER(key) LIKE LOWER('SERVICE%') DESC, LOWER(key) ASC");
}
@@ -1316,4 +1315,20 @@ class Service extends BaseModel
return $networks;
}
+
+ protected function isDeployable(): Attribute
+ {
+ return Attribute::make(
+ get: function () {
+ $envs = $this->environment_variables()->where('is_required', true)->get();
+ foreach ($envs as $env) {
+ if ($env->is_really_required) {
+ return false;
+ }
+ }
+ return true;
+ }
+ );
+ }
+
}
diff --git a/bootstrap/helpers/shared.php b/bootstrap/helpers/shared.php
index cfdea81fb..ea9d6ff3c 100644
--- a/bootstrap/helpers/shared.php
+++ b/bootstrap/helpers/shared.php
@@ -3569,6 +3569,7 @@ function newParser(Application|Service $resource, int $pull_request_id = 0, ?int
]);
} else {
if ($value->startsWith('$')) {
+ $isRequired = false;
if ($value->contains(':-')) {
$value = replaceVariables($value);
$key = $value->before(':');
@@ -3583,11 +3584,13 @@ function newParser(Application|Service $resource, int $pull_request_id = 0, ?int
$key = $value->before(':');
$value = $value->after(':?');
+ $isRequired = true;
} elseif ($value->contains('?')) {
$value = replaceVariables($value);
$key = $value->before('?');
$value = $value->after('?');
+ $isRequired = true;
}
if ($originalValue->value() === $value->value()) {
// This means the variable does not have a default value, so it needs to be created in Coolify
@@ -3598,6 +3601,7 @@ function newParser(Application|Service $resource, int $pull_request_id = 0, ?int
], [
'is_build_time' => false,
'is_preview' => false,
+ 'is_required' => $isRequired,
]);
// Add the variable to the environment so it will be shown in the deployable compose file
$environment[$parsedKeyValue->value()] = $resource->environment_variables()->where('key', $parsedKeyValue)->where($nameOfId, $resource->id)->first()->value;
@@ -3611,6 +3615,7 @@ function newParser(Application|Service $resource, int $pull_request_id = 0, ?int
'value' => $value,
'is_build_time' => false,
'is_preview' => false,
+ 'is_required' => $isRequired,
]);
}
diff --git a/composer.json b/composer.json
index 7bb2b761a..fbd77d0cf 100644
--- a/composer.json
+++ b/composer.json
@@ -24,7 +24,7 @@
"lcobucci/jwt": "^5.0.0",
"league/flysystem-aws-s3-v3": "^3.0",
"league/flysystem-sftp-v3": "^3.0",
- "livewire/livewire": "3.5.2",
+ "livewire/livewire": "3.4.9",
"log1x/laravel-webfonts": "^1.0",
"lorisleiva/laravel-actions": "^2.7",
"nubs/random-name-generator": "^2.2",
diff --git a/composer.lock b/composer.lock
index e0456481c..0b8da82d0 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "e6b8a44dc3fbcd52d0d5b17628efac99",
+ "content-hash": "c47adf3684eb727e22503937435c0914",
"packages": [
{
"name": "amphp/amp",
@@ -4402,16 +4402,16 @@
},
{
"name": "livewire/livewire",
- "version": "v3.5.2",
+ "version": "v3.4.9",
"source": {
"type": "git",
"url": "https://github.com/livewire/livewire.git",
- "reference": "636725c1f87bc7844dd80277488268db27eec1aa"
+ "reference": "c65b3f0798ab2c9338213ede3588c3cdf4e6fcc0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/livewire/livewire/zipball/636725c1f87bc7844dd80277488268db27eec1aa",
- "reference": "636725c1f87bc7844dd80277488268db27eec1aa",
+ "url": "https://api.github.com/repos/livewire/livewire/zipball/c65b3f0798ab2c9338213ede3588c3cdf4e6fcc0",
+ "reference": "c65b3f0798ab2c9338213ede3588c3cdf4e6fcc0",
"shasum": ""
},
"require": {
@@ -4421,16 +4421,15 @@
"illuminate/validation": "^10.0|^11.0",
"league/mime-type-detection": "^1.9",
"php": "^8.1",
- "symfony/console": "^6.0|^7.0",
"symfony/http-kernel": "^6.2|^7.0"
},
"require-dev": {
"calebporzio/sushi": "^2.1",
- "laravel/framework": "^10.15.0|^11.0",
+ "laravel/framework": "^10.0|^11.0",
"laravel/prompts": "^0.1.6",
"mockery/mockery": "^1.3.1",
- "orchestra/testbench": "^8.21.0|^9.0",
- "orchestra/testbench-dusk": "^8.24|^9.1",
+ "orchestra/testbench": "8.20.0|^9.0",
+ "orchestra/testbench-dusk": "8.20.0|^9.0",
"phpunit/phpunit": "^10.4",
"psy/psysh": "^0.11.22|^0.12"
},
@@ -4466,7 +4465,7 @@
"description": "A front-end framework for Laravel.",
"support": {
"issues": "https://github.com/livewire/livewire/issues",
- "source": "https://github.com/livewire/livewire/tree/v3.5.2"
+ "source": "https://github.com/livewire/livewire/tree/v3.4.9"
},
"funding": [
{
@@ -4474,7 +4473,7 @@
"type": "github"
}
],
- "time": "2024-07-03T17:22:45+00:00"
+ "time": "2024-03-14T14:03:32+00:00"
},
{
"name": "log1x/laravel-webfonts",
diff --git a/config/sentry.php b/config/sentry.php
index 03d36280c..a56ee680c 100644
--- a/config/sentry.php
+++ b/config/sentry.php
@@ -7,8 +7,7 @@ return [
// The release version of your application
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
- 'release' => '4.0.0-beta.359',
-
+ 'release' => '4.0.0-beta.361',
// When left empty or `null` the Laravel environment will be used
'environment' => config('app.env'),
diff --git a/config/version.php b/config/version.php
index 6d3ef4243..0e83ff40e 100644
--- a/config/version.php
+++ b/config/version.php
@@ -1,4 +1,3 @@
boolean('is_required')->default(false);
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::table('environment_variables', function (Blueprint $table) {
+ $table->dropColumn('is_required');
+ });
+ }
+};
diff --git a/docker/coolify-realtime/package.json b/docker/coolify-realtime/package.json
index 90d4f77db..146e6b90a 100644
--- a/docker/coolify-realtime/package.json
+++ b/docker/coolify-realtime/package.json
@@ -4,7 +4,7 @@
"dependencies": {
"@xterm/addon-fit": "^0.10.0",
"@xterm/xterm": "^5.5.0",
- "cookie": "^0.6.0",
+ "cookie": "^0.7.0",
"axios": "1.7.5",
"dotenv": "^16.4.5",
"node-pty": "^1.0.0",
diff --git a/public/svgs/affine.svg b/public/svgs/affine.svg
new file mode 100644
index 000000000..d8063e920
--- /dev/null
+++ b/public/svgs/affine.svg
@@ -0,0 +1,88 @@
+
diff --git a/public/svgs/cloudbeaver.svg b/public/svgs/cloudbeaver.svg
new file mode 100644
index 000000000..4a7634766
--- /dev/null
+++ b/public/svgs/cloudbeaver.svg
@@ -0,0 +1,7 @@
+
diff --git a/public/svgs/cryptgeon.png b/public/svgs/cryptgeon.png
new file mode 100644
index 000000000..be121cfd0
Binary files /dev/null and b/public/svgs/cryptgeon.png differ
diff --git a/public/svgs/dify.png b/public/svgs/dify.png
new file mode 100644
index 000000000..326acf789
Binary files /dev/null and b/public/svgs/dify.png differ
diff --git a/public/svgs/flowise.png b/public/svgs/flowise.png
new file mode 100644
index 000000000..6b0be0d2a
Binary files /dev/null and b/public/svgs/flowise.png differ
diff --git a/public/svgs/freshrss.png b/public/svgs/freshrss.png
new file mode 100644
index 000000000..d1a75118f
Binary files /dev/null and b/public/svgs/freshrss.png differ
diff --git a/public/svgs/heyform.svg b/public/svgs/heyform.svg
new file mode 100644
index 000000000..ff29ca654
--- /dev/null
+++ b/public/svgs/heyform.svg
@@ -0,0 +1,5 @@
+
diff --git a/public/svgs/homebox.svg b/public/svgs/homebox.svg
new file mode 100644
index 000000000..08670bbb9
--- /dev/null
+++ b/public/svgs/homebox.svg
@@ -0,0 +1,11 @@
+
diff --git a/public/svgs/immich.svg b/public/svgs/immich.svg
new file mode 100644
index 000000000..9d844a772
--- /dev/null
+++ b/public/svgs/immich.svg
@@ -0,0 +1,66 @@
+
+
+
diff --git a/public/svgs/kimai.svg b/public/svgs/kimai.svg
new file mode 100644
index 000000000..35b146972
--- /dev/null
+++ b/public/svgs/kimai.svg
@@ -0,0 +1,67 @@
+
\ No newline at end of file
diff --git a/public/svgs/libretranslate.svg b/public/svgs/libretranslate.svg
new file mode 100644
index 000000000..103d47d60
--- /dev/null
+++ b/public/svgs/libretranslate.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/svgs/litequeen.svg b/public/svgs/litequeen.svg
new file mode 100644
index 000000000..aa0b8e038
--- /dev/null
+++ b/public/svgs/litequeen.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/svgs/ntfy.svg b/public/svgs/ntfy.svg
new file mode 100644
index 000000000..9e5b5136f
--- /dev/null
+++ b/public/svgs/ntfy.svg
@@ -0,0 +1 @@
+