mirror of
https://github.com/coollabsio/coolify.git
synced 2026-09-28 02:06:37 -04:00
Merge remote-tracking branch 'origin/next' into openid-auth-support
This commit is contained in:
@@ -129,9 +129,13 @@
|
||||
}
|
||||
}"
|
||||
@keydown.escape.window="if (modalOpen) { modalOpen = false; resetModal(); }" :class="{ 'z-40': modalOpen }"
|
||||
class="relative w-auto h-auto">
|
||||
@class([
|
||||
'relative h-auto',
|
||||
'w-full' => $buttonFullWidth,
|
||||
'w-full sm:w-auto' => ! $buttonFullWidth,
|
||||
])>
|
||||
@if (isset($trigger))
|
||||
<div @click="modalOpen=true">
|
||||
<div class="w-full" @click="modalOpen=true">
|
||||
{{ $trigger }}
|
||||
</div>
|
||||
@elseif ($customButton)
|
||||
|
||||
@@ -44,16 +44,6 @@
|
||||
this.queryTheme();
|
||||
this.checkZoom();
|
||||
},
|
||||
setTheme(type) {
|
||||
this.theme = type;
|
||||
localStorage.setItem('theme', type);
|
||||
this.queryTheme();
|
||||
},
|
||||
cycleTheme() {
|
||||
const themes = ['light', 'system', 'dark'];
|
||||
const currentIndex = themes.indexOf(this.theme || localStorage.getItem('theme') || 'dark');
|
||||
this.setTheme(themes[(currentIndex + 1) % themes.length]);
|
||||
},
|
||||
queryTheme() {
|
||||
const darkModePreference = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||
const userSettings = localStorage.getItem('theme') || 'dark';
|
||||
@@ -375,45 +365,6 @@
|
||||
<li>
|
||||
<livewire:settings-dropdown trigger="changelog-sidebar" />
|
||||
</li>
|
||||
<li>
|
||||
<button type="button" @click.stop="cycleTheme()"
|
||||
:title="`Theme: ${theme === 'system' ? 'System default' : theme}. Click to change.`"
|
||||
:aria-label="`Theme: ${theme === 'system' ? 'System default' : theme}. Click to change theme.`"
|
||||
class="menu-item"
|
||||
:class="collapsed && 'lg:hidden'">
|
||||
<svg x-show="theme === 'dark'" class="menu-item-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" />
|
||||
</svg>
|
||||
<svg x-show="theme === 'light'" class="menu-item-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" />
|
||||
</svg>
|
||||
<svg x-show="theme === 'system'" class="menu-item-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
|
||||
</svg>
|
||||
<span class="text-left menu-item-label">Theme</span>
|
||||
</button>
|
||||
<button type="button" @click.stop="cycleTheme()"
|
||||
:title="`Theme: ${theme === 'system' ? 'System default' : theme}. Click to change.`"
|
||||
:aria-label="`Theme: ${theme === 'system' ? 'System default' : theme}. Click to change theme.`"
|
||||
class="menu-item hidden"
|
||||
:class="collapsed && 'lg:flex'">
|
||||
<svg x-show="theme === 'dark'" class="menu-item-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" />
|
||||
</svg>
|
||||
<svg x-show="theme === 'light'" class="menu-item-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" />
|
||||
</svg>
|
||||
<svg x-show="theme === 'system'" class="menu-item-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
|
||||
</svg>
|
||||
</button>
|
||||
</li>
|
||||
@if (isInstanceAdmin() && !isCloud())
|
||||
@persist('upgrade')
|
||||
<li>
|
||||
|
||||
@@ -82,7 +82,11 @@
|
||||
</div>
|
||||
<div class="flex flex-col w-full gap-2 xl:flex-row">
|
||||
<x-forms.input canGate="update" :canResource="$settings" id="smtpUsername" label="SMTP Username" />
|
||||
<x-forms.input canGate="update" :canResource="$settings" id="smtpPassword" type="password" label="SMTP Password" />
|
||||
@can('update', $settings)
|
||||
<x-forms.input canGate="update" :canResource="$settings" id="smtpPassword" type="password" label="SMTP Password" />
|
||||
@else
|
||||
<x-forms.input disabled label="SMTP Password" value="Hidden (only admins can view)" />
|
||||
@endcan
|
||||
<x-forms.input canGate="update" :canResource="$settings" id="smtpTimeout" type="number" helper="Timeout value for sending emails."
|
||||
label="Timeout" />
|
||||
</div>
|
||||
@@ -109,8 +113,12 @@
|
||||
<div class="flex flex-col">
|
||||
<div class="flex flex-col gap-4">
|
||||
<div class="flex flex-col w-full gap-2 xl:flex-row">
|
||||
<x-forms.input canGate="update" :canResource="$settings" required type="password" id="resendApiKey" placeholder="API key"
|
||||
label="API Key" />
|
||||
@can('update', $settings)
|
||||
<x-forms.input canGate="update" :canResource="$settings" required type="password" id="resendApiKey" placeholder="API key"
|
||||
label="API Key" />
|
||||
@else
|
||||
<x-forms.input disabled label="API Key" value="Hidden (only admins can view)" />
|
||||
@endcan
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,32 +1,40 @@
|
||||
<form wire:submit="submit">
|
||||
<div class="flex gap-2 pb-2">
|
||||
<div class="flex flex-col gap-3 pb-4 sm:flex-row sm:items-center">
|
||||
<h2>Scheduled Backup</h2>
|
||||
<x-forms.button type="submit">
|
||||
Save
|
||||
</x-forms.button>
|
||||
@if (str($status)->startsWith('running'))
|
||||
<x-forms.button wire:click='backupNow'>Backup Now</x-forms.button>
|
||||
@endif
|
||||
@if ($backup->database_id !== 0)
|
||||
<x-modal-confirmation title="Confirm Backup Schedule Deletion?" buttonTitle="Delete Backups and Schedule"
|
||||
isErrorButton submitAction="delete" :checkboxes="$checkboxes" :actions="[
|
||||
'The selected backup schedule will be deleted.',
|
||||
'Scheduled backups for this database will be stopped (if this is the only backup schedule for this database).',
|
||||
]"
|
||||
confirmationText="{{ $backup->database->name }}"
|
||||
confirmationLabel="Please confirm the execution of the actions by entering the Database Name of the scheduled backups below"
|
||||
shortConfirmationLabel="Database Name" />
|
||||
@endif
|
||||
<div class="flex flex-col gap-2 sm:flex-row sm:flex-wrap">
|
||||
<x-forms.button type="submit" class="w-full sm:w-auto">
|
||||
Save
|
||||
</x-forms.button>
|
||||
@if (str($status)->startsWith('running'))
|
||||
<x-forms.button wire:click='backupNow' class="w-full sm:w-auto">Backup Now</x-forms.button>
|
||||
@endif
|
||||
@if ($backup->database_id !== 0)
|
||||
<div class="w-full sm:w-auto">
|
||||
<x-modal-confirmation title="Confirm Backup Schedule Deletion?" isErrorButton submitAction="delete"
|
||||
:checkboxes="$checkboxes" :actions="[
|
||||
'The selected backup schedule will be deleted.',
|
||||
'Scheduled backups for this database will be stopped (if this is the only backup schedule for this database).',
|
||||
]"
|
||||
confirmationText="{{ $backup->database->name }}"
|
||||
confirmationLabel="Please confirm the execution of the actions by entering the Database Name of the scheduled backups below"
|
||||
shortConfirmationLabel="Database Name">
|
||||
<x-slot:trigger>
|
||||
<x-forms.button isError class="w-full sm:w-auto">Delete Backups and Schedule</x-forms.button>
|
||||
</x-slot:trigger>
|
||||
</x-modal-confirmation>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-64 pb-2">
|
||||
<div class="w-full max-w-md pb-2">
|
||||
<x-forms.checkbox instantSave label="Backup Enabled" id="backupEnabled" />
|
||||
@if ($s3s->count() > 0)
|
||||
@if ($availableS3Storages->count() > 0)
|
||||
<x-forms.checkbox instantSave label="S3 Enabled" id="saveS3" />
|
||||
@else
|
||||
<x-forms.checkbox instantSave helper="No validated S3 storage available." label="S3 Enabled" id="saveS3"
|
||||
disabled />
|
||||
@endif
|
||||
@if ($backup->save_s3)
|
||||
@if ($saveS3)
|
||||
<x-forms.checkbox instantSave label="Disable Local Backup" id="disableLocalBackup"
|
||||
helper="When enabled, backup files will be deleted from local storage immediately after uploading to S3. This requires S3 backup to be enabled." />
|
||||
@else
|
||||
@@ -34,16 +42,27 @@
|
||||
helper="When enabled, backup files will be deleted from local storage immediately after uploading to S3. This requires S3 backup to be enabled." />
|
||||
@endif
|
||||
</div>
|
||||
@if ($backup->save_s3)
|
||||
<div class="pb-6">
|
||||
<x-forms.select id="s3StorageId" label="S3 Storage" required>
|
||||
<option value="default" disabled>Select a S3 storage</option>
|
||||
@foreach ($s3s as $s3)
|
||||
<div class="w-full max-w-md pb-6">
|
||||
<div class="flex gap-1 items-center mb-1 text-sm font-medium">
|
||||
<span>S3 Storage</span>
|
||||
@if (!$saveS3)
|
||||
<span class="text-xs font-normal text-warning">(currently disabled)</span>
|
||||
@endif
|
||||
@if ($saveS3)
|
||||
<x-highlighted text="*" />
|
||||
@endif
|
||||
</div>
|
||||
<x-forms.select id="s3StorageId" wire:model.live="s3StorageId" :required="$saveS3"
|
||||
:disabled="$availableS3Storages->isEmpty()">
|
||||
@if ($availableS3Storages->isEmpty())
|
||||
<option value="">No S3 storage available</option>
|
||||
@else
|
||||
@foreach ($availableS3Storages as $s3)
|
||||
<option value="{{ $s3->id }}">{{ $s3->name }}</option>
|
||||
@endforeach
|
||||
</x-forms.select>
|
||||
</div>
|
||||
@endif
|
||||
@endif
|
||||
</x-forms.select>
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<h3>Settings</h3>
|
||||
<div class="flex gap-2 flex-col ">
|
||||
@@ -80,7 +99,7 @@
|
||||
@endif
|
||||
@endif
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<div class="grid grid-cols-1 gap-2 md:grid-cols-3">
|
||||
<x-forms.input label="Frequency" id="frequency" required />
|
||||
<x-forms.input label="Timezone" id="timezone" disabled
|
||||
helper="The timezone of the server where the backup is scheduled to run (if not set, the instance timezone will be used)" required />
|
||||
@@ -98,7 +117,7 @@
|
||||
<div class="flex gap-6 flex-col">
|
||||
<div>
|
||||
<h4 class="mb-3 font-medium">Local Backup Retention</h4>
|
||||
<div class="flex gap-2">
|
||||
<div class="grid grid-cols-1 gap-2 md:grid-cols-3">
|
||||
<x-forms.input label="Number of backups to keep" id="databaseBackupRetentionAmountLocally"
|
||||
type="number" min="0"
|
||||
helper="Keeps only the specified number of most recent backups on the server. Set to 0 for unlimited backups." required />
|
||||
@@ -111,10 +130,10 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if ($backup->save_s3)
|
||||
@if ($saveS3)
|
||||
<div>
|
||||
<h4 class="mb-3 font-medium">S3 Storage Retention</h4>
|
||||
<div class="flex gap-2">
|
||||
<div class="grid grid-cols-1 gap-2 md:grid-cols-3">
|
||||
<x-forms.input label="Number of backups to keep" id="databaseBackupRetentionAmountS3"
|
||||
type="number" min="0"
|
||||
helper="Keeps only the specified number of most recent backups on S3 storage. Set to 0 for unlimited backups." required />
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div wire:init='refreshBackupExecutions'>
|
||||
@isset($backup)
|
||||
<div class="flex items-center gap-2">
|
||||
<h3 class="py-4">Executions <span class="text-xs">({{ $executions_count }})</span></h3>
|
||||
<div class="flex flex-col gap-3 py-4 sm:flex-row sm:flex-wrap sm:items-center">
|
||||
<h3 class="py-0">Executions <span class="text-xs">({{ $executions_count }})</span></h3>
|
||||
@if ($executions_count > 0)
|
||||
<div class="flex items-center gap-2">
|
||||
<x-forms.button disabled="{{ !$showPrev }}" wire:click="previousPage('{{ $defaultTake }}')">
|
||||
@@ -21,13 +21,19 @@
|
||||
</x-forms.button>
|
||||
</div>
|
||||
@endif
|
||||
<x-forms.button wire:click='cleanupFailed'>Cleanup Failed Backups</x-forms.button>
|
||||
<x-modal-confirmation title="Cleanup Deleted Backup Entries?" buttonTitle="Cleanup Deleted" isErrorButton
|
||||
submitAction="cleanupDeleted()"
|
||||
:actions="['This will permanently delete all backup execution entries that are marked as deleted from local storage.', 'This only removes database entries, not actual backup files.']"
|
||||
confirmationText="cleanup deleted backups"
|
||||
confirmationLabel="Please confirm by typing 'cleanup deleted backups' below"
|
||||
shortConfirmationLabel="Confirmation" />
|
||||
<div class="flex flex-col gap-2 sm:flex-row sm:flex-wrap">
|
||||
<x-forms.button wire:click='cleanupFailed' class="w-full sm:w-auto">Cleanup Failed Backups</x-forms.button>
|
||||
<x-modal-confirmation title="Cleanup Deleted Backup Entries?" isErrorButton
|
||||
submitAction="cleanupDeleted()"
|
||||
:actions="['This will permanently delete all backup execution entries that are marked as deleted from local storage.', 'This only removes database entries, not actual backup files.']"
|
||||
confirmationText="cleanup deleted backups"
|
||||
confirmationLabel="Please confirm by typing 'cleanup deleted backups' below"
|
||||
shortConfirmationLabel="Confirmation">
|
||||
<x-slot:trigger>
|
||||
<x-forms.button isError class="w-full sm:w-auto">Cleanup Deleted</x-forms.button>
|
||||
</x-slot:trigger>
|
||||
</x-modal-confirmation>
|
||||
</div>
|
||||
</div>
|
||||
<div @if (!$skip) wire:poll.5000ms="refreshBackupExecutions" @endif
|
||||
class="flex flex-col gap-4">
|
||||
@@ -87,7 +93,7 @@
|
||||
<div class="text-gray-600 dark:text-gray-400 text-sm">
|
||||
Location: {{ data_get($execution, 'filename', 'N/A') }}
|
||||
</div>
|
||||
<div class="flex items-center gap-3 mt-2">
|
||||
<div class="flex flex-col gap-2 mt-2 sm:flex-row sm:flex-wrap sm:items-center sm:gap-3">
|
||||
<div class="text-gray-600 dark:text-gray-400 text-sm">
|
||||
Backup Availability:
|
||||
</div>
|
||||
@@ -154,9 +160,9 @@
|
||||
<pre class="whitespace-pre-wrap text-sm">{{ data_get($execution, 'message') }}</pre>
|
||||
</div>
|
||||
@endif
|
||||
<div class="flex gap-2 mt-4">
|
||||
<div class="grid grid-cols-2 gap-2 mt-4 sm:flex sm:flex-wrap">
|
||||
@if (data_get($execution, 'status') === 'success')
|
||||
<x-forms.button class="dark:hover:bg-coolgray-400"
|
||||
<x-forms.button class="w-full dark:hover:bg-coolgray-400 sm:w-auto"
|
||||
x-on:click="download_file('{{ data_get($execution, 'id') }}')">Download</x-forms.button>
|
||||
@endif
|
||||
@php
|
||||
@@ -175,11 +181,15 @@
|
||||
$deleteActions[] = 'This backup execution record will be deleted.';
|
||||
}
|
||||
@endphp
|
||||
<x-modal-confirmation title="Confirm Backup Deletion?" buttonTitle="Delete" isErrorButton
|
||||
<x-modal-confirmation title="Confirm Backup Deletion?" isErrorButton
|
||||
submitAction="deleteBackup({{ data_get($execution, 'id') }})" :checkboxes="$executionCheckboxes"
|
||||
:actions="$deleteActions" confirmationText="{{ data_get($execution, 'filename') }}"
|
||||
confirmationLabel="Please confirm the execution of the actions by entering the Backup Filename below"
|
||||
shortConfirmationLabel="Backup Filename" 1 />
|
||||
shortConfirmationLabel="Backup Filename">
|
||||
<x-slot:trigger>
|
||||
<x-forms.button isError class="w-full sm:w-auto">Delete</x-forms.button>
|
||||
</x-slot:trigger>
|
||||
</x-modal-confirmation>
|
||||
</div>
|
||||
</div>
|
||||
@empty
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<livewire:project.shared.configuration-checker :resource="$database" />
|
||||
<livewire:project.database.heading :database="$database" />
|
||||
<div>
|
||||
<livewire:project.database.backup-edit :backup="$backup" :s3s="$s3s" :status="data_get($database, 'status')" />
|
||||
<livewire:project.database.backup-edit :backup="$backup" :available-s3-storages="$s3s" :status="data_get($database, 'status')" />
|
||||
<livewire:project.database.backup-executions :backup="$backup" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -216,7 +216,7 @@
|
||||
@if ($type === 'service-database' && $selectedBackup)
|
||||
<div class="pt-10">
|
||||
<livewire:project.database.backup-edit wire:key="{{ $selectedBackup->id }}" :backup="$selectedBackup"
|
||||
:s3s="$s3s" :status="data_get($database, 'status')" />
|
||||
:available-s3-storages="$s3s" :status="data_get($database, 'status')" />
|
||||
<livewire:project.database.backup-executions wire:key="{{ $selectedBackup->uuid }}" :backup="$selectedBackup"
|
||||
:database="$database" />
|
||||
</div>
|
||||
|
||||
@@ -4,6 +4,10 @@
|
||||
<div class="w-full p-2 text-sm rounded bg-warning/10 text-warning">
|
||||
File on server exceeds 5 MB and cannot be edited from the UI. Edit it directly on the server.
|
||||
</div>
|
||||
@elseif ($fileStorage->is_host_file)
|
||||
<div class="w-full p-2 text-sm rounded bg-warning/10 text-warning">
|
||||
This host file mount is bind-only. Coolify will not create, edit, load, chmod, or delete the source file.
|
||||
</div>
|
||||
@elseif ($isReadOnly)
|
||||
<div class="w-full p-2 text-sm rounded bg-warning/10 text-warning">
|
||||
@if ($fileStorage->is_directory)
|
||||
@@ -32,7 +36,14 @@
|
||||
@if (!$isReadOnly)
|
||||
@can('update', $resource)
|
||||
<div class="flex gap-2">
|
||||
@if ($fileStorage->is_directory)
|
||||
@if ($fileStorage->is_host_file)
|
||||
<x-modal-confirmation :ignoreWire="false" title="Confirm Host File Mount Removal?"
|
||||
buttonTitle="Delete" isErrorButton submitAction="delete" :checkboxes="$hostFileDeletionCheckboxes"
|
||||
:actions="['Only the mount configuration will be removed. The host file will not be deleted.']"
|
||||
confirmationText="{{ $fs_path }}"
|
||||
confirmationLabel="Please confirm the execution of the actions by entering the Filepath below"
|
||||
shortConfirmationLabel="Filepath" />
|
||||
@elseif ($fileStorage->is_directory)
|
||||
<x-modal-confirmation :ignoreWire="false" title="Confirm Directory Conversion to File?"
|
||||
buttonTitle="Convert to file" submitAction="convertToFile" :actions="[
|
||||
'All files in this directory will be permanently deleted and an empty file will be created in its place.',
|
||||
@@ -68,7 +79,7 @@
|
||||
@endif
|
||||
</div>
|
||||
@endcan
|
||||
@if (!$fileStorage->is_directory)
|
||||
@if (!$fileStorage->is_directory && !$fileStorage->is_host_file)
|
||||
@can('update', $resource)
|
||||
@if (data_get($resource, 'settings.is_preserve_repository_enabled'))
|
||||
<div class="w-full sm:w-96">
|
||||
@@ -99,7 +110,7 @@
|
||||
@endif
|
||||
@else
|
||||
{{-- Read-only view --}}
|
||||
@if (!$fileStorage->is_directory)
|
||||
@if (!$fileStorage->is_directory && !$fileStorage->is_host_file)
|
||||
@can('update', $resource)
|
||||
<div class="flex gap-2">
|
||||
<x-forms.button type="button" wire:click="loadStorageOnServer">Load from
|
||||
|
||||
@@ -22,11 +22,13 @@
|
||||
dropdownOpen: false,
|
||||
volumeModalOpen: false,
|
||||
fileModalOpen: false,
|
||||
hostFileModalOpen: false,
|
||||
directoryModalOpen: false
|
||||
}"
|
||||
@close-storage-modal.window="
|
||||
if ($event.detail === 'volume') volumeModalOpen = false;
|
||||
if ($event.detail === 'file') fileModalOpen = false;
|
||||
if ($event.detail === 'host-file') hostFileModalOpen = false;
|
||||
if ($event.detail === 'directory') directoryModalOpen = false;
|
||||
">
|
||||
<div class="relative" @click.outside="dropdownOpen = false">
|
||||
@@ -62,6 +64,15 @@
|
||||
</svg>
|
||||
File Mount
|
||||
</a>
|
||||
<a class="dropdown-item"
|
||||
@click="hostFileModalOpen = true; dropdownOpen = false">
|
||||
<svg class="size-4" fill="none" stroke="currentColor"
|
||||
viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z" />
|
||||
</svg>
|
||||
Host File Mount
|
||||
</a>
|
||||
<a class="dropdown-item"
|
||||
@click="directoryModalOpen = true; dropdownOpen = false">
|
||||
<svg class="size-4" fill="none" stroke="currentColor"
|
||||
@@ -188,14 +199,28 @@
|
||||
}
|
||||
})">
|
||||
<form class="flex flex-col w-full gap-2 rounded-sm"
|
||||
x-data="{
|
||||
hostPath: @js($this->fileStorageHostPath()),
|
||||
filePath: @entangle('file_storage_path'),
|
||||
previewPath() {
|
||||
const path = (this.filePath || '').trim();
|
||||
|
||||
return this.hostPath + (path === '' ? '/' : (path.startsWith('/') ? path : `/${path}`));
|
||||
},
|
||||
}"
|
||||
wire:submit='submitFileStorage'>
|
||||
<div class="flex flex-col">
|
||||
<div>Actual file mounted from the host system to the container.</div>
|
||||
<div>This file will be created on the host, then mounted into the container.</div>
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="p-2 text-xs rounded-sm bg-neutral-100 dark:bg-coolgray-200">
|
||||
<div class="mb-1 font-medium">Host file path</div>
|
||||
<code class="break-all" x-text="previewPath()">{{ $this->fileStoragePreviewPath() }}</code>
|
||||
</div>
|
||||
<x-forms.input canGate="update" :canResource="$resource"
|
||||
placeholder="/etc/nginx/nginx.conf" id="file_storage_path"
|
||||
label="Destination Path" required
|
||||
x-on:input="filePath = $event.target.value"
|
||||
helper="File location inside the container" />
|
||||
<x-forms.textarea canGate="update" :canResource="$resource" label="Content"
|
||||
id="file_storage_content"></x-forms.textarea>
|
||||
@@ -209,6 +234,67 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
{{-- Host File Modal --}}
|
||||
<template x-teleport="body">
|
||||
<div x-show="hostFileModalOpen" @keydown.window.escape="hostFileModalOpen=false"
|
||||
class="fixed top-0 left-0 lg:px-0 px-4 z-99 flex items-center justify-center w-screen h-screen">
|
||||
<div x-show="hostFileModalOpen" x-transition:enter="ease-out duration-100"
|
||||
x-transition:enter-start="opacity-0" x-transition:enter-end="opacity-100"
|
||||
x-transition:leave="ease-in duration-100" x-transition:leave-start="opacity-100"
|
||||
x-transition:leave-end="opacity-0" @click="hostFileModalOpen=false"
|
||||
class="absolute inset-0 w-full h-full bg-black/20 backdrop-blur-xs"></div>
|
||||
<div x-show="hostFileModalOpen" x-trap.inert.noscroll="hostFileModalOpen"
|
||||
x-transition:enter="ease-out duration-100"
|
||||
x-transition:enter-start="opacity-0 -translate-y-2 sm:scale-95"
|
||||
x-transition:enter-end="opacity-100 translate-y-0 sm:scale-100"
|
||||
x-transition:leave="ease-in duration-100"
|
||||
x-transition:leave-start="opacity-100 translate-y-0 sm:scale-100"
|
||||
x-transition:leave-end="opacity-0 -translate-y-2 sm:scale-95"
|
||||
class="relative w-full py-6 border rounded-sm drop-shadow-sm min-w-full lg:min-w-[36rem] max-w-fit bg-white border-neutral-200 dark:bg-base px-6 dark:border-coolgray-300">
|
||||
<div class="flex items-center justify-between pb-3">
|
||||
<h3 class="text-2xl font-bold">Add Host File Mount</h3>
|
||||
<button @click="hostFileModalOpen=false"
|
||||
class="absolute top-0 right-0 flex items-center justify-center w-8 h-8 mt-5 mr-5 rounded-full dark:text-white hover:bg-neutral-100 dark:hover:bg-coolgray-300 outline-0 focus-visible:ring-2 focus-visible:ring-coollabs dark:focus-visible:ring-warning">
|
||||
<svg class="w-5 h-5" xmlns="http://www.w3.org/2000/svg" fill="none"
|
||||
viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="relative flex items-center justify-center w-auto"
|
||||
x-init="$watch('hostFileModalOpen', value => {
|
||||
if (value) {
|
||||
$nextTick(() => {
|
||||
const input = $el.querySelector('input');
|
||||
input?.focus();
|
||||
})
|
||||
}
|
||||
})">
|
||||
<form class="flex flex-col w-full gap-2 rounded-sm"
|
||||
wire:submit='submitHostFileStorage'>
|
||||
<div class="flex flex-col">
|
||||
<div>Bind an existing host file into the container. Coolify will not create, edit, load, chmod, or delete the source file.</div>
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<x-forms.input canGate="update" :canResource="$resource"
|
||||
placeholder="/etc/nginx/nginx.conf"
|
||||
id="host_file_storage_source" label="Host File Path" required
|
||||
helper="Existing file on the host system." />
|
||||
<x-forms.input canGate="update" :canResource="$resource"
|
||||
placeholder="/etc/nginx/nginx.conf"
|
||||
id="host_file_storage_destination" label="Destination Path"
|
||||
required helper="File location inside the container." />
|
||||
<x-forms.button canGate="update" :canResource="$resource" type="submit">
|
||||
Add
|
||||
</x-forms.button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
{{-- Directory Modal --}}
|
||||
<template x-teleport="body">
|
||||
<div x-show="directoryModalOpen" @keydown.window.escape="directoryModalOpen=false"
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
<x-forms.input type="password" label="Password" readonly id="postgres_password" />
|
||||
</div>
|
||||
</div>
|
||||
<livewire:project.database.backup-edit :backup="$backup" :s3s="$s3s" :status="data_get($database, 'status')" />
|
||||
<livewire:project.database.backup-edit :backup="$backup" :available-s3-storages="$s3s" :status="data_get($database, 'status')" />
|
||||
<div class="py-4">
|
||||
<livewire:project.database.backup-executions :backup="$backup" />
|
||||
</div>
|
||||
|
||||
@@ -114,7 +114,7 @@
|
||||
<span class="text-left menu-item-label" :class="collapsed && 'lg:hidden'">What's New</span>
|
||||
@if ($unreadCount > 0)
|
||||
<span
|
||||
class="absolute top-0 right-0 bg-error text-white text-[10px] rounded-full min-w-4 h-4 px-1 flex items-center justify-center"
|
||||
class="absolute right-2 top-1/2 -translate-y-1/2 bg-error text-white text-[10px] rounded-full min-w-4 h-4 px-1 flex items-center justify-center"
|
||||
aria-label="{{ $unreadCount }} unread changelog {{ Str::plural('entry', $unreadCount) }}">
|
||||
{{ $unreadCount > 9 ? '9+' : $unreadCount }}
|
||||
</span>
|
||||
|
||||
Reference in New Issue
Block a user