Merge branch 'next' into new-dockerfiles
This commit is contained in:
4
.gitattributes
vendored
4
.gitattributes
vendored
@@ -5,3 +5,7 @@
|
||||
*.html diff=html
|
||||
*.md diff=markdown
|
||||
*.php diff=php
|
||||
|
||||
/.github export-ignore
|
||||
CHANGELOG.md export-ignore
|
||||
.styleci.yml export-ignore
|
10
README.md
10
README.md
@@ -142,12 +142,10 @@ By subscribing to the cloud version, you get the Coolify server for the same pri
|
||||
|
||||
# Core Maintainers
|
||||
|
||||
<a href="https://github.com/andrasbacsai">
|
||||
<img src="https://github.com/andrasbacsai.png" width="60px" alt="andrasbacsai" />
|
||||
</a>
|
||||
<a href="https://github.com/peaklabs-dev">
|
||||
<img src="https://github.com/peaklabs-dev.png" width="60px" alt="peaklabs-dev" />
|
||||
</a>
|
||||
| Andras Bacsai | Peak |
|
||||
|------------|------------|
|
||||
| <img src="https://github.com/andrasbacsai.png" width="200px" alt="Andras Bacsai" /> | <img src="https://github.com/peaklabs-dev.png" width="200px" alt="Peak Labs" /> |
|
||||
| <a href="https://x.com/heyandras"><img src="https://raw.githubusercontent.com/gauravghongde/social-icons/master/SVG/Color/Twitter.svg" width="25px"></a> <a href="https://github.com/andrasbacsai"><img src="https://raw.githubusercontent.com/gauravghongde/social-icons/master/SVG/Color/Github.svg" width="25px"></a> | <a href="https://x.com/peaklabs_dev"><img src="https://raw.githubusercontent.com/gauravghongde/social-icons/master/SVG/Color/Twitter.svg" width="25px"></a> <a href="https://github.com/peaklabs-dev"><img src="https://raw.githubusercontent.com/gauravghongde/social-icons/master/SVG/Color/Github.svg" width="25px"></a> |
|
||||
|
||||
# Repo Activity
|
||||
|
||||
|
@@ -28,6 +28,8 @@ class Kernel extends ConsoleKernel
|
||||
{
|
||||
private $allServers;
|
||||
|
||||
private Schedule $scheduleInstance;
|
||||
|
||||
private InstanceSettings $settings;
|
||||
|
||||
private string $updateCheckFrequency;
|
||||
@@ -36,82 +38,90 @@ class Kernel extends ConsoleKernel
|
||||
|
||||
protected function schedule(Schedule $schedule): void
|
||||
{
|
||||
$this->scheduleInstance = $schedule;
|
||||
$this->allServers = Server::where('ip', '!=', '1.2.3.4');
|
||||
|
||||
$this->settings = instanceSettings();
|
||||
$this->updateCheckFrequency = $this->settings->update_check_frequency ?: '0 * * * *';
|
||||
|
||||
$this->instanceTimezone = $this->settings->instance_timezone ?: config('app.timezone');
|
||||
|
||||
$schedule->job(new CleanupStaleMultiplexedConnections)->hourly();
|
||||
if (validate_timezone($this->instanceTimezone) === false) {
|
||||
$this->instanceTimezone = config('app.timezone');
|
||||
}
|
||||
|
||||
$this->scheduleInstance->job(new CleanupStaleMultiplexedConnections)->hourly();
|
||||
|
||||
if (isDev()) {
|
||||
// Instance Jobs
|
||||
$schedule->command('horizon:snapshot')->everyMinute();
|
||||
$schedule->job(new CleanupInstanceStuffsJob)->everyMinute()->onOneServer();
|
||||
$schedule->job(new CheckHelperImageJob)->everyTenMinutes()->onOneServer();
|
||||
$this->scheduleInstance->command('horizon:snapshot')->everyMinute();
|
||||
$this->scheduleInstance->job(new CleanupInstanceStuffsJob)->everyMinute()->onOneServer();
|
||||
$this->scheduleInstance->job(new CheckHelperImageJob)->everyTenMinutes()->onOneServer();
|
||||
|
||||
// Server Jobs
|
||||
$this->checkResources($schedule);
|
||||
$this->checkResources();
|
||||
|
||||
$this->checkScheduledBackups($schedule);
|
||||
$this->checkScheduledTasks($schedule);
|
||||
$this->checkScheduledBackups();
|
||||
$this->checkScheduledTasks();
|
||||
|
||||
$schedule->command('uploads:clear')->everyTwoMinutes();
|
||||
$this->scheduleInstance->command('uploads:clear')->everyTwoMinutes();
|
||||
|
||||
} else {
|
||||
// Instance Jobs
|
||||
$schedule->command('horizon:snapshot')->everyFiveMinutes();
|
||||
$schedule->command('cleanup:unreachable-servers')->daily()->onOneServer();
|
||||
$schedule->job(new PullTemplatesFromCDN)->cron($this->updateCheckFrequency)->timezone($this->instanceTimezone)->onOneServer();
|
||||
$schedule->job(new CleanupInstanceStuffsJob)->everyTwoMinutes()->onOneServer();
|
||||
$this->scheduleUpdates($schedule);
|
||||
$this->scheduleInstance->command('horizon:snapshot')->everyFiveMinutes();
|
||||
$this->scheduleInstance->command('cleanup:unreachable-servers')->daily()->onOneServer();
|
||||
|
||||
$this->scheduleInstance->job(new PullTemplatesFromCDN)->cron($this->updateCheckFrequency)->timezone($this->instanceTimezone)->onOneServer();
|
||||
|
||||
$this->scheduleInstance->job(new CleanupInstanceStuffsJob)->everyTwoMinutes()->onOneServer();
|
||||
$this->scheduleUpdates();
|
||||
|
||||
// Server Jobs
|
||||
$this->checkResources($schedule);
|
||||
$this->checkResources();
|
||||
|
||||
$this->pullImages($schedule);
|
||||
$this->pullImages();
|
||||
|
||||
$this->checkScheduledBackups($schedule);
|
||||
$this->checkScheduledTasks($schedule);
|
||||
$this->checkScheduledBackups();
|
||||
$this->checkScheduledTasks();
|
||||
|
||||
$schedule->command('cleanup:database --yes')->daily();
|
||||
$schedule->command('uploads:clear')->everyTwoMinutes();
|
||||
$this->scheduleInstance->command('cleanup:database --yes')->daily();
|
||||
$this->scheduleInstance->command('uploads:clear')->everyTwoMinutes();
|
||||
}
|
||||
}
|
||||
|
||||
private function pullImages($schedule): void
|
||||
private function pullImages(): void
|
||||
{
|
||||
$servers = $this->allServers->whereRelation('settings', 'is_usable', true)->whereRelation('settings', 'is_reachable', true)->get();
|
||||
foreach ($servers as $server) {
|
||||
if ($server->isSentinelEnabled()) {
|
||||
$schedule->job(function () use ($server) {
|
||||
$this->scheduleInstance->job(function () use ($server) {
|
||||
CheckAndStartSentinelJob::dispatch($server);
|
||||
})->cron($this->updateCheckFrequency)->timezone($this->instanceTimezone)->onOneServer();
|
||||
}
|
||||
}
|
||||
$schedule->job(new CheckHelperImageJob)
|
||||
$this->scheduleInstance->job(new CheckHelperImageJob)
|
||||
->cron($this->updateCheckFrequency)
|
||||
->timezone($this->instanceTimezone)
|
||||
->onOneServer();
|
||||
}
|
||||
|
||||
private function scheduleUpdates($schedule): void
|
||||
private function scheduleUpdates(): void
|
||||
{
|
||||
$schedule->job(new CheckForUpdatesJob)
|
||||
$this->scheduleInstance->job(new CheckForUpdatesJob)
|
||||
->cron($this->updateCheckFrequency)
|
||||
->timezone($this->instanceTimezone)
|
||||
->onOneServer();
|
||||
|
||||
if ($this->settings->is_auto_update_enabled) {
|
||||
$autoUpdateFrequency = $this->settings->auto_update_frequency;
|
||||
$schedule->job(new UpdateCoolifyJob)
|
||||
$this->scheduleInstance->job(new UpdateCoolifyJob)
|
||||
->cron($autoUpdateFrequency)
|
||||
->timezone($this->instanceTimezone)
|
||||
->onOneServer();
|
||||
}
|
||||
}
|
||||
|
||||
private function checkResources($schedule): void
|
||||
private function checkResources(): void
|
||||
{
|
||||
if (isCloud()) {
|
||||
$servers = $this->allServers->whereHas('team.subscription')->get();
|
||||
@@ -128,31 +138,34 @@ class Kernel extends ConsoleKernel
|
||||
$lastSentinelUpdate = $server->sentinel_updated_at;
|
||||
if (Carbon::parse($lastSentinelUpdate)->isBefore(now()->subSeconds($server->waitBeforeDoingSshCheck()))) {
|
||||
// Check container status every minute if Sentinel does not activated
|
||||
$schedule->job(new ServerCheckJob($server))->everyMinute()->onOneServer();
|
||||
// $schedule->job(new \App\Jobs\ServerCheckNewJob($server))->everyMinute()->onOneServer();
|
||||
if (validate_timezone($serverTimezone) === false) {
|
||||
$serverTimezone = config('app.timezone');
|
||||
}
|
||||
$this->scheduleInstance->job(new ServerCheckJob($server))->timezone($serverTimezone)->everyMinute()->onOneServer();
|
||||
// $this->scheduleInstance->job(new \App\Jobs\ServerCheckNewJob($server))->everyMinute()->onOneServer();
|
||||
|
||||
// Check storage usage every 10 minutes if Sentinel does not activated
|
||||
$schedule->job(new ServerStorageCheckJob($server))->everyTenMinutes()->onOneServer();
|
||||
$this->scheduleInstance->job(new ServerStorageCheckJob($server))->everyTenMinutes()->onOneServer();
|
||||
}
|
||||
if ($server->settings->force_docker_cleanup) {
|
||||
$schedule->job(new DockerCleanupJob($server))->cron($server->settings->docker_cleanup_frequency)->timezone($serverTimezone)->onOneServer();
|
||||
$this->scheduleInstance->job(new DockerCleanupJob($server))->cron($server->settings->docker_cleanup_frequency)->timezone($serverTimezone)->onOneServer();
|
||||
} else {
|
||||
$schedule->job(new DockerCleanupJob($server))->everyTenMinutes()->timezone($serverTimezone)->onOneServer();
|
||||
$this->scheduleInstance->job(new DockerCleanupJob($server))->everyTenMinutes()->timezone($serverTimezone)->onOneServer();
|
||||
}
|
||||
|
||||
// Cleanup multiplexed connections every hour
|
||||
$schedule->job(new ServerCleanupMux($server))->hourly()->onOneServer();
|
||||
$this->scheduleInstance->job(new ServerCleanupMux($server))->hourly()->onOneServer();
|
||||
|
||||
// Temporary solution until we have better memory management for Sentinel
|
||||
if ($server->isSentinelEnabled()) {
|
||||
$schedule->job(function () use ($server) {
|
||||
$this->scheduleInstance->job(function () use ($server) {
|
||||
$server->restartContainer('coolify-sentinel');
|
||||
})->daily()->onOneServer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function checkScheduledBackups($schedule): void
|
||||
private function checkScheduledBackups(): void
|
||||
{
|
||||
$scheduled_backups = ScheduledDatabaseBackup::where('enabled', true)->get();
|
||||
if ($scheduled_backups->isEmpty()) {
|
||||
@@ -174,13 +187,13 @@ class Kernel extends ConsoleKernel
|
||||
if (isset(VALID_CRON_STRINGS[$scheduled_backup->frequency])) {
|
||||
$scheduled_backup->frequency = VALID_CRON_STRINGS[$scheduled_backup->frequency];
|
||||
}
|
||||
$schedule->job(new DatabaseBackupJob(
|
||||
$this->scheduleInstance->job(new DatabaseBackupJob(
|
||||
backup: $scheduled_backup
|
||||
))->cron($scheduled_backup->frequency)->timezone($this->instanceTimezone)->onOneServer();
|
||||
}
|
||||
}
|
||||
|
||||
private function checkScheduledTasks($schedule): void
|
||||
private function checkScheduledTasks(): void
|
||||
{
|
||||
$scheduled_tasks = ScheduledTask::where('enabled', true)->get();
|
||||
if ($scheduled_tasks->isEmpty()) {
|
||||
@@ -214,7 +227,7 @@ class Kernel extends ConsoleKernel
|
||||
if (isset(VALID_CRON_STRINGS[$scheduled_task->frequency])) {
|
||||
$scheduled_task->frequency = VALID_CRON_STRINGS[$scheduled_task->frequency];
|
||||
}
|
||||
$schedule->job(new ScheduledTaskJob(
|
||||
$this->scheduleInstance->job(new ScheduledTaskJob(
|
||||
task: $scheduled_task
|
||||
))->cron($scheduled_task->frequency)->timezone($this->instanceTimezone)->onOneServer();
|
||||
}
|
||||
|
@@ -26,7 +26,7 @@ class DockerCleanupJob implements ShouldBeEncrypted, ShouldQueue
|
||||
|
||||
public function middleware(): array
|
||||
{
|
||||
return [(new WithoutOverlapping($this->server->id))->dontRelease()];
|
||||
return [(new WithoutOverlapping($this->server->uuid))->dontRelease()];
|
||||
}
|
||||
|
||||
public function __construct(public Server $server, public bool $manualCleanup = false) {}
|
||||
|
@@ -28,7 +28,7 @@ class ServerCheckJob implements ShouldBeEncrypted, ShouldQueue
|
||||
|
||||
public function middleware(): array
|
||||
{
|
||||
return [(new WithoutOverlapping($this->server->id))->dontRelease()];
|
||||
return [(new WithoutOverlapping($this->server->uuid))->dontRelease()];
|
||||
}
|
||||
|
||||
public function __construct(public Server $server) {}
|
||||
|
@@ -127,7 +127,14 @@ class Show extends Component
|
||||
$this->server->settings->sentinel_custom_url = $this->sentinelCustomUrl;
|
||||
$this->server->settings->is_sentinel_enabled = $this->isSentinelEnabled;
|
||||
$this->server->settings->is_sentinel_debug_enabled = $this->isSentinelDebugEnabled;
|
||||
$this->server->settings->server_timezone = $this->serverTimezone;
|
||||
|
||||
if (! validate_timezone($this->serverTimezone)) {
|
||||
$this->serverTimezone = config('app.timezone');
|
||||
throw new \Exception('Invalid timezone.');
|
||||
} else {
|
||||
$this->server->settings->server_timezone = $this->serverTimezone;
|
||||
}
|
||||
|
||||
$this->server->settings->save();
|
||||
} else {
|
||||
$this->name = $this->server->name;
|
||||
|
@@ -139,6 +139,14 @@ class Index extends Component
|
||||
$error_show = false;
|
||||
$this->server = Server::findOrFail(0);
|
||||
$this->resetErrorBag();
|
||||
|
||||
if (! validate_timezone($this->instance_timezone)) {
|
||||
$this->instance_timezone = config('app.timezone');
|
||||
throw new \Exception('Invalid timezone.');
|
||||
} else {
|
||||
$this->settings->instance_timezone = $this->instance_timezone;
|
||||
}
|
||||
|
||||
if ($this->settings->public_port_min > $this->settings->public_port_max) {
|
||||
$this->addError('settings.public_port_min', 'The minimum port must be lower than the maximum port.');
|
||||
|
||||
|
@@ -394,7 +394,7 @@ function fqdnLabelsForTraefik(string $uuid, Collection $domains, bool $is_force_
|
||||
$middlewares->push('gzip');
|
||||
}
|
||||
if (str($image)->contains('ghost')) {
|
||||
$middlewares->push('redir-ghost');
|
||||
$middlewares->push("redir-ghost-{$uuid}");
|
||||
}
|
||||
if ($redirect_direction === 'non-www' && str($host)->startsWith('www.')) {
|
||||
$labels = $labels->merge($redirect_to_non_www);
|
||||
@@ -417,7 +417,7 @@ function fqdnLabelsForTraefik(string $uuid, Collection $domains, bool $is_force_
|
||||
$middlewares->push('gzip');
|
||||
}
|
||||
if (str($image)->contains('ghost')) {
|
||||
$middlewares->push('redir-ghost');
|
||||
$middlewares->push("redir-ghost-{$uuid}");
|
||||
}
|
||||
if ($redirect_direction === 'non-www' && str($host)->startsWith('www.')) {
|
||||
$labels = $labels->merge($redirect_to_non_www);
|
||||
@@ -466,7 +466,7 @@ function fqdnLabelsForTraefik(string $uuid, Collection $domains, bool $is_force_
|
||||
$middlewares->push('gzip');
|
||||
}
|
||||
if (str($image)->contains('ghost')) {
|
||||
$middlewares->push('redir-ghost');
|
||||
$middlewares->push("redir-ghost-{$uuid}");
|
||||
}
|
||||
if ($redirect_direction === 'non-www' && str($host)->startsWith('www.')) {
|
||||
$labels = $labels->merge($redirect_to_non_www);
|
||||
@@ -489,7 +489,7 @@ function fqdnLabelsForTraefik(string $uuid, Collection $domains, bool $is_force_
|
||||
$middlewares->push('gzip');
|
||||
}
|
||||
if (str($image)->contains('ghost')) {
|
||||
$middlewares->push('redir-ghost');
|
||||
$middlewares->push("redir-ghost-{$uuid}");
|
||||
}
|
||||
if ($redirect_direction === 'non-www' && str($host)->startsWith('www.')) {
|
||||
$labels = $labels->merge($redirect_to_non_www);
|
||||
|
@@ -385,6 +385,11 @@ function validate_cron_expression($expression_to_validate): bool
|
||||
|
||||
return $isValid;
|
||||
}
|
||||
|
||||
function validate_timezone(string $timezone): bool
|
||||
{
|
||||
return in_array($timezone, timezone_identifiers_list());
|
||||
}
|
||||
function send_internal_notification(string $message): void
|
||||
{
|
||||
try {
|
||||
|
@@ -74,8 +74,9 @@ services:
|
||||
networks:
|
||||
- coolify
|
||||
testing-host:
|
||||
image: "ghcr.io/coollabsio/coolify-testing-host:latest"
|
||||
pull_policy: always
|
||||
build:
|
||||
context: .
|
||||
dockerfile: ./docker/testing-host/Dockerfile
|
||||
init: true
|
||||
container_name: coolify-testing-host
|
||||
volumes:
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#!/command/execlineb -P
|
||||
foreground {
|
||||
s6-sleep 5
|
||||
su - www-data -c "php /var/www/html/artisan start:horizon"
|
||||
su - webuser -c "php /var/www/html/artisan start:horizon"
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#!/command/execlineb -P
|
||||
foreground {
|
||||
s6-sleep 5
|
||||
su - www-data -c "php /var/www/html/artisan start:scheduler"
|
||||
su - webuser -c "php /var/www/html/artisan start:scheduler"
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#!/command/execlineb -P
|
||||
foreground {
|
||||
s6-sleep 5
|
||||
su - www-data -c "php /var/www/html/artisan start:horizon"
|
||||
su - webuser -c "php /var/www/html/artisan start:horizon"
|
||||
}
|
||||
|
@@ -1,3 +1,3 @@
|
||||
#!/command/execlineb -P
|
||||
s6-setuidgid www-data
|
||||
s6-setuidgid webuser
|
||||
php /var/www/html/artisan app:init
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#!/command/execlineb -P
|
||||
foreground {
|
||||
s6-sleep 5
|
||||
su - www-data -c "php /var/www/html/artisan start:scheduler"
|
||||
su - webuser -c "php /var/www/html/artisan start:scheduler"
|
||||
}
|
||||
|
@@ -14,8 +14,8 @@
|
||||
'w-full' => $fullWidth,
|
||||
])>
|
||||
@if (!$hideLabel)
|
||||
<label @class(['flex gap-4 px-0 min-w-fit label', 'opacity-40' => $disabled])>
|
||||
<span class="flex gap-2">
|
||||
<label @class(['flex gap-4 items-center px-0 min-w-fit label w-full cursor-pointer', 'opacity-40' => $disabled])>
|
||||
<span class="flex flex-grow gap-2">
|
||||
@if ($label)
|
||||
{!! $label !!}
|
||||
@else
|
||||
@@ -25,11 +25,11 @@
|
||||
<x-helper :helper="$helper" />
|
||||
@endif
|
||||
</span>
|
||||
@endif
|
||||
<input @disabled($disabled) type="checkbox" {{ $attributes->merge(['class' => $defaultClass]) }}
|
||||
@if ($instantSave) wire:loading.attr="disabled" wire:click='{{ $instantSave === 'instantSave' || $instantSave == '1' ? 'instantSave' : $instantSave }}'
|
||||
wire:model={{ $id }} @else wire:model={{ $value ?? $id }} @endif />
|
||||
@if (!$hideLabel)
|
||||
</label>
|
||||
@endif
|
||||
<span class="flex-grow"></span>
|
||||
<input @disabled($disabled) type="checkbox" {{ $attributes->merge(['class' => $defaultClass]) }}
|
||||
@if ($instantSave) wire:loading.attr="disabled" wire:click='{{ $instantSave === 'instantSave' || $instantSave == '1' ? 'instantSave' : $instantSave }}'
|
||||
wire:model={{ $id }} @else wire:model={{ $value ?? $id }} @endif />
|
||||
|
||||
</div>
|
||||
|
@@ -28,7 +28,7 @@
|
||||
$disableTwoStepConfirmation = data_get(InstanceSettings::get(), 'disable_two_step_confirmation');
|
||||
@endphp
|
||||
|
||||
<div x-data="{
|
||||
<div wire:ignore x-data="{
|
||||
modalOpen: false,
|
||||
step: {{ empty($checkboxes) ? 2 : 1 }},
|
||||
initialStep: {{ empty($checkboxes) ? 2 : 1 }},
|
||||
@@ -106,8 +106,8 @@
|
||||
this.selectedActions.push(id);
|
||||
}
|
||||
}
|
||||
}" @keydown.escape.window="modalOpen = false; resetModal()" :class="{ 'z-40': modalOpen }"
|
||||
class="relative w-auto h-auto">
|
||||
}" @keydown.escape.window="modalOpen = false; resetModal()"
|
||||
:class="{ 'z-40': modalOpen }" class="relative w-auto h-auto">
|
||||
@if ($customButton)
|
||||
@if ($buttonFullWidth)
|
||||
<x-forms.button @click="modalOpen=true" class="w-full">
|
||||
@@ -302,7 +302,8 @@
|
||||
</x-forms.button>
|
||||
@endif
|
||||
<x-forms.button
|
||||
x-bind:disabled="!disableTwoStepConfirmation && confirmWithText && userConfirmationText !== confirmationText"
|
||||
x-bind:disabled="!disableTwoStepConfirmation && confirmWithText && userConfirmationText !==
|
||||
confirmationText"
|
||||
class="w-auto" isError
|
||||
@click="
|
||||
if (dispatchEvent) {
|
||||
@@ -337,11 +338,14 @@
|
||||
Your Password
|
||||
</label>
|
||||
<form @submit.prevent="false" @keydown.enter.prevent>
|
||||
<input type="text" name="username" autocomplete="username" value="{{ auth()->user()->email }}" style="display: none;">
|
||||
<input type="password" id="password-confirm-{{ $passwordConfirm }}" x-model="password"
|
||||
class="w-full input" placeholder="Enter your password" autocomplete="current-password">
|
||||
<input type="text" name="username" autocomplete="username"
|
||||
value="{{ auth()->user()->email }}" style="display: none;">
|
||||
<input type="password" id="password-confirm-{{ $passwordConfirm }}"
|
||||
x-model="password" class="w-full input" placeholder="Enter your password"
|
||||
autocomplete="current-password">
|
||||
</form>
|
||||
<p x-show="passwordError" x-text="passwordError" class="mt-1 text-sm text-red-500"></p>
|
||||
<p x-show="passwordError" x-text="passwordError" class="mt-1 text-sm text-red-500">
|
||||
</p>
|
||||
@error('password')
|
||||
<p class="mt-1 text-sm text-red-500">{{ $message }}</p>
|
||||
@enderror
|
||||
|
@@ -110,8 +110,7 @@
|
||||
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.debounce.300ms="serverTimezone">
|
||||
class="w-full input" :placeholder="placeholder" wire:model="serverTimezone">
|
||||
<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">
|
||||
@@ -124,7 +123,7 @@
|
||||
<template
|
||||
x-for="timezone in timezones.filter(tz => tz.toLowerCase().includes(search.toLowerCase()))"
|
||||
:key="timezone">
|
||||
<div @click="search = timezone; open = false; $wire.set('serverTimezone', timezone)"
|
||||
<div @click="search = timezone; open = false; $wire.set('serverTimezone', 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>
|
||||
|
@@ -40,14 +40,13 @@
|
||||
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 items-center relative w-full">
|
||||
<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.debounce.300ms="instance_timezone">
|
||||
<svg class="absolute right-0 w-4 h-4 mr-2" xmlns="http://www.w3.org/2000/svg"
|
||||
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"
|
||||
@@ -55,18 +54,17 @@
|
||||
</svg>
|
||||
</div>
|
||||
<div x-show="open"
|
||||
class="absolute z-50 w-full mt-1 bg-white dark:bg-coolgray-100 border dark:border-coolgray-200 rounded-md shadow-lg max-h-60 overflow-auto scrollbar overflow-x-hidden">
|
||||
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)"
|
||||
class="px-4 py-2 cursor-pointer hover:bg-gray-100 dark:hover:bg-coolgray-300 text-gray-800 dark:text-gray-200"
|
||||
<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 class="flex gap-2 md:flex-row flex-col w-full">
|
||||
<x-forms.input id="public_ipv4" type="password" label="Instance's IPv4"
|
||||
@@ -134,7 +132,9 @@
|
||||
<h4 class="py-4">Confirmation Settings</h4>
|
||||
<div x-data="{ open: false }" class="mb-32 md:w-[40rem]">
|
||||
<button type="button" @click.prevent="open = !open"
|
||||
class="flex items-center justify-between w-full p-4 bg-coolgray-100 hover:bg-coolgray-200 rounded-md">
|
||||
class="flex items-center justify-between w-full p-4 rounded-md
|
||||
dark:bg-coolgray-100 dark:hover:bg-coolgray-200
|
||||
bg-gray-100 hover:bg-gray-200">
|
||||
<span class="font-medium">Two-Step Confirmation Settings</span>
|
||||
<svg class="w-5 h-5 transition-transform" :class="{ 'rotate-180': open }" fill="none"
|
||||
stroke="currentColor" viewBox="0 0 24 24">
|
||||
|
@@ -33,7 +33,7 @@
|
||||
</x-forms.select>
|
||||
<x-forms.button type="submit">Connect</x-forms.button>
|
||||
</form>
|
||||
<livewire:project.shared.terminal />
|
||||
@endif
|
||||
<livewire:project.shared.terminal />
|
||||
</div>
|
||||
</div>
|
||||
|
10
scripts/run
10
scripts/run
@@ -32,14 +32,14 @@ function sync:bunny {
|
||||
}
|
||||
|
||||
function db:reset {
|
||||
bash spin exec -u www-data coolify php artisan migrate:fresh --seed
|
||||
bash spin exec -u webuser coolify php artisan migrate:fresh --seed
|
||||
}
|
||||
function db:reset-prod {
|
||||
bash spin exec -u www-data coolify php artisan migrate:fresh --force --seed --seeder=ProductionSeeder ||
|
||||
bash spin exec -u webuser coolify php artisan migrate:fresh --force --seed --seeder=ProductionSeeder ||
|
||||
php artisan migrate:fresh --force --seed --seeder=ProductionSeeder
|
||||
}
|
||||
function coolify {
|
||||
bash spin exec -u www-data coolify bash
|
||||
bash spin exec -u webuser coolify bash
|
||||
}
|
||||
|
||||
function coolify:root {
|
||||
@@ -58,7 +58,7 @@ function vite {
|
||||
}
|
||||
|
||||
function tinker {
|
||||
bash spin exec -u www-data coolify php artisan tinker
|
||||
bash spin exec -u webuser coolify php artisan tinker
|
||||
}
|
||||
|
||||
function default {
|
||||
@@ -66,4 +66,4 @@ function default {
|
||||
}
|
||||
|
||||
TIMEFORMAT="Task completed in %3lR"
|
||||
time "${@:-default}"
|
||||
time "${@:-default}"
|
Reference in New Issue
Block a user