refactor(ui): separate views for instance settings to separate paths to make it cleaner
This commit is contained in:
119
app/Livewire/Settings/Advanced.php
Normal file
119
app/Livewire/Settings/Advanced.php
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Livewire\Settings;
|
||||||
|
|
||||||
|
use App\Models\InstanceSettings;
|
||||||
|
use App\Models\Server;
|
||||||
|
use Auth;
|
||||||
|
use Hash;
|
||||||
|
use Livewire\Attributes\Validate;
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
class Advanced extends Component
|
||||||
|
{
|
||||||
|
#[Validate('required')]
|
||||||
|
public Server $server;
|
||||||
|
|
||||||
|
public InstanceSettings $settings;
|
||||||
|
|
||||||
|
#[Validate('boolean')]
|
||||||
|
public bool $is_registration_enabled;
|
||||||
|
|
||||||
|
#[Validate('boolean')]
|
||||||
|
public bool $do_not_track;
|
||||||
|
|
||||||
|
#[Validate('boolean')]
|
||||||
|
public bool $is_dns_validation_enabled;
|
||||||
|
|
||||||
|
#[Validate('nullable|string')]
|
||||||
|
public ?string $custom_dns_servers = null;
|
||||||
|
|
||||||
|
#[Validate('boolean')]
|
||||||
|
public bool $is_api_enabled;
|
||||||
|
|
||||||
|
#[Validate('nullable|string')]
|
||||||
|
public ?string $allowed_ips = null;
|
||||||
|
|
||||||
|
#[Validate('boolean')]
|
||||||
|
public bool $is_sponsorship_popup_enabled;
|
||||||
|
|
||||||
|
#[Validate('boolean')]
|
||||||
|
public bool $disable_two_step_confirmation;
|
||||||
|
|
||||||
|
public function mount()
|
||||||
|
{
|
||||||
|
if (! isInstanceAdmin()) {
|
||||||
|
return redirect()->route('dashboard');
|
||||||
|
} else {
|
||||||
|
$this->server = Server::findOrFail(0);
|
||||||
|
$this->settings = instanceSettings();
|
||||||
|
$this->custom_dns_servers = $this->settings->custom_dns_servers;
|
||||||
|
$this->allowed_ips = $this->settings->allowed_ips;
|
||||||
|
$this->do_not_track = $this->settings->do_not_track;
|
||||||
|
$this->is_registration_enabled = $this->settings->is_registration_enabled;
|
||||||
|
$this->is_dns_validation_enabled = $this->settings->is_dns_validation_enabled;
|
||||||
|
$this->is_api_enabled = $this->settings->is_api_enabled;
|
||||||
|
$this->disable_two_step_confirmation = $this->settings->disable_two_step_confirmation;
|
||||||
|
$this->is_sponsorship_popup_enabled = $this->settings->is_sponsorship_popup_enabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function submit()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$this->validate();
|
||||||
|
|
||||||
|
$this->custom_dns_servers = str($this->custom_dns_servers)->replaceEnd(',', '')->trim();
|
||||||
|
$this->custom_dns_servers = str($this->custom_dns_servers)->trim()->explode(',')->map(function ($dns) {
|
||||||
|
return str($dns)->trim()->lower();
|
||||||
|
})->unique()->implode(',');
|
||||||
|
|
||||||
|
$this->allowed_ips = str($this->allowed_ips)->replaceEnd(',', '')->trim();
|
||||||
|
$this->allowed_ips = str($this->allowed_ips)->trim()->explode(',')->map(function ($ip) {
|
||||||
|
return str($ip)->trim();
|
||||||
|
})->unique()->implode(',');
|
||||||
|
|
||||||
|
$this->instantSave();
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return handleError($e, $this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function instantSave()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$this->settings->is_registration_enabled = $this->is_registration_enabled;
|
||||||
|
$this->settings->do_not_track = $this->do_not_track;
|
||||||
|
$this->settings->is_dns_validation_enabled = $this->is_dns_validation_enabled;
|
||||||
|
$this->settings->custom_dns_servers = $this->custom_dns_servers;
|
||||||
|
$this->settings->is_api_enabled = $this->is_api_enabled;
|
||||||
|
$this->settings->allowed_ips = $this->allowed_ips;
|
||||||
|
$this->settings->is_sponsorship_popup_enabled = $this->is_sponsorship_popup_enabled;
|
||||||
|
$this->settings->disable_two_step_confirmation = $this->disable_two_step_confirmation;
|
||||||
|
$this->settings->save();
|
||||||
|
$this->dispatch('success', 'Settings updated!');
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return handleError($e, $this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toggleTwoStepConfirmation($password): bool
|
||||||
|
{
|
||||||
|
if (! Hash::check($password, Auth::user()->password)) {
|
||||||
|
$this->addError('password', 'The provided password is incorrect.');
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->settings->disable_two_step_confirmation = $this->disable_two_step_confirmation = true;
|
||||||
|
$this->settings->save();
|
||||||
|
$this->dispatch('success', 'Two step confirmation has been disabled.');
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return view('livewire.settings.advanced');
|
||||||
|
}
|
||||||
|
}
|
@@ -2,11 +2,8 @@
|
|||||||
|
|
||||||
namespace App\Livewire\Settings;
|
namespace App\Livewire\Settings;
|
||||||
|
|
||||||
use App\Jobs\CheckForUpdatesJob;
|
|
||||||
use App\Models\InstanceSettings;
|
use App\Models\InstanceSettings;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use Illuminate\Support\Facades\Auth;
|
|
||||||
use Illuminate\Support\Facades\Hash;
|
|
||||||
use Livewire\Attributes\Computed;
|
use Livewire\Attributes\Computed;
|
||||||
use Livewire\Attributes\Validate;
|
use Livewire\Attributes\Validate;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
@@ -15,10 +12,7 @@ class Index extends Component
|
|||||||
{
|
{
|
||||||
public InstanceSettings $settings;
|
public InstanceSettings $settings;
|
||||||
|
|
||||||
protected Server $server;
|
public Server $server;
|
||||||
|
|
||||||
#[Validate('boolean')]
|
|
||||||
public bool $is_auto_update_enabled;
|
|
||||||
|
|
||||||
#[Validate('nullable|string|max:255')]
|
#[Validate('nullable|string|max:255')]
|
||||||
public ?string $fqdn = null;
|
public ?string $fqdn = null;
|
||||||
@@ -29,48 +23,18 @@ class Index extends Component
|
|||||||
#[Validate('required|integer|min:1025|max:65535')]
|
#[Validate('required|integer|min:1025|max:65535')]
|
||||||
public int $public_port_max;
|
public int $public_port_max;
|
||||||
|
|
||||||
#[Validate('nullable|string')]
|
|
||||||
public ?string $custom_dns_servers = null;
|
|
||||||
|
|
||||||
#[Validate('nullable|string|max:255')]
|
#[Validate('nullable|string|max:255')]
|
||||||
public ?string $instance_name = null;
|
public ?string $instance_name = null;
|
||||||
|
|
||||||
#[Validate('nullable|string')]
|
|
||||||
public ?string $allowed_ips = null;
|
|
||||||
|
|
||||||
#[Validate('nullable|string')]
|
#[Validate('nullable|string')]
|
||||||
public ?string $public_ipv4 = null;
|
public ?string $public_ipv4 = null;
|
||||||
|
|
||||||
#[Validate('nullable|string')]
|
#[Validate('nullable|string')]
|
||||||
public ?string $public_ipv6 = null;
|
public ?string $public_ipv6 = null;
|
||||||
|
|
||||||
#[Validate('string')]
|
|
||||||
public string $auto_update_frequency;
|
|
||||||
|
|
||||||
#[Validate('string|required')]
|
|
||||||
public string $update_check_frequency;
|
|
||||||
|
|
||||||
#[Validate('required|string|timezone')]
|
#[Validate('required|string|timezone')]
|
||||||
public string $instance_timezone;
|
public string $instance_timezone;
|
||||||
|
|
||||||
#[Validate('boolean')]
|
|
||||||
public bool $do_not_track;
|
|
||||||
|
|
||||||
#[Validate('boolean')]
|
|
||||||
public bool $is_registration_enabled;
|
|
||||||
|
|
||||||
#[Validate('boolean')]
|
|
||||||
public bool $is_dns_validation_enabled;
|
|
||||||
|
|
||||||
#[Validate('boolean')]
|
|
||||||
public bool $is_api_enabled;
|
|
||||||
|
|
||||||
#[Validate('boolean')]
|
|
||||||
public bool $disable_two_step_confirmation;
|
|
||||||
|
|
||||||
#[Validate('boolean')]
|
|
||||||
public bool $is_sponsorship_popup_enabled;
|
|
||||||
|
|
||||||
public function render()
|
public function render()
|
||||||
{
|
{
|
||||||
return view('livewire.settings.index');
|
return view('livewire.settings.index');
|
||||||
@@ -82,24 +46,14 @@ class Index extends Component
|
|||||||
return redirect()->route('dashboard');
|
return redirect()->route('dashboard');
|
||||||
} else {
|
} else {
|
||||||
$this->settings = instanceSettings();
|
$this->settings = instanceSettings();
|
||||||
|
$this->server = Server::findOrFail(0);
|
||||||
$this->fqdn = $this->settings->fqdn;
|
$this->fqdn = $this->settings->fqdn;
|
||||||
$this->public_port_min = $this->settings->public_port_min;
|
$this->public_port_min = $this->settings->public_port_min;
|
||||||
$this->public_port_max = $this->settings->public_port_max;
|
$this->public_port_max = $this->settings->public_port_max;
|
||||||
$this->custom_dns_servers = $this->settings->custom_dns_servers;
|
|
||||||
$this->instance_name = $this->settings->instance_name;
|
$this->instance_name = $this->settings->instance_name;
|
||||||
$this->allowed_ips = $this->settings->allowed_ips;
|
|
||||||
$this->public_ipv4 = $this->settings->public_ipv4;
|
$this->public_ipv4 = $this->settings->public_ipv4;
|
||||||
$this->public_ipv6 = $this->settings->public_ipv6;
|
$this->public_ipv6 = $this->settings->public_ipv6;
|
||||||
$this->do_not_track = $this->settings->do_not_track;
|
|
||||||
$this->is_auto_update_enabled = $this->settings->is_auto_update_enabled;
|
|
||||||
$this->is_registration_enabled = $this->settings->is_registration_enabled;
|
|
||||||
$this->is_dns_validation_enabled = $this->settings->is_dns_validation_enabled;
|
|
||||||
$this->is_api_enabled = $this->settings->is_api_enabled;
|
|
||||||
$this->auto_update_frequency = $this->settings->auto_update_frequency;
|
|
||||||
$this->update_check_frequency = $this->settings->update_check_frequency;
|
|
||||||
$this->instance_timezone = $this->settings->instance_timezone;
|
$this->instance_timezone = $this->settings->instance_timezone;
|
||||||
$this->disable_two_step_confirmation = $this->settings->disable_two_step_confirmation;
|
|
||||||
$this->is_sponsorship_popup_enabled = $this->settings->is_sponsorship_popup_enabled;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,30 +69,13 @@ class Index extends Component
|
|||||||
public function instantSave($isSave = true)
|
public function instantSave($isSave = true)
|
||||||
{
|
{
|
||||||
$this->validate();
|
$this->validate();
|
||||||
if ($this->settings->is_auto_update_enabled === true) {
|
|
||||||
$this->validate([
|
|
||||||
'auto_update_frequency' => ['required', 'string'],
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->settings->fqdn = $this->fqdn;
|
$this->settings->fqdn = $this->fqdn;
|
||||||
$this->settings->public_port_min = $this->public_port_min;
|
$this->settings->public_port_min = $this->public_port_min;
|
||||||
$this->settings->public_port_max = $this->public_port_max;
|
$this->settings->public_port_max = $this->public_port_max;
|
||||||
$this->settings->custom_dns_servers = $this->custom_dns_servers;
|
|
||||||
$this->settings->instance_name = $this->instance_name;
|
$this->settings->instance_name = $this->instance_name;
|
||||||
$this->settings->allowed_ips = $this->allowed_ips;
|
|
||||||
$this->settings->public_ipv4 = $this->public_ipv4;
|
$this->settings->public_ipv4 = $this->public_ipv4;
|
||||||
$this->settings->public_ipv6 = $this->public_ipv6;
|
$this->settings->public_ipv6 = $this->public_ipv6;
|
||||||
$this->settings->do_not_track = $this->do_not_track;
|
|
||||||
$this->settings->is_auto_update_enabled = $this->is_auto_update_enabled;
|
|
||||||
$this->settings->is_registration_enabled = $this->is_registration_enabled;
|
|
||||||
$this->settings->is_dns_validation_enabled = $this->is_dns_validation_enabled;
|
|
||||||
$this->settings->is_api_enabled = $this->is_api_enabled;
|
|
||||||
$this->settings->auto_update_frequency = $this->auto_update_frequency;
|
|
||||||
$this->settings->update_check_frequency = $this->update_check_frequency;
|
|
||||||
$this->settings->disable_two_step_confirmation = $this->disable_two_step_confirmation;
|
|
||||||
$this->settings->instance_timezone = $this->instance_timezone;
|
$this->settings->instance_timezone = $this->instance_timezone;
|
||||||
$this->settings->is_sponsorship_popup_enabled = $this->is_sponsorship_popup_enabled;
|
|
||||||
if ($isSave) {
|
if ($isSave) {
|
||||||
$this->settings->save();
|
$this->settings->save();
|
||||||
$this->dispatch('success', 'Settings updated!');
|
$this->dispatch('success', 'Settings updated!');
|
||||||
@@ -149,7 +86,6 @@ class Index extends Component
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$error_show = false;
|
$error_show = false;
|
||||||
$this->server = Server::findOrFail(0);
|
|
||||||
$this->resetErrorBag();
|
$this->resetErrorBag();
|
||||||
|
|
||||||
if (! validate_timezone($this->instance_timezone)) {
|
if (! validate_timezone($this->instance_timezone)) {
|
||||||
@@ -166,46 +102,15 @@ class Index extends Component
|
|||||||
}
|
}
|
||||||
$this->validate();
|
$this->validate();
|
||||||
|
|
||||||
if ($this->is_auto_update_enabled && ! validate_cron_expression($this->auto_update_frequency)) {
|
if ($this->settings->is_dns_validation_enabled && $this->fqdn) {
|
||||||
$this->dispatch('error', 'Invalid Cron / Human expression for Auto Update Frequency.');
|
if (! validate_dns_entry($this->fqdn, $this->server)) {
|
||||||
if (empty($this->auto_update_frequency)) {
|
$this->dispatch('error', "Validating DNS failed.<br><br>Make sure you have added the DNS records correctly.<br><br>{$this->fqdn}->{$this->server->ip}<br><br>Check this <a target='_blank' class='underline dark:text-white' href='https://coolify.io/docs/knowledge-base/dns-configuration'>documentation</a> for further help.");
|
||||||
$this->auto_update_frequency = '0 0 * * *';
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! validate_cron_expression($this->update_check_frequency)) {
|
|
||||||
$this->dispatch('error', 'Invalid Cron / Human expression for Update Check Frequency.');
|
|
||||||
if (empty($this->update_check_frequency)) {
|
|
||||||
$this->update_check_frequency = '0 * * * *';
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->settings->is_dns_validation_enabled && $this->settings->fqdn) {
|
|
||||||
if (! validate_dns_entry($this->settings->fqdn, $this->server)) {
|
|
||||||
$this->dispatch('error', "Validating DNS failed.<br><br>Make sure you have added the DNS records correctly.<br><br>{$this->settings->fqdn}->{$this->server->ip}<br><br>Check this <a target='_blank' class='underline dark:text-white' href='https://coolify.io/docs/knowledge-base/dns-configuration'>documentation</a> for further help.");
|
|
||||||
$error_show = true;
|
$error_show = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($this->settings->fqdn) {
|
if ($this->fqdn) {
|
||||||
check_domain_usage(domain: $this->settings->fqdn);
|
check_domain_usage(domain: $this->fqdn);
|
||||||
}
|
}
|
||||||
$this->settings->custom_dns_servers = str($this->settings->custom_dns_servers)->replaceEnd(',', '')->trim();
|
|
||||||
$this->settings->custom_dns_servers = str($this->settings->custom_dns_servers)->trim()->explode(',')->map(function ($dns) {
|
|
||||||
return str($dns)->trim()->lower();
|
|
||||||
});
|
|
||||||
$this->settings->custom_dns_servers = $this->settings->custom_dns_servers->unique();
|
|
||||||
$this->settings->custom_dns_servers = $this->settings->custom_dns_servers->implode(',');
|
|
||||||
|
|
||||||
$this->settings->allowed_ips = str($this->settings->allowed_ips)->replaceEnd(',', '')->trim();
|
|
||||||
$this->settings->allowed_ips = str($this->settings->allowed_ips)->trim()->explode(',')->map(function ($ip) {
|
|
||||||
return str($ip)->trim();
|
|
||||||
});
|
|
||||||
$this->settings->allowed_ips = $this->settings->allowed_ips->unique();
|
|
||||||
$this->settings->allowed_ips = $this->settings->allowed_ips->implode(',');
|
|
||||||
|
|
||||||
$this->instantSave(isSave: false);
|
$this->instantSave(isSave: false);
|
||||||
|
|
||||||
@@ -218,31 +123,4 @@ class Index extends Component
|
|||||||
return handleError($e, $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function checkManually()
|
|
||||||
{
|
|
||||||
CheckForUpdatesJob::dispatchSync();
|
|
||||||
$this->dispatch('updateAvailable');
|
|
||||||
$settings = instanceSettings();
|
|
||||||
if ($settings->new_version_available) {
|
|
||||||
$this->dispatch('success', 'New version available!');
|
|
||||||
} else {
|
|
||||||
$this->dispatch('success', 'No new version available.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function toggleTwoStepConfirmation($password): bool
|
|
||||||
{
|
|
||||||
if (! Hash::check($password, Auth::user()->password)) {
|
|
||||||
$this->addError('password', 'The provided password is incorrect.');
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->settings->disable_two_step_confirmation = $this->disable_two_step_confirmation = true;
|
|
||||||
$this->settings->save();
|
|
||||||
$this->dispatch('success', 'Two step confirmation has been disabled.');
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
101
app/Livewire/Settings/Updates.php
Normal file
101
app/Livewire/Settings/Updates.php
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Livewire\Settings;
|
||||||
|
|
||||||
|
use App\Jobs\CheckForUpdatesJob;
|
||||||
|
use App\Models\InstanceSettings;
|
||||||
|
use App\Models\Server;
|
||||||
|
use Livewire\Attributes\Validate;
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
class Updates extends Component
|
||||||
|
{
|
||||||
|
public InstanceSettings $settings;
|
||||||
|
|
||||||
|
public Server $server;
|
||||||
|
|
||||||
|
#[Validate('string')]
|
||||||
|
public string $auto_update_frequency;
|
||||||
|
|
||||||
|
#[Validate('string|required')]
|
||||||
|
public string $update_check_frequency;
|
||||||
|
|
||||||
|
#[Validate('boolean')]
|
||||||
|
public bool $is_auto_update_enabled;
|
||||||
|
|
||||||
|
public function mount()
|
||||||
|
{
|
||||||
|
$this->server = Server::findOrFail(0);
|
||||||
|
|
||||||
|
$this->settings = instanceSettings();
|
||||||
|
$this->auto_update_frequency = $this->settings->auto_update_frequency;
|
||||||
|
$this->update_check_frequency = $this->settings->update_check_frequency;
|
||||||
|
$this->is_auto_update_enabled = $this->settings->is_auto_update_enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function instantSave()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if ($this->settings->is_auto_update_enabled === true) {
|
||||||
|
$this->validate([
|
||||||
|
'auto_update_frequency' => ['required', 'string'],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
$this->settings->auto_update_frequency = $this->auto_update_frequency;
|
||||||
|
$this->settings->update_check_frequency = $this->update_check_frequency;
|
||||||
|
$this->settings->is_auto_update_enabled = $this->is_auto_update_enabled;
|
||||||
|
$this->settings->save();
|
||||||
|
$this->dispatch('success', 'Settings updated!');
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return handleError($e, $this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function submit()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$this->resetErrorBag();
|
||||||
|
$this->validate();
|
||||||
|
|
||||||
|
if ($this->is_auto_update_enabled && ! validate_cron_expression($this->auto_update_frequency)) {
|
||||||
|
$this->dispatch('error', 'Invalid Cron / Human expression for Auto Update Frequency.');
|
||||||
|
if (empty($this->auto_update_frequency)) {
|
||||||
|
$this->auto_update_frequency = '0 0 * * *';
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! validate_cron_expression($this->update_check_frequency)) {
|
||||||
|
$this->dispatch('error', 'Invalid Cron / Human expression for Update Check Frequency.');
|
||||||
|
if (empty($this->update_check_frequency)) {
|
||||||
|
$this->update_check_frequency = '0 * * * *';
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->instantSave();
|
||||||
|
$this->server->setupDynamicProxyConfiguration();
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return handleError($e, $this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function checkManually()
|
||||||
|
{
|
||||||
|
CheckForUpdatesJob::dispatchSync();
|
||||||
|
$this->dispatch('updateAvailable');
|
||||||
|
$settings = instanceSettings();
|
||||||
|
if ($settings->new_version_available) {
|
||||||
|
$this->dispatch('success', 'New version available!');
|
||||||
|
} else {
|
||||||
|
$this->dispatch('success', 'No new version available.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return view('livewire.settings.updates');
|
||||||
|
}
|
||||||
|
}
|
@@ -31,7 +31,7 @@ class Form extends Component
|
|||||||
'storage.endpoint' => 'Endpoint',
|
'storage.endpoint' => 'Endpoint',
|
||||||
];
|
];
|
||||||
|
|
||||||
public function test_s3_connection()
|
public function testConnection()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$this->storage->testConnection(shouldSave: true);
|
$this->storage->testConnection(shouldSave: true);
|
||||||
@@ -45,6 +45,8 @@ class Form extends Component
|
|||||||
public function delete()
|
public function delete()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
$this->authorize('delete', $this->storage);
|
||||||
|
|
||||||
$this->storage->delete();
|
$this->storage->delete();
|
||||||
|
|
||||||
return redirect()->route('storage.index');
|
return redirect()->route('storage.index');
|
||||||
@@ -57,7 +59,7 @@ class Form extends Component
|
|||||||
{
|
{
|
||||||
$this->validate();
|
$this->validate();
|
||||||
try {
|
try {
|
||||||
$this->test_s3_connection();
|
$this->testConnection();
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return handleError($e, $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
|
66
app/Policies/S3StoragePolicy.php
Normal file
66
app/Policies/S3StoragePolicy.php
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Policies;
|
||||||
|
|
||||||
|
use App\Models\S3Storage;
|
||||||
|
use App\Models\Server;
|
||||||
|
use App\Models\User;
|
||||||
|
|
||||||
|
class S3StoragePolicy
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine whether the user can view any models.
|
||||||
|
*/
|
||||||
|
public function viewAny(User $user): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the user can view the model.
|
||||||
|
*/
|
||||||
|
public function view(User $user, S3Storage $storage): bool
|
||||||
|
{
|
||||||
|
return $user->teams()->get()->firstWhere('id', $storage->team_id) !== null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the user can create models.
|
||||||
|
*/
|
||||||
|
public function create(User $user): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the user can update the model.
|
||||||
|
*/
|
||||||
|
public function update(User $user, Server $server): bool
|
||||||
|
{
|
||||||
|
return $user->teams()->get()->firstWhere('id', $server->team_id) !== null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the user can delete the model.
|
||||||
|
*/
|
||||||
|
public function delete(User $user, S3Storage $storage): bool
|
||||||
|
{
|
||||||
|
return $user->teams()->get()->firstWhere('id', $storage->team_id) !== null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the user can restore the model.
|
||||||
|
*/
|
||||||
|
public function restore(User $user, S3Storage $storage): bool
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the user can permanently delete the model.
|
||||||
|
*/
|
||||||
|
public function forceDelete(User $user, S3Storage $storage): bool
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
@@ -42,7 +42,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@utility button {
|
@utility button {
|
||||||
@apply flex gap-2 justify-center items-center px-2 py-1 text-sm text-black normal-case rounded-sm border outline-0 cursor-pointer bg-neutral-200/50 border-neutral-300 hover:bg-neutral-300 dark:bg-coolgray-200 dark:text-white dark:hover:text-white dark:hover:bg-coolgray-500 dark:border-coolgray-300 hover:text-black disabled:cursor-not-allowed min-w-fit dark:disabled:text-neutral-600 disabled:border-none disabled:hover:bg-transparent disabled:bg-transparent disabled:text-neutral-300;
|
@apply flex gap-2 justify-center items-center px-2 py-1 text-sm text-black normal-case rounded-sm border outline-0 cursor-pointer bg-neutral-200/50 border-neutral-300 hover:bg-neutral-300 dark:bg-coolgray-200 dark:text-white dark:hover:text-white dark:hover:bg-coolgray-500 dark:border-coolgray-300 hover:text-black disabled:cursor-not-allowed min-w-fit dark:disabled:text-neutral-600 disabled:border-transparent disabled:hover:bg-transparent disabled:bg-transparent disabled:text-neutral-300;
|
||||||
}
|
}
|
||||||
|
|
||||||
@utility alert-success {
|
@utility alert-success {
|
||||||
|
@@ -5,19 +5,19 @@
|
|||||||
<nav class="flex items-center gap-6 min-h-10 whitespace-nowrap">
|
<nav class="flex items-center gap-6 min-h-10 whitespace-nowrap">
|
||||||
<a class="{{ request()->routeIs('settings.index') ? 'dark:text-white' : '' }}"
|
<a class="{{ request()->routeIs('settings.index') ? 'dark:text-white' : '' }}"
|
||||||
href="{{ route('settings.index') }}">
|
href="{{ route('settings.index') }}">
|
||||||
<button>Configuration</button>
|
Configuration
|
||||||
</a>
|
</a>
|
||||||
<a class="{{ request()->routeIs('settings.backup') ? 'dark:text-white' : '' }}"
|
<a class="{{ request()->routeIs('settings.backup') ? 'dark:text-white' : '' }}"
|
||||||
href="{{ route('settings.backup') }}">
|
href="{{ route('settings.backup') }}">
|
||||||
<button>Backup</button>
|
Backup
|
||||||
</a>
|
</a>
|
||||||
<a class="{{ request()->routeIs('settings.email') ? 'dark:text-white' : '' }}"
|
<a class="{{ request()->routeIs('settings.email') ? 'dark:text-white' : '' }}"
|
||||||
href="{{ route('settings.email') }}">
|
href="{{ route('settings.email') }}">
|
||||||
<button>Transactional Email</button>
|
Transactional Email
|
||||||
</a>
|
</a>
|
||||||
<a class="{{ request()->routeIs('settings.oauth') ? 'dark:text-white' : '' }}"
|
<a class="{{ request()->routeIs('settings.oauth') ? 'dark:text-white' : '' }}"
|
||||||
href="{{ route('settings.oauth') }}">
|
href="{{ route('settings.oauth') }}">
|
||||||
<button>OAuth</button>
|
OAuth
|
||||||
</a>
|
</a>
|
||||||
<div class="flex-1"></div>
|
<div class="flex-1"></div>
|
||||||
</nav>
|
</nav>
|
||||||
|
8
resources/views/components/settings/sidebar.blade.php
Normal file
8
resources/views/components/settings/sidebar.blade.php
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<div class="flex flex-col items-start gap-2 min-w-fit">
|
||||||
|
<a class="menu-item {{ $activeMenu === 'general' ? 'menu-item-active' : '' }}"
|
||||||
|
href="{{ route('settings.index') }}">General</a>
|
||||||
|
<a class="menu-item {{ $activeMenu === 'advanced' ? 'menu-item-active' : '' }}"
|
||||||
|
href="{{ route('settings.advanced') }}">Advanced</a>
|
||||||
|
<a class="menu-item {{ $activeMenu === 'updates' ? 'menu-item-active' : '' }}"
|
||||||
|
href="{{ route('settings.updates') }}">Updates</a>
|
||||||
|
</div>
|
@@ -9,16 +9,16 @@
|
|||||||
<div class="navbar-main">
|
<div class="navbar-main">
|
||||||
<nav class="flex items-center gap-6 min-h-10">
|
<nav class="flex items-center gap-6 min-h-10">
|
||||||
<a class="{{ request()->routeIs('team.index') ? 'dark:text-white' : '' }}" href="{{ route('team.index') }}">
|
<a class="{{ request()->routeIs('team.index') ? 'dark:text-white' : '' }}" href="{{ route('team.index') }}">
|
||||||
<button>General</button>
|
General
|
||||||
</a>
|
</a>
|
||||||
<a class="{{ request()->routeIs('team.member.index') ? 'dark:text-white' : '' }}"
|
<a class="{{ request()->routeIs('team.member.index') ? 'dark:text-white' : '' }}"
|
||||||
href="{{ route('team.member.index') }}">
|
href="{{ route('team.member.index') }}">
|
||||||
<button>Members</button>
|
Members
|
||||||
</a>
|
</a>
|
||||||
@if (isInstanceAdmin())
|
@if (isInstanceAdmin())
|
||||||
<a class="{{ request()->routeIs('team.admin-view') ? 'dark:text-white' : '' }}"
|
<a class="{{ request()->routeIs('team.admin-view') ? 'dark:text-white' : '' }}"
|
||||||
href="{{ route('team.admin-view') }}">
|
href="{{ route('team.admin-view') }}">
|
||||||
<button>Admin View</button>
|
Admin View
|
||||||
</a>
|
</a>
|
||||||
@endif
|
@endif
|
||||||
<div class="flex-1"></div>
|
<div class="flex-1"></div>
|
||||||
|
@@ -63,12 +63,13 @@
|
|||||||
<section>
|
<section>
|
||||||
<h3 class="pb-2">Servers</h3>
|
<h3 class="pb-2">Servers</h3>
|
||||||
@if ($servers->count() > 0)
|
@if ($servers->count() > 0)
|
||||||
<div class="grid grid-cols-1 gap-2 xl:grid-cols-2">
|
<div class="grid grid-cols-1 gap-4 xl:grid-cols-2">
|
||||||
@foreach ($servers as $server)
|
@foreach ($servers as $server)
|
||||||
<a href="{{ route('server.show', ['server_uuid' => data_get($server, 'uuid')]) }}"
|
<a href="{{ route('server.show', ['server_uuid' => data_get($server, 'uuid')]) }}"
|
||||||
@class([
|
@class([
|
||||||
'gap-2 border cursor-pointer box group',
|
'gap-2 border cursor-pointer box group',
|
||||||
'border-red-500' => !$server->settings->is_reachable,
|
'border-red-500' =>
|
||||||
|
!$server->settings->is_reachable || $server->settings->force_disabled,
|
||||||
])>
|
])>
|
||||||
<div class="flex flex-col justify-center mx-6">
|
<div class="flex flex-col justify-center mx-6">
|
||||||
<div class="box-title">
|
<div class="box-title">
|
||||||
|
@@ -11,13 +11,13 @@
|
|||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
<div class="subtitle">Network endpoints to deploy your resources.</div>
|
<div class="subtitle">Network endpoints to deploy your resources.</div>
|
||||||
<div class="grid gap-2 lg:grid-cols-1">
|
<div class="grid gap-4 lg:grid-cols-2">
|
||||||
@forelse ($servers as $server)
|
@forelse ($servers as $server)
|
||||||
@forelse ($server->destinations() as $destination)
|
@forelse ($server->destinations() as $destination)
|
||||||
@if ($destination->getMorphClass() === 'App\Models\StandaloneDocker')
|
@if ($destination->getMorphClass() === 'App\Models\StandaloneDocker')
|
||||||
<a class="box group"
|
<a class="box group"
|
||||||
href="{{ route('destination.show', ['destination_uuid' => data_get($destination, 'uuid')]) }}">
|
href="{{ route('destination.show', ['destination_uuid' => data_get($destination, 'uuid')]) }}">
|
||||||
<div class="flex flex-col mx-6">
|
<div class="flex flex-col justify-center mx-6">
|
||||||
<div class="box-title">{{ $destination->name }}</div>
|
<div class="box-title">{{ $destination->name }}</div>
|
||||||
<div class="box-description">Server: {{ $destination->server->name }}</div>
|
<div class="box-description">Server: {{ $destination->server->name }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -2,5 +2,5 @@
|
|||||||
<x-modal-confirmation buttonFullWidth title="Confirm Team Deletion?" buttonTitle="Delete Team" isErrorButton
|
<x-modal-confirmation buttonFullWidth title="Confirm Team Deletion?" buttonTitle="Delete Team" isErrorButton
|
||||||
submitAction="delete" :actions="['The current Team will be permanently deleted.']" confirmationText="{{ $team }}"
|
submitAction="delete" :actions="['The current Team will be permanently deleted.']" confirmationText="{{ $team }}"
|
||||||
confirmationLabel="Please confirm the execution of the actions by entering the Team Name below"
|
confirmationLabel="Please confirm the execution of the actions by entering the Team Name below"
|
||||||
shortConfirmationLabel="Team Name" step3ButtonText="Permanently Delete" />
|
shortConfirmationLabel="Team Name" step3ButtonText="Confirm" />
|
||||||
</div>
|
</div>
|
||||||
|
@@ -112,7 +112,7 @@
|
|||||||
:checkboxes="$checkboxes"
|
:checkboxes="$checkboxes"
|
||||||
:actions="['This backup will be permanently deleted from local storage.']" confirmationText="{{ data_get($execution, 'filename') }}"
|
:actions="['This backup will be permanently deleted from local storage.']" confirmationText="{{ data_get($execution, 'filename') }}"
|
||||||
confirmationLabel="Please confirm the execution of the actions by entering the Backup Filename below"
|
confirmationLabel="Please confirm the execution of the actions by entering the Backup Filename below"
|
||||||
shortConfirmationLabel="Backup Filename" step3ButtonText="Permanently Delete" />
|
shortConfirmationLabel="Backup Filename" step3ButtonText="Confirm" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@empty
|
@empty
|
||||||
|
@@ -11,11 +11,11 @@
|
|||||||
buttonTitle="Convert to Application" submitAction="convertToApplication" :actions="['The selected resource will be converted to an application.']"
|
buttonTitle="Convert to Application" submitAction="convertToApplication" :actions="['The selected resource will be converted to an application.']"
|
||||||
confirmationText="{{ Str::headline($database->name) }}"
|
confirmationText="{{ Str::headline($database->name) }}"
|
||||||
confirmationLabel="Please confirm the execution of the actions by entering the Service Database Name below"
|
confirmationLabel="Please confirm the execution of the actions by entering the Service Database Name below"
|
||||||
shortConfirmationLabel="Service Database Name" step3ButtonText="Permanently Delete" />
|
shortConfirmationLabel="Service Database Name" step3ButtonText="Confirm" />
|
||||||
<x-modal-confirmation title="Confirm Service Database Deletion?" buttonTitle="Delete" isErrorButton
|
<x-modal-confirmation title="Confirm Service Database Deletion?" buttonTitle="Delete" isErrorButton
|
||||||
submitAction="delete" :actions="['The selected service database container will be stopped and permanently deleted.']" confirmationText="{{ Str::headline($database->name) }}"
|
submitAction="delete" :actions="['The selected service database container will be stopped and permanently deleted.']" confirmationText="{{ Str::headline($database->name) }}"
|
||||||
confirmationLabel="Please confirm the execution of the actions by entering the Service Database Name below"
|
confirmationLabel="Please confirm the execution of the actions by entering the Service Database Name below"
|
||||||
shortConfirmationLabel="Service Database Name" step3ButtonText="Permanently Delete" />
|
shortConfirmationLabel="Service Database Name" step3ButtonText="Confirm" />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col gap-2">
|
<div class="flex flex-col gap-2">
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
|
@@ -21,7 +21,7 @@
|
|||||||
]"
|
]"
|
||||||
confirmationText="{{ $fs_path }}"
|
confirmationText="{{ $fs_path }}"
|
||||||
confirmationLabel="Please confirm the execution of the actions by entering the Filepath below"
|
confirmationLabel="Please confirm the execution of the actions by entering the Filepath below"
|
||||||
shortConfirmationLabel="Filepath" step3ButtonText="Permanently Delete" />
|
shortConfirmationLabel="Filepath" step3ButtonText="Confirm" />
|
||||||
@else
|
@else
|
||||||
@if (!$fileStorage->is_binary)
|
@if (!$fileStorage->is_binary)
|
||||||
<x-modal-confirmation :ignoreWire="false" title="Confirm File Conversion to Directory?"
|
<x-modal-confirmation :ignoreWire="false" title="Confirm File Conversion to Directory?"
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
isErrorButton submitAction="delete" :checkboxes="$fileDeletionCheckboxes" :actions="['The selected file will be permanently deleted from the container.']"
|
isErrorButton submitAction="delete" :checkboxes="$fileDeletionCheckboxes" :actions="['The selected file will be permanently deleted from the container.']"
|
||||||
confirmationText="{{ $fs_path }}"
|
confirmationText="{{ $fs_path }}"
|
||||||
confirmationLabel="Please confirm the execution of the actions by entering the Filepath below"
|
confirmationLabel="Please confirm the execution of the actions by entering the Filepath below"
|
||||||
shortConfirmationLabel="Filepath" step3ButtonText="Permanently Delete" />
|
shortConfirmationLabel="Filepath" step3ButtonText="Confirm" />
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
@if (!$fileStorage->is_directory)
|
@if (!$fileStorage->is_directory)
|
||||||
|
@@ -11,11 +11,11 @@
|
|||||||
buttonTitle="Convert to Database" submitAction="convertToDatabase" :actions="['The selected resource will be converted to a service database.']"
|
buttonTitle="Convert to Database" submitAction="convertToDatabase" :actions="['The selected resource will be converted to a service database.']"
|
||||||
confirmationText="{{ Str::headline($application->name) }}"
|
confirmationText="{{ Str::headline($application->name) }}"
|
||||||
confirmationLabel="Please confirm the execution of the actions by entering the Service Application Name below"
|
confirmationLabel="Please confirm the execution of the actions by entering the Service Application Name below"
|
||||||
shortConfirmationLabel="Service Application Name" step3ButtonText="Permanently Delete" />
|
shortConfirmationLabel="Service Application Name" step3ButtonText="Confirm" />
|
||||||
<x-modal-confirmation title="Confirm Service Application Deletion?" buttonTitle="Delete" isErrorButton
|
<x-modal-confirmation title="Confirm Service Application Deletion?" buttonTitle="Delete" isErrorButton
|
||||||
submitAction="delete" :actions="['The selected service application container will be stopped and permanently deleted.']" confirmationText="{{ Str::headline($application->name) }}"
|
submitAction="delete" :actions="['The selected service application container will be stopped and permanently deleted.']" confirmationText="{{ Str::headline($application->name) }}"
|
||||||
confirmationLabel="Please confirm the execution of the actions by entering the Service Application Name below"
|
confirmationLabel="Please confirm the execution of the actions by entering the Service Application Name below"
|
||||||
shortConfirmationLabel="Service Application Name" step3ButtonText="Permanently Delete" />
|
shortConfirmationLabel="Service Application Name" step3ButtonText="Confirm" />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col gap-2">
|
<div class="flex flex-col gap-2">
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
|
@@ -7,5 +7,5 @@
|
|||||||
<x-modal-confirmation title="Confirm Resource Deletion?" buttonTitle="Delete" isErrorButton submitAction="delete"
|
<x-modal-confirmation title="Confirm Resource Deletion?" buttonTitle="Delete" isErrorButton submitAction="delete"
|
||||||
buttonTitle="Delete" :checkboxes="$checkboxes" :actions="['Permanently delete all containers of this resource.']" confirmationText="{{ $resourceName }}"
|
buttonTitle="Delete" :checkboxes="$checkboxes" :actions="['Permanently delete all containers of this resource.']" confirmationText="{{ $resourceName }}"
|
||||||
confirmationLabel="Please confirm the execution of the actions by entering the Resource Name below"
|
confirmationLabel="Please confirm the execution of the actions by entering the Resource Name below"
|
||||||
shortConfirmationLabel="Resource Name" step3ButtonText="Permanently Delete" />
|
shortConfirmationLabel="Resource Name" step3ButtonText="Confirm" />
|
||||||
</div>
|
</div>
|
||||||
|
@@ -70,7 +70,7 @@
|
|||||||
'This will stop the all running applications on this server and remove it as a deployment destination.',
|
'This will stop the all running applications on this server and remove it as a deployment destination.',
|
||||||
]" confirmationText="{{ data_get($destination, 'server.name') }}"
|
]" confirmationText="{{ data_get($destination, 'server.name') }}"
|
||||||
confirmationLabel="Please confirm the execution of the actions by entering the Server Name below"
|
confirmationLabel="Please confirm the execution of the actions by entering the Server Name below"
|
||||||
shortConfirmationLabel="Server Name" step3ButtonText="Remove application from server" />
|
shortConfirmationLabel="Server Name" step3ButtonText="Confirm" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@endforeach
|
@endforeach
|
||||||
|
@@ -60,7 +60,7 @@
|
|||||||
'If the persistent storage/volume is actvily used by a resource data will be lost.',
|
'If the persistent storage/volume is actvily used by a resource data will be lost.',
|
||||||
]" confirmationText="{{ $storage->name }}"
|
]" confirmationText="{{ $storage->name }}"
|
||||||
confirmationLabel="Please confirm the execution of the actions by entering the Storage Name below"
|
confirmationLabel="Please confirm the execution of the actions by entering the Storage Name below"
|
||||||
shortConfirmationLabel="Storage Name" step3ButtonText="Permanently Delete" />
|
shortConfirmationLabel="Storage Name" step3ButtonText="Confirm" />
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
</form>
|
</form>
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
<div>
|
<div>
|
||||||
<x-security.navbar />
|
<x-security.navbar />
|
||||||
|
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
<h2 class="pb-4">Private Keys</h2>
|
<h2 class="pb-4">Private Keys</h2>
|
||||||
<x-modal-input buttonTitle="+ Add" title="New Private Key">
|
<x-modal-input buttonTitle="+ Add" title="New Private Key">
|
||||||
@@ -9,18 +8,19 @@
|
|||||||
<x-modal-confirmation title="Confirm unused SSH Key Deletion?" buttonTitle="Delete unused SSH Keys" isErrorButton
|
<x-modal-confirmation title="Confirm unused SSH Key Deletion?" buttonTitle="Delete unused SSH Keys" isErrorButton
|
||||||
submitAction="cleanupUnusedKeys" :actions="['All unused SSH keys (marked with unused) are permanently deleted.']" :confirmWithText="false" :confirmWithPassword="false" />
|
submitAction="cleanupUnusedKeys" :actions="['All unused SSH keys (marked with unused) are permanently deleted.']" :confirmWithText="false" :confirmWithPassword="false" />
|
||||||
</div>
|
</div>
|
||||||
<div class="grid gap-2 lg:grid-cols-2">
|
<div class="grid gap-4 lg:grid-cols-2">
|
||||||
@forelse ($privateKeys as $key)
|
@forelse ($privateKeys as $key)
|
||||||
<a class="box group"
|
<a class="box group"
|
||||||
href="{{ route('security.private-key.show', ['private_key_uuid' => data_get($key, 'uuid')]) }}">
|
href="{{ route('security.private-key.show', ['private_key_uuid' => data_get($key, 'uuid')]) }}">
|
||||||
<div class="flex flex-col mx-6">
|
<div class="flex flex-col justify-center mx-6">
|
||||||
<div class="box-title">
|
<div class="box-title">
|
||||||
{{ data_get($key, 'name') }}
|
{{ data_get($key, 'name') }}
|
||||||
</div>
|
</div>
|
||||||
<div class="box-description">
|
<div class="box-description">
|
||||||
{{ $key->description }}
|
{{ $key->description }}
|
||||||
@if (!$key->isInUse())
|
@if (!$key->isInUse())
|
||||||
<span class="inline-flex items-center px-2 py-0.5 rounded-sm text-xs font-medium bg-yellow-400 text-black">Unused</span>
|
<span
|
||||||
|
class="inline-flex items-center px-2 py-0.5 rounded-sm text-xs font-medium bg-yellow-400 text-black">Unused</span>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@@ -4,56 +4,58 @@
|
|||||||
</x-slot>
|
</x-slot>
|
||||||
<x-security.navbar />
|
<x-security.navbar />
|
||||||
<div x-data="{ showPrivateKey: false }">
|
<div x-data="{ showPrivateKey: false }">
|
||||||
<form class="flex flex-col gap-2" wire:submit='changePrivateKey'>
|
<form class="flex flex-col" wire:submit='changePrivateKey'>
|
||||||
<div class="flex items-end gap-2">
|
<div class="flex items-start gap-2">
|
||||||
<h2>Private Key</h2>
|
<h2 class="pb-4">Private Key</h2>
|
||||||
<x-forms.button type="submit">
|
<x-forms.button type="submit">
|
||||||
Save
|
Save
|
||||||
</x-forms.button>
|
</x-forms.button>
|
||||||
@if (data_get($private_key, 'id') > 0)
|
@if (data_get($private_key, 'id') > 0)
|
||||||
<x-modal-confirmation
|
<x-modal-confirmation title="Confirm Private Key Deletion?" isErrorButton buttonTitle="Delete"
|
||||||
title="Confirm Private Key Deletion?"
|
submitAction="delete({{ $private_key->id }})" :actions="[
|
||||||
isErrorButton
|
'This private key will be permanently deleted.',
|
||||||
buttonTitle="Delete"
|
'All servers connected to this private key will stop working.',
|
||||||
submitAction="delete({{ $private_key->id }})"
|
'Any git app using this private key will stop working.',
|
||||||
:actions="['This private key will be permanently deleted.', 'All servers connected to this private key will stop working.', 'Any git app using this private key will stop working.']"
|
]"
|
||||||
confirmationText="{{ $private_key->name }}"
|
confirmationText="{{ $private_key->name }}"
|
||||||
confirmationLabel="Please confirm the execution of the actions by entering the Private Key Name below"
|
confirmationLabel="Please confirm the execution of the actions by entering the Private Key Name below"
|
||||||
shortConfirmationLabel="Private Key Name"
|
shortConfirmationLabel="Private Key Name" :confirmWithPassword="false"
|
||||||
:confirmWithPassword="false"
|
step2ButtonText="Delete Private Key" />
|
||||||
step2ButtonText="Delete Private Key"
|
|
||||||
/>
|
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
<x-forms.input id="private_key.name" label="Name" required />
|
<div class="flex flex-col gap-2">
|
||||||
<x-forms.input id="private_key.description" label="Description" />
|
<div class="flex gap-2">
|
||||||
<div>
|
<x-forms.input id="private_key.name" label="Name" required />
|
||||||
<div class="flex items-end gap-2 py-2 ">
|
<x-forms.input id="private_key.description" label="Description" />
|
||||||
<div class="pl-1 ">Public Key</div>
|
|
||||||
</div>
|
</div>
|
||||||
<x-forms.input readonly id="public_key" />
|
<div>
|
||||||
<div class="flex items-end gap-2 py-2 ">
|
<div class="flex items-end gap-2 py-2 ">
|
||||||
<div class="pl-1 ">Private Key <span class='text-helper'>*</span></div>
|
<div class="pl-1">Public Key</div>
|
||||||
<div class="text-xs underline cursor-pointer dark:text-white" x-cloak x-show="!showPrivateKey"
|
|
||||||
x-on:click="showPrivateKey = true">
|
|
||||||
Edit
|
|
||||||
</div>
|
</div>
|
||||||
<div class="text-xs underline cursor-pointer dark:text-white" x-cloak x-show="showPrivateKey"
|
<x-forms.input readonly id="public_key" />
|
||||||
x-on:click="showPrivateKey = false">
|
<div class="flex items-end gap-2 py-2 ">
|
||||||
Hide
|
<div class="pl-1">Private Key <span class='text-helper'>*</span></div>
|
||||||
|
<div class="text-xs underline cursor-pointer dark:text-white" x-cloak x-show="!showPrivateKey"
|
||||||
|
x-on:click="showPrivateKey = true">
|
||||||
|
Edit
|
||||||
|
</div>
|
||||||
|
<div class="text-xs underline cursor-pointer dark:text-white" x-cloak x-show="showPrivateKey"
|
||||||
|
x-on:click="showPrivateKey = false">
|
||||||
|
Hide
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
@if (data_get($private_key, 'is_git_related'))
|
||||||
@if (data_get($private_key, 'is_git_related'))
|
<div class="w-48">
|
||||||
<div class="w-48">
|
<x-forms.checkbox id="private_key.is_git_related" disabled label="Is used by a Git App?" />
|
||||||
<x-forms.checkbox id="private_key.is_git_related" disabled label="Is used by a Git App?" />
|
</div>
|
||||||
|
@endif
|
||||||
|
<div x-cloak x-show="!showPrivateKey">
|
||||||
|
<x-forms.input allowToPeak="false" type="password" rows="10" id="private_key.private_key"
|
||||||
|
required disabled />
|
||||||
|
</div>
|
||||||
|
<div x-cloak x-show="showPrivateKey">
|
||||||
|
<x-forms.textarea rows="10" id="private_key.private_key" required />
|
||||||
</div>
|
</div>
|
||||||
@endif
|
|
||||||
<div x-cloak x-show="!showPrivateKey">
|
|
||||||
<x-forms.input allowToPeak="false" type="password" rows="10" id="private_key.private_key"
|
|
||||||
required disabled />
|
|
||||||
</div>
|
|
||||||
<div x-cloak x-show="showPrivateKey">
|
|
||||||
<x-forms.textarea rows="10" id="private_key.private_key" required />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
@@ -42,8 +42,7 @@
|
|||||||
]"
|
]"
|
||||||
confirmationText="DISABLE CLOUDFLARE TUNNEL"
|
confirmationText="DISABLE CLOUDFLARE TUNNEL"
|
||||||
confirmationLabel="Please type the confirmation text to disable Cloudflare Tunnel."
|
confirmationLabel="Please type the confirmation text to disable Cloudflare Tunnel."
|
||||||
shortConfirmationLabel="Confirmation text"
|
shortConfirmationLabel="Confirmation text" step3ButtonText="Confirm" />
|
||||||
step3ButtonText="Disable Cloudflare Tunnel" />
|
|
||||||
@else
|
@else
|
||||||
<x-modal-confirmation title="Disable Cloudflare Tunnel?"
|
<x-modal-confirmation title="Disable Cloudflare Tunnel?"
|
||||||
buttonTitle="Disable Cloudflare Tunnel" isErrorButton
|
buttonTitle="Disable Cloudflare Tunnel" isErrorButton
|
||||||
@@ -55,8 +54,7 @@
|
|||||||
]"
|
]"
|
||||||
confirmationText="DISABLE CLOUDFLARE TUNNEL"
|
confirmationText="DISABLE CLOUDFLARE TUNNEL"
|
||||||
confirmationLabel="Please type the confirmation text to disable Cloudflare Tunnel."
|
confirmationLabel="Please type the confirmation text to disable Cloudflare Tunnel."
|
||||||
shortConfirmationLabel="Confirmation text"
|
shortConfirmationLabel="Confirmation text" step3ButtonText="Confirm" />
|
||||||
step3ButtonText="Disable Cloudflare Tunnel" />
|
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@@ -18,12 +18,12 @@
|
|||||||
<x-modal-confirmation title="Confirm Server Deletion?" isErrorButton buttonTitle="Delete"
|
<x-modal-confirmation title="Confirm Server Deletion?" isErrorButton buttonTitle="Delete"
|
||||||
submitAction="delete" :actions="['This server will be permanently deleted.']" confirmationText="{{ $server->name }}"
|
submitAction="delete" :actions="['This server will be permanently deleted.']" confirmationText="{{ $server->name }}"
|
||||||
confirmationLabel="Please confirm the execution of the actions by entering the Server Name below"
|
confirmationLabel="Please confirm the execution of the actions by entering the Server Name below"
|
||||||
shortConfirmationLabel="Server Name" step3ButtonText="Permanently Delete" />
|
shortConfirmationLabel="Server Name" step3ButtonText="Confirm" />
|
||||||
@else
|
@else
|
||||||
<x-modal-confirmation title="Confirm Server Deletion?" isErrorButton buttonTitle="Delete"
|
<x-modal-confirmation title="Confirm Server Deletion?" isErrorButton buttonTitle="Delete"
|
||||||
submitAction="delete" :actions="['This server will be permanently deleted.']" confirmationText="{{ $server->name }}"
|
submitAction="delete" :actions="['This server will be permanently deleted.']" confirmationText="{{ $server->name }}"
|
||||||
confirmationLabel="Please confirm the execution of the actions by entering the Server Name below"
|
confirmationLabel="Please confirm the execution of the actions by entering the Server Name below"
|
||||||
shortConfirmationLabel="Server Name" step3ButtonText="Permanently Delete" />
|
shortConfirmationLabel="Server Name" step3ButtonText="Confirm" />
|
||||||
@endif
|
@endif
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
@@ -9,15 +9,11 @@
|
|||||||
</x-modal-input>
|
</x-modal-input>
|
||||||
</div>
|
</div>
|
||||||
<div class="subtitle">All your servers are here.</div>
|
<div class="subtitle">All your servers are here.</div>
|
||||||
<div class="grid gap-2 lg:grid-cols-2">
|
<div class="grid gap-4 lg:grid-cols-2">
|
||||||
@forelse ($servers as $server)
|
@forelse ($servers as $server)
|
||||||
<a href="{{ route('server.show', ['server_uuid' => data_get($server, 'uuid')]) }}"
|
<a href="{{ route('server.show', ['server_uuid' => data_get($server, 'uuid')]) }}"
|
||||||
@class([
|
@class([
|
||||||
'gap-2 border cursor-pointer box group',
|
'gap-2 border cursor-pointer box group',
|
||||||
'border-transparent' =>
|
|
||||||
$server->settings->is_reachable &&
|
|
||||||
$server->settings->is_usable &&
|
|
||||||
!$server->settings->force_disabled,
|
|
||||||
'border-red-500' =>
|
'border-red-500' =>
|
||||||
!$server->settings->is_reachable || $server->settings->force_disabled,
|
!$server->settings->is_reachable || $server->settings->force_disabled,
|
||||||
])>
|
])>
|
||||||
|
79
resources/views/livewire/settings/advanced.blade.php
Normal file
79
resources/views/livewire/settings/advanced.blade.php
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
<div>
|
||||||
|
<x-slot:title>
|
||||||
|
Advanced Settings | Coolify
|
||||||
|
</x-slot>
|
||||||
|
<x-settings.navbar />
|
||||||
|
<div x-data="{ activeTab: window.location.hash ? window.location.hash.substring(1) : 'general' }" class="flex flex-col h-full gap-8 sm:flex-row">
|
||||||
|
<x-settings.sidebar activeMenu="advanced" />
|
||||||
|
<form wire:submit='submit' class="flex flex-col">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<h2>Advanced</h2>
|
||||||
|
<x-forms.button type="submit">
|
||||||
|
Save
|
||||||
|
</x-forms.button>
|
||||||
|
</div>
|
||||||
|
<div class="pb-4">Advanced settings for your Coolify instance.</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col gap-1 md:w-96">
|
||||||
|
<x-forms.checkbox instantSave id="is_registration_enabled"
|
||||||
|
helper="If enabled, users can register themselves. If disabled, only administrators can create new users."
|
||||||
|
label="Registration Allowed" />
|
||||||
|
<x-forms.checkbox instantSave id="do_not_track"
|
||||||
|
helper="If enabled, Coolify will not track any data. This is useful if you are concerned about privacy."
|
||||||
|
label="Do Not Track" />
|
||||||
|
<h4 class="pt-4">DNS Settings</h4>
|
||||||
|
<x-forms.checkbox instantSave id="is_dns_validation_enabled"
|
||||||
|
helper="If you set a custom domain, Coolify will validate the domain in your DNS provider."
|
||||||
|
label="DNS Validation" />
|
||||||
|
<x-forms.input id="custom_dns_servers" label="Custom DNS Servers"
|
||||||
|
helper="DNS servers to validate domains against. A comma separated list of DNS servers."
|
||||||
|
placeholder="1.1.1.1,8.8.8.8" />
|
||||||
|
<h4 class="pt-4">API Settings</h4>
|
||||||
|
<x-forms.checkbox instantSave id="is_api_enabled" label="API Access"
|
||||||
|
helper="If enabled, the API will be enabled. If disabled, the API will be disabled." />
|
||||||
|
<x-forms.input id="allowed_ips" label="Allowed IPs for API Access"
|
||||||
|
helper="Allowed IP lists for the API. A comma separated list of IPs. Empty means you allow from everywhere."
|
||||||
|
placeholder="1.1.1.1,8.8.8.8" />
|
||||||
|
<h4 class="pt-4">Confirmation Settings</h4>
|
||||||
|
<div class="md:w-96 pb-1">
|
||||||
|
<x-forms.checkbox instantSave id="is_sponsorship_popup_enabled" label="Show Sponsorship Popup"
|
||||||
|
helper="When enabled, sponsorship popups will be shown monthly to users. When disabled, the sponsorship popup will be permanently hidden for all users." />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-1">
|
||||||
|
@if ($disable_two_step_confirmation)
|
||||||
|
<div class="md:w-96 pb-4" wire:key="two-step-confirmation-enabled">
|
||||||
|
<x-forms.checkbox instantSave id="disable_two_step_confirmation"
|
||||||
|
label="Disable Two Step Confirmation"
|
||||||
|
helper="When disabled, you will not need to confirm actions with a text and user password. This significantly reduces security and may lead to accidental deletions or unwanted changes. Use with extreme caution, especially on production servers." />
|
||||||
|
</div>
|
||||||
|
@else
|
||||||
|
<div class="md:w-96 pb-4 flex items-center justify-between gap-2"
|
||||||
|
wire:key="two-step-confirmation-disabled">
|
||||||
|
<label class="flex items-center gap-2">
|
||||||
|
Disable Two Step Confirmation
|
||||||
|
<x-helper
|
||||||
|
helper="When disabled, you will not need to confirm actions with a text and user password. This significantly reduces security and may lead to accidental deletions or unwanted changes. Use with extreme caution, especially on production servers.">
|
||||||
|
</x-helper>
|
||||||
|
</label>
|
||||||
|
<x-modal-confirmation title="Disable Two Step Confirmation?" buttonTitle="Disable" isErrorButton
|
||||||
|
submitAction="toggleTwoStepConfirmation" :actions="[
|
||||||
|
'Two Step confirmation will be disabled globally.',
|
||||||
|
'Disabling two step confirmation reduces security (as anyone can easily delete anything).',
|
||||||
|
'The risk of accidental actions will increase.',
|
||||||
|
]"
|
||||||
|
confirmationText="DISABLE TWO STEP CONFIRMATION"
|
||||||
|
confirmationLabel="Please type the confirmation text to disable two step confirmation."
|
||||||
|
shortConfirmationLabel="Confirmation text" step3ButtonText="Confirm" />
|
||||||
|
</div>
|
||||||
|
<div class="w-full px-4 py-2 mb-4 text-white rounded-xs border-l-4 border-red-500 bg-error">
|
||||||
|
<p class="font-bold">Warning!</p>
|
||||||
|
<p>Disabling two step confirmation reduces security (as anyone can easily delete anything) and
|
||||||
|
increases
|
||||||
|
the risk of accidental actions. This is not recommended for production servers.</p>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
@@ -3,159 +3,81 @@
|
|||||||
Settings | Coolify
|
Settings | Coolify
|
||||||
</x-slot>
|
</x-slot>
|
||||||
<x-settings.navbar />
|
<x-settings.navbar />
|
||||||
<form wire:submit='submit' class="flex flex-col">
|
<div x-data="{ activeTab: window.location.hash ? window.location.hash.substring(1) : 'general' }" class="flex flex-col h-full gap-8 sm:flex-row">
|
||||||
<div class="flex items-center gap-2 pb-2">
|
<x-settings.sidebar activeMenu="general" />
|
||||||
<h2>Configuration</h2>
|
<form wire:submit='submit' class="flex flex-col">
|
||||||
<x-forms.button type="submit">
|
<div class="flex items-center gap-2">
|
||||||
Save
|
<h2>General</h2>
|
||||||
</x-forms.button>
|
<x-forms.button type="submit">
|
||||||
</div>
|
Save
|
||||||
<div>General configuration for your Coolify instance.</div>
|
</x-forms.button>
|
||||||
|
</div>
|
||||||
|
<div class="pb-4">General configuration for your Coolify instance.</div>
|
||||||
|
|
||||||
<div class="flex flex-col gap-2">
|
<div class="flex flex-col gap-2">
|
||||||
<h4 class="pt-6">Instance Settings</h4>
|
<div class="flex flex-wrap items-end gap-2">
|
||||||
<div class="flex flex-wrap items-end gap-2">
|
<div class="flex gap-2 md:flex-row flex-col w-full">
|
||||||
<div class="flex gap-2 md:flex-row flex-col w-full">
|
<x-forms.input id="fqdn" label="Domain"
|
||||||
<x-forms.input id="fqdn" label="Instance's Domain"
|
helper="Enter the full domain name (FQDN) of the instance, including 'https://' if you want to secure the dashboard with HTTPS. Setting this will make the dashboard accessible via this domain, secured by HTTPS, instead of just the IP address."
|
||||||
helper="Enter the full domain name (FQDN) of the instance, including 'https://' if you want to secure the dashboard with HTTPS. Setting this will make the dashboard accessible via this domain, secured by HTTPS, instead of just the IP address."
|
placeholder="https://coolify.yourdomain.com" />
|
||||||
placeholder="https://coolify.yourdomain.com" />
|
<x-forms.input id="instance_name" label="Name" placeholder="Coolify"
|
||||||
<x-forms.input id="instance_name" label="Instance's Name" placeholder="Coolify" />
|
helper="Custom name for your Coolify instance, shown in the URL." />
|
||||||
<div class="w-full" x-data="{
|
<div class="w-full" x-data="{
|
||||||
open: false,
|
open: false,
|
||||||
search: '{{ $settings->instance_timezone ?: '' }}',
|
search: '{{ $settings->instance_timezone ?: '' }}',
|
||||||
timezones: @js($this->timezones),
|
timezones: @js($this->timezones),
|
||||||
placeholder: '{{ $settings->instance_timezone ? 'Search timezone...' : 'Select Server Timezone' }}',
|
placeholder: '{{ $settings->instance_timezone ? 'Search timezone...' : 'Select Server Timezone' }}',
|
||||||
init() {
|
init() {
|
||||||
this.$watch('search', value => {
|
this.$watch('search', value => {
|
||||||
if (value === '') {
|
if (value === '') {
|
||||||
this.open = true;
|
this.open = true;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}">
|
}">
|
||||||
<div class="flex items-center mb-1">
|
<div class="flex items-center mb-1">
|
||||||
<label for="instance_timezone">Instance
|
<label for="instance_timezone">Instance
|
||||||
Timezone</label>
|
Timezone</label>
|
||||||
<x-helper class="ml-2"
|
<x-helper class="ml-2"
|
||||||
helper="Timezone for the Coolify instance. This is used for the update check and automatic update frequency." />
|
helper="Timezone for the Coolify instance. This is used for the update check and automatic update frequency." />
|
||||||
</div>
|
|
||||||
<div class="relative">
|
|
||||||
<div class="inline-flex relative items-center w-full">
|
|
||||||
<input autocomplete="off"
|
|
||||||
wire:dirty.class.remove='dark:focus:ring-coolgray-300 dark:ring-coolgray-300'
|
|
||||||
wire:dirty.class="dark:focus:ring-warning dark:ring-warning" x-model="search"
|
|
||||||
@focus="open = true" @click.away="open = false" @input="open = true"
|
|
||||||
class="w-full input" :placeholder="placeholder" wire:model="instance_timezone">
|
|
||||||
<svg class="absolute right-0 mr-2 w-4 h-4" xmlns="http://www.w3.org/2000/svg"
|
|
||||||
fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"
|
|
||||||
@click="open = true">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round"
|
|
||||||
d="M8.25 15L12 18.75 15.75 15m-7.5-6L12 5.25 15.75 9" />
|
|
||||||
</svg>
|
|
||||||
</div>
|
</div>
|
||||||
<div x-show="open"
|
<div class="relative">
|
||||||
class="overflow-auto overflow-x-hidden absolute z-50 mt-1 w-full max-h-60 bg-white rounded-md border shadow-lg dark:bg-coolgray-100 dark:border-coolgray-200 scrollbar">
|
<div class="inline-flex relative items-center w-full">
|
||||||
<template
|
<input autocomplete="off"
|
||||||
x-for="timezone in timezones.filter(tz => tz.toLowerCase().includes(search.toLowerCase()))"
|
wire:dirty.class.remove='dark:focus:ring-coolgray-300 dark:ring-coolgray-300'
|
||||||
:key="timezone">
|
wire:dirty.class="dark:focus:ring-warning dark:ring-warning" x-model="search"
|
||||||
<div @click="search = timezone; open = false; $wire.set('instance_timezone', timezone); $wire.submit()"
|
@focus="open = true" @click.away="open = false" @input="open = true"
|
||||||
class="px-4 py-2 text-gray-800 cursor-pointer hover:bg-gray-100 dark:hover:bg-coolgray-300 dark:text-gray-200"
|
class="w-full input" :placeholder="placeholder" wire:model="instance_timezone">
|
||||||
x-text="timezone"></div>
|
<svg class="absolute right-0 mr-2 w-4 h-4" xmlns="http://www.w3.org/2000/svg"
|
||||||
</template>
|
fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"
|
||||||
|
@click="open = true">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round"
|
||||||
|
d="M8.25 15L12 18.75 15.75 15m-7.5-6L12 5.25 15.75 9" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div x-show="open"
|
||||||
|
class="overflow-auto overflow-x-hidden absolute z-50 mt-1 w-full max-h-60 bg-white rounded-md border shadow-lg dark:bg-coolgray-100 dark:border-coolgray-200 scrollbar">
|
||||||
|
<template
|
||||||
|
x-for="timezone in timezones.filter(tz => tz.toLowerCase().includes(search.toLowerCase()))"
|
||||||
|
:key="timezone">
|
||||||
|
<div @click="search = timezone; open = false; $wire.set('instance_timezone', timezone); $wire.submit()"
|
||||||
|
class="px-4 py-2 text-gray-800 cursor-pointer hover:bg-gray-100 dark:hover:bg-coolgray-300 dark:text-gray-200"
|
||||||
|
x-text="timezone"></div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="flex gap-2 md:flex-row flex-col w-full">
|
||||||
|
<x-forms.input id="public_ipv4" type="password" label="Instance's Public IPv4"
|
||||||
|
helper="Enter the IPv4 address of the instance.<br><br>It is useful if you have several IPv4 addresses and Coolify could not detect the correct one."
|
||||||
|
placeholder="1.2.3.4" autocomplete="new-password" />
|
||||||
|
<x-forms.input id="public_ipv6" type="password" label="Instance's Public IPv6"
|
||||||
|
helper="Enter the IPv6 address of the instance.<br><br>It is useful if you have several IPv6 addresses and Coolify could not detect the correct one."
|
||||||
|
placeholder="2001:db8::1" autocomplete="new-password" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex gap-2 md:flex-row flex-col w-full">
|
|
||||||
<x-forms.input id="public_ipv4" type="password" label="Instance's IPv4"
|
|
||||||
helper="Enter the IPv4 address of the instance.<br><br>It is useful if you have several IPv4 addresses and Coolify could not detect the correct one."
|
|
||||||
placeholder="1.2.3.4" autocomplete="new-password" />
|
|
||||||
<x-forms.input id="public_ipv6" type="password" label="Instance's IPv6"
|
|
||||||
helper="Enter the IPv6 address of the instance.<br><br>It is useful if you have several IPv6 addresses and Coolify could not detect the correct one."
|
|
||||||
placeholder="2001:db8::1" autocomplete="new-password" />
|
|
||||||
</div>
|
|
||||||
<h4 class="w-full pt-6">DNS Validation</h4>
|
|
||||||
<div class="md:w-96">
|
|
||||||
<x-forms.checkbox instantSave id="is_dns_validation_enabled" label="Enabled" />
|
|
||||||
</div>
|
|
||||||
<x-forms.input id="custom_dns_servers" label="DNS Servers"
|
|
||||||
helper="DNS servers to validate FQDNs against. A comma separated list of DNS servers."
|
|
||||||
placeholder="1.1.1.1,8.8.8.8" />
|
|
||||||
</div>
|
</div>
|
||||||
|
</form>
|
||||||
{{-- <div class="flex gap-2 ">
|
</div>
|
||||||
<x-forms.input type="number" id="public_port_min" label="Public Port Min" />
|
|
||||||
<x-forms.input type="number" id="public_port_max" label="Public Port Max" />
|
|
||||||
</div> --}}
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<h4 class="pt-6">API</h4>
|
|
||||||
<div class="md:w-96 pb-2">
|
|
||||||
<x-forms.checkbox instantSave id="is_api_enabled" label="Enabled" />
|
|
||||||
</div>
|
|
||||||
<x-forms.input id="allowed_ips" label="Allowed IPs"
|
|
||||||
helper="Allowed IP lists for the API. A comma separated list of IPs. Empty means you allow from everywhere."
|
|
||||||
placeholder="1.1.1.1,8.8.8.8" />
|
|
||||||
<h4 class="pt-6">Update</h4>
|
|
||||||
<div class="text-right md:w-96 pb-4">
|
|
||||||
@if (!is_null(config('constants.coolify.autoupdate', null)))
|
|
||||||
<div class="text-right md:w-96">
|
|
||||||
<x-forms.checkbox instantSave helper="AUTOUPDATE is set in .env file, you need to modify it there."
|
|
||||||
disabled checked="{{ config('constants.coolify.autoupdate') }}" label="Auto Update Enabled" />
|
|
||||||
</div>
|
|
||||||
@else
|
|
||||||
<x-forms.checkbox instantSave id="is_auto_update_enabled" label="Auto Update Enabled" />
|
|
||||||
@endif
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-col gap-2">
|
|
||||||
<div class="flex items-end gap-2">
|
|
||||||
<x-forms.input required id="update_check_frequency" label="Update Check Frequency"
|
|
||||||
placeholder="0 * * * *"
|
|
||||||
helper="Cron expression for update check frequency (check for new Coolify versions and pull new Service Templates from CDN).<br>You can use every_minute, hourly, daily, weekly, monthly, yearly.<br><br>Default is every hour." />
|
|
||||||
<x-forms.button wire:click='checkManually'>Check Manually</x-forms.button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@if (is_null(config('constants.coolify.autoupdate', null)) && $is_auto_update_enabled)
|
|
||||||
<x-forms.input required id="auto_update_frequency" label="Auto Update Frequency" placeholder="0 0 * * *"
|
|
||||||
helper="Cron expression for auto update frequency (automatically update coolify).<br>You can use every_minute, hourly, daily, weekly, monthly, yearly.<br><br>Default is every day at 00:00" />
|
|
||||||
@endif
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h4 class="pt-6">Advanced</h4>
|
|
||||||
<div class="text-right md:w-96">
|
|
||||||
<x-forms.checkbox instantSave id="is_registration_enabled" label="Registration Allowed" />
|
|
||||||
<x-forms.checkbox instantSave id="do_not_track" label="Do Not Track" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h4 class="py-4">Confirmation Settings</h4>
|
|
||||||
<div class="md:w-96 ">
|
|
||||||
<x-forms.checkbox instantSave id="is_sponsorship_popup_enabled" label="Show Sponsorship Popup"
|
|
||||||
helper="When enabled, sponsorship popups will be shown monthly to users. When disabled, the sponsorship popup will be permanently hidden for all users." />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@if ($disable_two_step_confirmation)
|
|
||||||
<div class="md:w-96 pb-4" wire:key="two-step-confirmation-enabled">
|
|
||||||
<x-forms.checkbox instantSave id="disable_two_step_confirmation" label="Disable Two Step Confirmation"
|
|
||||||
helper="When disabled, you will not need to confirm actions with a text and user password. This significantly reduces security and may lead to accidental deletions or unwanted changes. Use with extreme caution, especially on production servers." />
|
|
||||||
</div>
|
|
||||||
@else
|
|
||||||
<div class="md:w-96 pb-4" wire:key="two-step-confirmation-disabled">
|
|
||||||
<x-modal-confirmation title="Disable Two Step Confirmation?"
|
|
||||||
buttonTitle="Disable Two Step Confirmation" isErrorButton submitAction="toggleTwoStepConfirmation"
|
|
||||||
:actions="[
|
|
||||||
'Two Step confirmation will be disabled globally.',
|
|
||||||
'Disabling two step confirmation reduces security (as anyone can easily delete anything).',
|
|
||||||
'The risk of accidental actions will increase.',
|
|
||||||
]" confirmationText="DISABLE TWO STEP CONFIRMATION"
|
|
||||||
confirmationLabel="Please type the confirmation text to disable two step confirmation."
|
|
||||||
shortConfirmationLabel="Confirmation text" step3ButtonText="Disable Two Step Confirmation" />
|
|
||||||
</div>
|
|
||||||
<div class="w-full px-4 py-2 mb-4 text-white rounded-xs border-l-4 border-red-500 bg-error">
|
|
||||||
<p class="font-bold">Warning!</p>
|
|
||||||
<p>Disabling two step confirmation reduces security (as anyone can easily delete anything) and
|
|
||||||
increases
|
|
||||||
the risk of accidental actions. This is not recommended for production servers.</p>
|
|
||||||
</div>
|
|
||||||
@endif
|
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
|
51
resources/views/livewire/settings/updates.blade.php
Normal file
51
resources/views/livewire/settings/updates.blade.php
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
<div>
|
||||||
|
<x-slot:title>
|
||||||
|
Auto Update | Coolify
|
||||||
|
</x-slot>
|
||||||
|
<x-settings.navbar />
|
||||||
|
<div x-data="{ activeTab: window.location.hash ? window.location.hash.substring(1) : 'general' }" class="flex flex-col h-full gap-8 sm:flex-row">
|
||||||
|
<x-settings.sidebar activeMenu="updates" />
|
||||||
|
<form wire:submit='submit' class="flex flex-col w-full">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<h2>Updates</h2>
|
||||||
|
<x-forms.button type="submit">
|
||||||
|
Save
|
||||||
|
</x-forms.button>
|
||||||
|
</div>
|
||||||
|
<div class="pb-4">Your instance's update settings.</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="flex flex-col gap-2">
|
||||||
|
<div class="flex items-end gap-2">
|
||||||
|
<x-forms.input required id="update_check_frequency" label="Update Check Frequency"
|
||||||
|
placeholder="0 * * * *"
|
||||||
|
helper="Frequency (cron expression) to check for new Coolify versions and pull new Service Templates from CDN.<br>You can use every_minute, hourly, daily, weekly, monthly, yearly.<br><br>Default is every hour." />
|
||||||
|
<x-forms.button wire:click='checkManually'>Check Manually</x-forms.button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h4 class="pt-4">Auto Update</h4>
|
||||||
|
|
||||||
|
<div class="text-right md:w-64">
|
||||||
|
@if (!is_null(config('constants.coolify.autoupdate', null)))
|
||||||
|
<div class="text-right">
|
||||||
|
<x-forms.checkbox instantSave
|
||||||
|
helper="AUTOUPDATE is set in .env file, you need to modify it there." disabled
|
||||||
|
checked="{{ config('constants.coolify.autoupdate') }}" label="Enabled" />
|
||||||
|
</div>
|
||||||
|
@else
|
||||||
|
<x-forms.checkbox instantSave id="is_auto_update_enabled" label="Enabled" />
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
@if (is_null(config('constants.coolify.autoupdate', null)) && $is_auto_update_enabled)
|
||||||
|
<x-forms.input required id="auto_update_frequency" label="Frequency (cron expression)"
|
||||||
|
placeholder="0 0 * * *"
|
||||||
|
helper="Frequency (cron expression) (automatically update coolify).<br>You can use every_minute, hourly, daily, weekly, monthly, yearly.<br><br>Default is every day at 00:00" />
|
||||||
|
@else
|
||||||
|
<x-forms.input required label="Frequency (cron expression)" disabled placeholder="disabled"
|
||||||
|
helper="Frequency (cron expression) (automatically update coolify).<br>You can use every_minute, hourly, daily, weekly, monthly, yearly.<br><br>Default is every day at 00:00" />
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
@@ -1,21 +1,28 @@
|
|||||||
<div>
|
<div>
|
||||||
<form class="flex flex-col gap-2 pb-6" wire:submit='submit'>
|
<form class="flex flex-col gap-2 pb-6" wire:submit='submit'>
|
||||||
<div class="flex items-start gap-2">
|
<div class="flex items-start gap-2">
|
||||||
<div class="pb-4">
|
<div class="">
|
||||||
<h1>Storage Details</h1>
|
<h1>Storage Details</h1>
|
||||||
<div class="subtitle">{{ $storage->name }}</div>
|
<div class="subtitle">{{ $storage->name }}</div>
|
||||||
@if ($storage->is_usable)
|
<div class="flex items-center gap-2 pb-4">
|
||||||
<div>Usable</div>
|
<div>Current Status:</div>
|
||||||
@else
|
@if ($storage->is_usable)
|
||||||
<div class="text-red-500">Not Usable</div>
|
<span
|
||||||
@endif
|
class="px-2 py-1 text-xs font-semibold text-green-800 bg-green-100 rounded dark:text-green-100 dark:bg-green-800">
|
||||||
|
Usable
|
||||||
|
</span>
|
||||||
|
@else
|
||||||
|
<span
|
||||||
|
class="px-2 py-1 text-xs font-semibold text-red-800 bg-red-100 rounded dark:text-red-100 dark:bg-red-800">
|
||||||
|
Not Usable
|
||||||
|
</span>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<x-forms.button type="submit">
|
<x-forms.button type="submit">
|
||||||
Save
|
Save
|
||||||
</x-forms.button>
|
</x-forms.button>
|
||||||
<x-forms.button wire:click="test_s3_connection">
|
|
||||||
Validate Connection
|
|
||||||
</x-forms.button>
|
|
||||||
<x-modal-confirmation title="Confirm Storage Deletion?" isErrorButton buttonTitle="Delete"
|
<x-modal-confirmation title="Confirm Storage Deletion?" isErrorButton buttonTitle="Delete"
|
||||||
submitAction="delete({{ $storage->id }})" :actions="[
|
submitAction="delete({{ $storage->id }})" :actions="[
|
||||||
'The selected storage location will be permanently deleted from Coolify.',
|
'The selected storage location will be permanently deleted from Coolify.',
|
||||||
@@ -37,5 +44,8 @@
|
|||||||
<x-forms.input required type="password" label="Access Key" id="storage.key" />
|
<x-forms.input required type="password" label="Access Key" id="storage.key" />
|
||||||
<x-forms.input required type="password" label="Secret Key" id="storage.secret" />
|
<x-forms.input required type="password" label="Secret Key" id="storage.secret" />
|
||||||
</div>
|
</div>
|
||||||
|
<x-forms.button class="mt-4" isHighlighted wire:click="testConnection">
|
||||||
|
Validate Connection
|
||||||
|
</x-forms.button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -9,10 +9,10 @@
|
|||||||
</x-modal-input>
|
</x-modal-input>
|
||||||
</div>
|
</div>
|
||||||
<div class="subtitle">S3 storages for backups.</div>
|
<div class="subtitle">S3 storages for backups.</div>
|
||||||
<div class="grid gap-2 lg:grid-cols-2">
|
<div class="grid gap-4 lg:grid-cols-2">
|
||||||
@forelse ($s3 as $storage)
|
@forelse ($s3 as $storage)
|
||||||
<a href="/storages/{{ $storage->uuid }}" @class(['gap-2 border cursor-pointer box group border-transparent'])>
|
<a href="/storages/{{ $storage->uuid }}" @class(['gap-2 border cursor-pointer box group'])>
|
||||||
<div class="flex flex-col mx-6">
|
<div class="flex flex-col justify-center mx-6">
|
||||||
<div class="box-title">
|
<div class="box-title">
|
||||||
{{ $storage->name }}
|
{{ $storage->name }}
|
||||||
</div>
|
</div>
|
||||||
@@ -20,7 +20,10 @@
|
|||||||
{{ $storage->description }}
|
{{ $storage->description }}
|
||||||
</div>
|
</div>
|
||||||
@if (!$storage->is_usable)
|
@if (!$storage->is_usable)
|
||||||
<div class="text-red-500">Not Usable</div>
|
<span
|
||||||
|
class="px-2 py-1 text-xs font-semibold text-red-800 bg-red-100 rounded dark:text-red-100 dark:bg-red-800">
|
||||||
|
Not Usable
|
||||||
|
</span>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
|
@@ -7,8 +7,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex flex-wrap gap-2 ">
|
<div class="flex flex-wrap gap-2 ">
|
||||||
@forelse ($tags as $oneTag)
|
@forelse ($tags as $oneTag)
|
||||||
<a :class="{{ $tag?->id == $oneTag->id }} && 'dark:bg-coollabs hover:bg-coollabs-100'"
|
<a :class="{{ $tag?->id == $oneTag->id }} && 'dark:bg-coollabs'"
|
||||||
class="w-64 box-without-bg dark:bg-coolgray-100 dark:text-white font-bold"
|
class="w-32 box-without-bg dark:bg-coolgray-100 dark:text-white font-bold dark:hover:bg-coollabs-100 flex justify-center items-center"
|
||||||
href="{{ route('tags.show', ['tagName' => $oneTag->name]) }}">{{ $oneTag->name }}</a>
|
href="{{ route('tags.show', ['tagName' => $oneTag->name]) }}">{{ $oneTag->name }}</a>
|
||||||
@empty
|
@empty
|
||||||
<div>No tags yet defined yet. Go to a resource and add a tag there.</div>
|
<div>No tags yet defined yet. Go to a resource and add a tag there.</div>
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
</div>
|
</div>
|
||||||
@if (isset($tag))
|
@if (isset($tag))
|
||||||
<div>
|
<div>
|
||||||
<h3 class="py-4">Details</h3>
|
<h3 class="py-4">Tag Details</h3>
|
||||||
<div class="flex items-end gap-2 ">
|
<div class="flex items-end gap-2 ">
|
||||||
<div class="w-[500px]">
|
<div class="w-[500px]">
|
||||||
<x-forms.input readonly label="Deploy Webhook URL" id="webhook" />
|
<x-forms.input readonly label="Deploy Webhook URL" id="webhook" />
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
@if (isset($applications) && count($applications) > 0)
|
@if (isset($applications) && count($applications) > 0)
|
||||||
@foreach ($applications as $application)
|
@foreach ($applications as $application)
|
||||||
<a href="{{ $application->link() }}" class="box group">
|
<a href="{{ $application->link() }}" class="box group">
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col justify-center">
|
||||||
<div class="box-title">
|
<div class="box-title">
|
||||||
{{ $application->project()->name }}/{{ $application->environment->name }}
|
{{ $application->project()->name }}/{{ $application->environment->name }}
|
||||||
</div>
|
</div>
|
||||||
|
@@ -3,12 +3,16 @@
|
|||||||
Team Admin | Coolify
|
Team Admin | Coolify
|
||||||
</x-slot>
|
</x-slot>
|
||||||
<x-team.navbar />
|
<x-team.navbar />
|
||||||
|
<h2>Admin View</h2>
|
||||||
|
<div class="subtitle">
|
||||||
|
Manage users of this instance.
|
||||||
|
</div>
|
||||||
<form wire:submit="submitSearch" class="flex flex-col gap-2 lg:flex-row">
|
<form wire:submit="submitSearch" class="flex flex-col gap-2 lg:flex-row">
|
||||||
<x-forms.input wire:model="search" placeholder="Search for a user" />
|
<x-forms.input wire:model="search" placeholder="Search for a user" />
|
||||||
<x-forms.button type="submit">Search</x-forms.button>
|
<x-forms.button type="submit">Search</x-forms.button>
|
||||||
</form>
|
</form>
|
||||||
<h3 class="pt-4">Users</h3>
|
<h3 class="py-4">Users</h3>
|
||||||
<div class="flex flex-col gap-2 ">
|
<div class="grid grid-cols-1 gap-2 lg:grid-cols-2">
|
||||||
@forelse ($users as $user)
|
@forelse ($users as $user)
|
||||||
<div wire:key="user-{{ $user->id }}"
|
<div wire:key="user-{{ $user->id }}"
|
||||||
class="flex items-center justify-center gap-2 bg-white box-without-bg dark:bg-coolgray-100">
|
class="flex items-center justify-center gap-2 bg-white box-without-bg dark:bg-coolgray-100">
|
||||||
@@ -23,7 +27,7 @@
|
|||||||
]"
|
]"
|
||||||
confirmationText="{{ $user->name }}"
|
confirmationText="{{ $user->name }}"
|
||||||
confirmationLabel="Please confirm the execution of the actions by entering the User Name below"
|
confirmationLabel="Please confirm the execution of the actions by entering the User Name below"
|
||||||
shortConfirmationLabel="User Name" step3ButtonText="Permanently Delete" />
|
shortConfirmationLabel="User Name" step3ButtonText="Confirm" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@empty
|
@empty
|
||||||
|
@@ -4,17 +4,19 @@
|
|||||||
</x-slot>
|
</x-slot>
|
||||||
<x-team.navbar />
|
<x-team.navbar />
|
||||||
|
|
||||||
<form class="flex flex-col gap-2 pb-6" wire:submit='submit'>
|
<form class="flex flex-col" wire:submit='submit'>
|
||||||
<div class="flex items-end gap-2">
|
<h2>General</h2>
|
||||||
<h2>General</h2>
|
<div class="subtitle">
|
||||||
|
Manage the general settings of this team.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex items-end gap-2 pb-6">
|
||||||
|
<x-forms.input id="team.name" label="Name" required />
|
||||||
|
<x-forms.input id="team.description" label="Description" />
|
||||||
<x-forms.button type="submit">
|
<x-forms.button type="submit">
|
||||||
Save
|
Save
|
||||||
</x-forms.button>
|
</x-forms.button>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex gap-2">
|
|
||||||
<x-forms.input id="team.name" label="Name" required />
|
|
||||||
<x-forms.input id="team.description" label="Description" />
|
|
||||||
</div>
|
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
@@ -4,7 +4,9 @@
|
|||||||
</x-slot>
|
</x-slot>
|
||||||
<x-team.navbar />
|
<x-team.navbar />
|
||||||
<h2>Members</h2>
|
<h2>Members</h2>
|
||||||
|
<div class="subtitle">
|
||||||
|
Manage or invite members of this team.
|
||||||
|
</div>
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<div class="overflow-x-auto">
|
<div class="overflow-x-auto">
|
||||||
@@ -38,8 +40,8 @@
|
|||||||
@else
|
@else
|
||||||
<h2>Invite New Member</h2>
|
<h2>Invite New Member</h2>
|
||||||
@if (isInstanceAdmin())
|
@if (isInstanceAdmin())
|
||||||
<div class="pb-4 text-xs dark:text-warning">You need to configure (as root team) <a href="/settings#smtp"
|
<div class="pb-4 text-xs dark:text-warning">You need to configure (as root team) <a
|
||||||
class="underline dark:text-warning">Transactional
|
href="/settings#smtp" class="underline dark:text-warning">Transactional
|
||||||
Emails</a>
|
Emails</a>
|
||||||
before
|
before
|
||||||
you can invite a
|
you can invite a
|
||||||
|
@@ -1,8 +0,0 @@
|
|||||||
<x-layout>
|
|
||||||
<x-security.navbar />
|
|
||||||
<a class="text-center hover:no-underline group" href="{{ route('security.private-key.index') }}">
|
|
||||||
<div class="dark:group-hover:text-white">
|
|
||||||
<div>Private Keys</div>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</x-layout>
|
|
@@ -8,25 +8,29 @@
|
|||||||
<livewire:source.github.create />
|
<livewire:source.github.create />
|
||||||
</x-modal-input>
|
</x-modal-input>
|
||||||
</div>
|
</div>
|
||||||
<div class="subtitle ">Git sources for your applications.</div>
|
<div class="subtitle">Git sources for your applications.</div>
|
||||||
<div class="grid gap-2 lg:grid-cols-2">
|
<div class="grid gap-4 lg:grid-cols-2">
|
||||||
@forelse ($sources as $source)
|
@forelse ($sources as $source)
|
||||||
@if ($source->getMorphClass() === 'App\Models\GithubApp')
|
@if ($source->getMorphClass() === 'App\Models\GithubApp')
|
||||||
<a class="flex gap-4 text-center hover:no-underline box group"
|
<a class="flex gap-2 text-center hover:no-underline box group"
|
||||||
href="{{ route('source.github.show', ['github_app_uuid' => data_get($source, 'uuid')]) }}">
|
href="{{ route('source.github.show', ['github_app_uuid' => data_get($source, 'uuid')]) }}">
|
||||||
<x-git-icon class="dark:text-white w-9 h-9" git="{{ $source->getMorphClass() }}" />
|
{{-- <x-git-icon class="dark:text-white w-8 h-8 mt-1" git="{{ $source->getMorphClass() }}" /> --}}
|
||||||
<div class="text-left dark:group-hover:text-white">
|
<div class="text-left dark:group-hover:text-white flex flex-col justify-center mx-6">
|
||||||
<div class="box-title">{{ $source->name }}</div>
|
<div class="box-title">{{ $source->name }}</div>
|
||||||
@if (is_null($source->app_id))
|
@if (is_null($source->app_id))
|
||||||
<span class="box-description text-error! ">Configuration is not finished.</span>
|
<span class="box-description text-error! ">Configuration is not finished.</span>
|
||||||
|
@else
|
||||||
|
@if ($source->organization)
|
||||||
|
<span class="box-description">Organization: {{ $source->organization }}</span>
|
||||||
|
@endif
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
@endif
|
@endif
|
||||||
@if ($source->getMorphClass() === 'App\Models\GitlabApp')
|
{{-- @if ($source->getMorphClass() === 'App\Models\GitlabApp')
|
||||||
<a class="flex gap-4 text-center hover:no-underline box group"
|
<a class="flex gap-4 text-center hover:no-underline box group"
|
||||||
href="{{ route('source.gitlab.show', ['gitlab_app_uuid' => data_get($source, 'uuid')]) }}">
|
href="{{ route('source.gitlab.show', ['gitlab_app_uuid' => data_get($source, 'uuid')]) }}">
|
||||||
<x-git-icon class="dark:text-white w-9 h-9" git="{{ $source->getMorphClass() }}" />
|
<x-git-icon class="dark:text-white w-8 h-8" git="{{ $source->getMorphClass() }}" />
|
||||||
<div class="text-left dark:group-hover:text-white">
|
<div class="text-left dark:group-hover:text-white">
|
||||||
<div>{{ $source->name }}</div>
|
<div>{{ $source->name }}</div>
|
||||||
@if (is_null($source->app_id))
|
@if (is_null($source->app_id))
|
||||||
@@ -34,7 +38,7 @@
|
|||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
@endif
|
@endif --}}
|
||||||
@empty
|
@empty
|
||||||
<div>
|
<div>
|
||||||
<div>No sources found.</div>
|
<div>No sources found.</div>
|
||||||
|
@@ -52,7 +52,9 @@ use App\Livewire\Server\Proxy\Show as ProxyShow;
|
|||||||
use App\Livewire\Server\Resources as ResourcesShow;
|
use App\Livewire\Server\Resources as ResourcesShow;
|
||||||
use App\Livewire\Server\Security\Patches;
|
use App\Livewire\Server\Security\Patches;
|
||||||
use App\Livewire\Server\Show as ServerShow;
|
use App\Livewire\Server\Show as ServerShow;
|
||||||
|
use App\Livewire\Settings\Advanced as SettingsAdvanced;
|
||||||
use App\Livewire\Settings\Index as SettingsIndex;
|
use App\Livewire\Settings\Index as SettingsIndex;
|
||||||
|
use App\Livewire\Settings\Updates as SettingsUpdates;
|
||||||
use App\Livewire\SettingsBackup;
|
use App\Livewire\SettingsBackup;
|
||||||
use App\Livewire\SettingsEmail;
|
use App\Livewire\SettingsEmail;
|
||||||
use App\Livewire\SettingsOauth;
|
use App\Livewire\SettingsOauth;
|
||||||
@@ -105,6 +107,9 @@ Route::middleware(['auth', 'verified'])->group(function () {
|
|||||||
Route::get('/subscription/new', SubscriptionIndex::class)->name('subscription.index');
|
Route::get('/subscription/new', SubscriptionIndex::class)->name('subscription.index');
|
||||||
|
|
||||||
Route::get('/settings', SettingsIndex::class)->name('settings.index');
|
Route::get('/settings', SettingsIndex::class)->name('settings.index');
|
||||||
|
Route::get('/settings/advanced', SettingsAdvanced::class)->name('settings.advanced');
|
||||||
|
Route::get('/settings/updates', SettingsUpdates::class)->name('settings.updates');
|
||||||
|
|
||||||
Route::get('/settings/backup', SettingsBackup::class)->name('settings.backup');
|
Route::get('/settings/backup', SettingsBackup::class)->name('settings.backup');
|
||||||
Route::get('/settings/email', SettingsEmail::class)->name('settings.email');
|
Route::get('/settings/email', SettingsEmail::class)->name('settings.email');
|
||||||
Route::get('/settings/oauth', SettingsOauth::class)->name('settings.oauth');
|
Route::get('/settings/oauth', SettingsOauth::class)->name('settings.oauth');
|
||||||
|
Reference in New Issue
Block a user