mirror of
https://github.com/coollabsio/coolify.git
synced 2026-09-24 23:40:16 -05:00
fix(storages): make volume backup executions responsive on mobile
Stack execution details into labeled mobile rows and keep archive paths visible with copy actions.
This commit is contained in:
+52
-1
@@ -3151,7 +3151,58 @@ input[type="search"]::-webkit-search-results-decoration {
|
||||
|
||||
.volume-backup-executions-grid {
|
||||
grid-template-columns: 7.5rem minmax(0, 1fr) 8.5rem 7rem 9rem minmax(9rem, 0.7fr);
|
||||
min-width: 50rem;
|
||||
}
|
||||
|
||||
.volume-backup-execution-label {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.volume-backup-execution-message {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.data-table-header.volume-backup-executions-grid {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.data-table-row.volume-backup-executions-grid {
|
||||
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
|
||||
min-height: 0;
|
||||
align-items: start;
|
||||
gap: 0.875rem 1rem;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.volume-backup-execution-archive,
|
||||
.volume-backup-execution-availability,
|
||||
.volume-backup-execution-message {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
.volume-backup-execution-status,
|
||||
.volume-backup-execution-archive,
|
||||
.volume-backup-execution-time,
|
||||
.volume-backup-execution-size,
|
||||
.volume-backup-execution-availability,
|
||||
.volume-backup-execution-actions {
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
flex-direction: column;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.volume-backup-execution-label {
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
line-height: 1rem;
|
||||
color: var(--coollabs-subtle);
|
||||
}
|
||||
|
||||
.volume-backup-execution-actions > span:last-child {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
}
|
||||
|
||||
.clone-destinations-table-grid {
|
||||
|
||||
+74
-56
@@ -23,7 +23,7 @@
|
||||
</x-slot:actions>
|
||||
|
||||
@if ($executionCount > 0)
|
||||
<div class="data-table w-full overflow-x-auto">
|
||||
<div class="data-table w-full">
|
||||
<div
|
||||
class="data-table-header volume-backup-executions-grid border-b border-neutral-200 bg-neutral-50 dark:border-white/[0.08] dark:bg-white/[0.05]">
|
||||
<span>Status</span>
|
||||
@@ -66,70 +66,88 @@
|
||||
|
||||
<div wire:key="volume-backup-execution-{{ $execution->id }}"
|
||||
class="data-table-row volume-backup-executions-grid min-h-16 items-center gap-x-3 border-b border-neutral-200 text-[12px] last:border-b-0 dark:border-white/[0.07]">
|
||||
<span>
|
||||
<div class="volume-backup-execution-status min-w-0">
|
||||
<span class="volume-backup-execution-label">Status</span>
|
||||
<x-status-badge :status="$statusLabel" :type="$statusType" />
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<span class="min-w-0">
|
||||
<x-forms.copy-button :text="$execution->filename ?? 'No archive name'" />
|
||||
</span>
|
||||
<div class="volume-backup-execution-archive min-w-0">
|
||||
<span class="volume-backup-execution-label">Archive</span>
|
||||
<div class="flex min-w-0 items-center gap-1">
|
||||
<code class="select-all break-all font-mono text-[11px] text-neutral-600 md:truncate dark:text-fg-dim"
|
||||
title="Backup path: {{ $execution->filename ?? 'No archive name' }}">{{ $execution->filename ?? 'No archive name' }}</code>
|
||||
<x-copy-button :value="$execution->filename ?? ''" label="Copy backup path" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<span class="text-[11px] text-neutral-500 dark:text-fg-faint">
|
||||
@if ($execution->status === 'running')
|
||||
Running for {{ calculateDuration($execution->created_at, now()) }}
|
||||
@else
|
||||
{{ $finishedAt->diffForHumans() }}<br>
|
||||
{{ calculateDuration($execution->created_at, $finishedAt) }}
|
||||
@endif
|
||||
</span>
|
||||
<div class="volume-backup-execution-time min-w-0">
|
||||
<span class="volume-backup-execution-label">Time</span>
|
||||
<span class="text-[11px] text-neutral-500 dark:text-fg-faint">
|
||||
@if ($execution->status === 'running')
|
||||
Running for {{ calculateDuration($execution->created_at, now()) }}
|
||||
@else
|
||||
{{ $finishedAt->diffForHumans() }}<br>
|
||||
{{ calculateDuration($execution->created_at, $finishedAt) }}
|
||||
@endif
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<span class="tabular-nums text-neutral-500 dark:text-fg-dim">
|
||||
{{ $execution->size > 0 ? formatBytes($execution->size) : '-' }}
|
||||
</span>
|
||||
<div class="volume-backup-execution-size min-w-0">
|
||||
<span class="volume-backup-execution-label">Size</span>
|
||||
<span class="tabular-nums text-neutral-500 dark:text-fg-dim">
|
||||
{{ $execution->size > 0 ? formatBytes($execution->size) : '-' }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<span class="flex flex-wrap gap-1">
|
||||
<x-status-badge :status="$execution->local_storage_deleted ? 'Local deleted' : 'Local'"
|
||||
:type="$execution->local_storage_deleted ? 'neutral' : 'success'" />
|
||||
@if ($execution->s3_uploaded !== null)
|
||||
<x-status-badge
|
||||
:status="$execution->s3_storage_deleted
|
||||
? 'S3 deleted'
|
||||
: ($execution->s3_uploaded ? 'S3' : 'S3 failed')"
|
||||
:type="$execution->s3_storage_deleted
|
||||
? 'neutral'
|
||||
: ($execution->s3_uploaded ? 'success' : 'error')" />
|
||||
@endif
|
||||
</span>
|
||||
<div class="volume-backup-execution-availability min-w-0">
|
||||
<span class="volume-backup-execution-label">Availability</span>
|
||||
<span class="flex flex-wrap gap-1">
|
||||
<x-status-badge :status="$execution->local_storage_deleted ? 'Local deleted' : 'Local'"
|
||||
:type="$execution->local_storage_deleted ? 'neutral' : 'success'" />
|
||||
@if ($execution->s3_uploaded !== null)
|
||||
<x-status-badge
|
||||
:status="$execution->s3_storage_deleted
|
||||
? 'S3 deleted'
|
||||
: ($execution->s3_uploaded ? 'S3' : 'S3 failed')"
|
||||
:type="$execution->s3_storage_deleted
|
||||
? 'neutral'
|
||||
: ($execution->s3_uploaded ? 'success' : 'error')" />
|
||||
@endif
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<span class="flex items-center justify-end gap-1">
|
||||
@if ($execution->status === 'success' && ! $execution->local_storage_deleted)
|
||||
<button type="button" class="icon-button shrink-0"
|
||||
x-on:click="download_volume_backup_file('{{ $execution->id }}')"
|
||||
title="Download backup" aria-label="Download backup">
|
||||
<x-reicon name="upload" class="size-3.5 rotate-180" />
|
||||
</button>
|
||||
@endif
|
||||
@if ($execution->status !== 'running')
|
||||
<x-modal-confirmation title="Confirm Backup Deletion?" isErrorButton
|
||||
submitAction="deleteBackup({{ $execution->id }})"
|
||||
:checkboxes="$executionCheckboxes" :actions="$deleteActions"
|
||||
confirmationText="{{ $execution->filename }}"
|
||||
confirmationLabel="Please confirm the execution of the actions by entering the Backup Filename below"
|
||||
shortConfirmationLabel="Backup Filename">
|
||||
<x-slot:trigger>
|
||||
<button type="button"
|
||||
class="icon-button shrink-0 text-red-500 hover:text-red-600 dark:text-red-400 dark:hover:text-red-300"
|
||||
title="Delete backup" aria-label="Delete backup">
|
||||
<x-reicon name="trash" class="size-3.5" />
|
||||
</button>
|
||||
</x-slot:trigger>
|
||||
</x-modal-confirmation>
|
||||
@endif
|
||||
</span>
|
||||
<div class="volume-backup-execution-actions min-w-0">
|
||||
<span class="volume-backup-execution-label">Actions</span>
|
||||
<span class="flex items-center justify-end gap-1">
|
||||
@if ($execution->status === 'success' && ! $execution->local_storage_deleted)
|
||||
<button type="button" class="icon-button shrink-0"
|
||||
x-on:click="download_volume_backup_file('{{ $execution->id }}')"
|
||||
title="Download backup" aria-label="Download backup">
|
||||
<x-reicon name="upload" class="size-3.5 rotate-180" />
|
||||
</button>
|
||||
@endif
|
||||
@if ($execution->status !== 'running')
|
||||
<x-modal-confirmation title="Confirm Backup Deletion?" isErrorButton
|
||||
submitAction="deleteBackup({{ $execution->id }})"
|
||||
:checkboxes="$executionCheckboxes" :actions="$deleteActions"
|
||||
confirmationText="{{ $execution->filename }}"
|
||||
confirmationLabel="Please confirm the execution of the actions by entering the Backup Filename below"
|
||||
shortConfirmationLabel="Backup Filename">
|
||||
<x-slot:trigger>
|
||||
<button type="button"
|
||||
class="icon-button shrink-0 text-red-500 hover:text-red-600 dark:text-red-400 dark:hover:text-red-300"
|
||||
title="Delete backup" aria-label="Delete backup">
|
||||
<x-reicon name="trash" class="size-3.5" />
|
||||
</button>
|
||||
</x-slot:trigger>
|
||||
</x-modal-confirmation>
|
||||
@endif
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@if ($execution->message)
|
||||
<pre
|
||||
class="volume-backup-execution-message col-span-6 mt-2 max-h-32 overflow-auto rounded-lg border border-neutral-200 bg-neutral-50 p-2 text-[11px] whitespace-pre-wrap text-neutral-600 dark:border-white/[0.08] dark:bg-white/[0.05] dark:text-fg-dim">{{ $execution->message }}</pre>
|
||||
class="volume-backup-execution-message mt-2 max-h-32 overflow-auto rounded-lg border border-neutral-200 bg-neutral-50 p-2 text-[11px] whitespace-pre-wrap text-neutral-600 dark:border-white/[0.08] dark:bg-white/[0.05] dark:text-fg-dim">{{ $execution->message }}</pre>
|
||||
@endif
|
||||
</div>
|
||||
@endforeach
|
||||
|
||||
@@ -1,16 +1,23 @@
|
||||
<?php
|
||||
|
||||
it('keeps the volume backup executions table horizontally scrollable on mobile', function () {
|
||||
it('stacks volume backup executions and keeps archive paths visible on mobile', function () {
|
||||
$view = file_get_contents(resource_path('views/livewire/project/shared/storages/volume-backups/executions.blade.php'));
|
||||
$css = file_get_contents(resource_path('css/app.css'));
|
||||
|
||||
expect($view)
|
||||
->toContain('volume-backup-executions-grid')
|
||||
->toContain('data-table w-full overflow-x-auto')
|
||||
->toContain('volume-backup-execution-archive')
|
||||
->toContain('volume-backup-execution-label')
|
||||
->toContain('select-all break-all')
|
||||
->toContain('x-copy-button')
|
||||
->not->toContain('data-table w-full overflow-x-auto')
|
||||
->not->toContain('x-forms.copy-button')
|
||||
->and($css)
|
||||
->toContain('.volume-backup-executions-grid')
|
||||
->toContain('min-width: 50rem;')
|
||||
->not->toContain('.data-table-header.volume-backup-executions-grid');
|
||||
->toContain('.data-table-header.volume-backup-executions-grid')
|
||||
->toContain('.volume-backup-execution-archive')
|
||||
->toContain('grid-column: 1 / -1;')
|
||||
->not->toMatch('/\.volume-backup-executions-grid\s*\{[^}]*min-width:/');
|
||||
});
|
||||
|
||||
it('uses compact icon actions for volume backup executions', function () {
|
||||
@@ -194,8 +201,8 @@ it('renders volumes as a data table with shared column headers', function () {
|
||||
->toMatch('/<x-callout[^>]*title="File-level consistency"[\s\S]*id="stopDuringBackup"[\s\S]*<\/x-callout>/');
|
||||
expect(file_get_contents(resource_path('views/livewire/project/shared/storages/volume-backups/executions.blade.php')))
|
||||
->toContain('<span>Time</span>')
|
||||
->toContain('x-forms.copy-button')
|
||||
->toContain('col-span-6');
|
||||
->toContain('x-copy-button')
|
||||
->toContain('volume-backup-execution-message');
|
||||
|
||||
$css = file_get_contents(resource_path('css/app.css'));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user