mirror of
https://github.com/tiennm99/coolify.git
synced 2026-10-19 18:15:31 +00:00
feat(backups): add scheduled persistent volume backups
This commit is contained in:
1 parent
05dc2c65f6
commit
63961e0799
36 files changed
+3506
-31
No files matched your search
@@ -5,6 +5,13 @@
|
||||
<x-forms.button type="submit" class="w-full sm:w-auto">
|
||||
Save
|
||||
</x-forms.button>
|
||||
@if (!$backupEnabled)
|
||||
<x-forms.button type="button" wire:click="toggleEnabled" wire:loading.attr="disabled"
|
||||
wire:target="toggleEnabled" isHighlighted>Enable Backup</x-forms.button>
|
||||
@else
|
||||
<x-forms.button type="button" wire:click="toggleEnabled" wire:loading.attr="disabled"
|
||||
wire:target="toggleEnabled">Disable Backup</x-forms.button>
|
||||
@endif
|
||||
@if (str($status)->startsWith('running'))
|
||||
<x-forms.button wire:click='backupNow' class="w-full sm:w-auto">Backup Now</x-forms.button>
|
||||
@endif
|
||||
@@ -27,9 +34,11 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-full max-w-md pb-2">
|
||||
<x-forms.checkbox instantSave label="Backup Enabled" id="backupEnabled" />
|
||||
@if ($availableS3Storages->count() > 0)
|
||||
<x-forms.checkbox instantSave label="S3 Enabled" id="saveS3" />
|
||||
@elseif ($saveS3)
|
||||
<x-forms.checkbox instantSave label="S3 Enabled" id="saveS3"
|
||||
helper="The configured S3 storage is no longer available. Disable S3 backups or configure a usable S3 storage." />
|
||||
@else
|
||||
<x-forms.checkbox instantSave helper="No validated S3 storage available." label="S3 Enabled" id="saveS3"
|
||||
disabled />
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
@php
|
||||
$databasePageItems = [
|
||||
['label' => 'Configuration', 'route' => 'project.database.configuration', 'active' => request()->routeIs('project.database.configuration')],
|
||||
['label' => 'Logs', 'route' => 'project.database.logs', 'active' => request()->routeIs('project.database.logs')],
|
||||
['label' => 'Terminal', 'route' => 'project.database.command', 'active' => request()->routeIs('project.database.command'), 'navigate' => false, 'visible' => auth()->user()?->can('canAccessTerminal')],
|
||||
[
|
||||
'label' => 'Backups',
|
||||
'route' => 'project.database.backup.index',
|
||||
@@ -15,6 +13,8 @@
|
||||
'App\Models\StandaloneMariadb',
|
||||
]),
|
||||
],
|
||||
['label' => 'Logs', 'route' => 'project.database.logs', 'active' => request()->routeIs('project.database.logs')],
|
||||
['label' => 'Terminal', 'route' => 'project.database.command', 'active' => request()->routeIs('project.database.command'), 'navigate' => false, 'visible' => auth()->user()?->can('canAccessTerminal')],
|
||||
];
|
||||
|
||||
$databaseConfigurationItems = [
|
||||
@@ -190,16 +190,6 @@
|
||||
Configuration
|
||||
</a>
|
||||
|
||||
<a class="shrink-0 {{ request()->routeIs('project.database.logs') ? 'dark:text-white' : '' }}"
|
||||
href="{{ route('project.database.logs', $parameters) }}">
|
||||
Logs
|
||||
</a>
|
||||
@can('canAccessTerminal')
|
||||
<a class="shrink-0 {{ request()->routeIs('project.database.command') ? 'dark:text-white' : '' }}"
|
||||
href="{{ route('project.database.command', $parameters) }}">
|
||||
Terminal
|
||||
</a>
|
||||
@endcan
|
||||
@if (
|
||||
$database->getMorphClass() === 'App\Models\StandalonePostgresql' ||
|
||||
$database->getMorphClass() === 'App\Models\StandaloneMongodb' ||
|
||||
@@ -210,6 +200,16 @@
|
||||
Backups
|
||||
</a>
|
||||
@endif
|
||||
<a class="shrink-0 {{ request()->routeIs('project.database.logs') ? 'dark:text-white' : '' }}"
|
||||
href="{{ route('project.database.logs', $parameters) }}">
|
||||
Logs
|
||||
</a>
|
||||
@can('canAccessTerminal')
|
||||
<a class="shrink-0 {{ request()->routeIs('project.database.command') ? 'dark:text-white' : '' }}"
|
||||
href="{{ route('project.database.command', $parameters) }}">
|
||||
Terminal
|
||||
</a>
|
||||
@endcan
|
||||
</nav>
|
||||
|
||||
@if ($database->destination->server->isFunctional())
|
||||
|
||||
@@ -1,4 +1,15 @@
|
||||
<div>
|
||||
<div x-data="{
|
||||
search: '',
|
||||
backups: @js($database->scheduledBackups->map(fn ($backup) => [
|
||||
'name' => strtolower($database->name),
|
||||
'frequency' => strtolower($backup->frequency),
|
||||
])->values()),
|
||||
hasMatches() {
|
||||
const query = this.search.toLowerCase();
|
||||
|
||||
return this.backups.some((backup) => backup.name.includes(query) || backup.frequency.includes(query));
|
||||
},
|
||||
}">
|
||||
<div class="flex flex-col gap-2">
|
||||
@if ($database->is_migrated && blank($database->custom_type))
|
||||
<div>
|
||||
@@ -18,9 +29,16 @@
|
||||
</form>
|
||||
</div>
|
||||
@else
|
||||
<div class="max-w-md pb-4">
|
||||
<x-forms.input id="null" type="search" x-model="search"
|
||||
placeholder="Search by database name or frequency..." />
|
||||
</div>
|
||||
<div x-cloak x-show="search !== '' && backups.length > 0 && !hasMatches()">
|
||||
No scheduled backups match your search.
|
||||
</div>
|
||||
@forelse($database->scheduledBackups as $backup)
|
||||
@if ($type == 'database')
|
||||
<a @class([
|
||||
<a x-show="search === '' || @js(strtolower($database->name)).includes(search.toLowerCase()) || @js(strtolower($backup->frequency)).includes(search.toLowerCase())" @class([
|
||||
'flex flex-col border-l-2 transition-colors p-4 cursor-pointer bg-white hover:bg-gray-100 dark:bg-coolgray-100 dark:hover:bg-coolgray-200 text-black dark:text-white',
|
||||
'border-blue-500/50 border-dashed' =>
|
||||
$backup->latest_log &&
|
||||
@@ -105,7 +123,7 @@
|
||||
</div>
|
||||
</a>
|
||||
@else
|
||||
<div @class([
|
||||
<div x-show="search === '' || @js(strtolower($database->name)).includes(search.toLowerCase()) || @js(strtolower($backup->frequency)).includes(search.toLowerCase())" @class([
|
||||
'flex flex-col border-l-2 transition-colors p-4 cursor-pointer bg-white hover:bg-gray-100 dark:bg-coolgray-100 dark:hover:bg-coolgray-200 text-black dark:text-white',
|
||||
'bg-gray-200 dark:bg-coolgray-200' =>
|
||||
data_get($backup, 'id') === data_get($selectedBackup, 'id'),
|
||||
|
||||
Reference in new issue
Block a user