Merge remote-tracking branch 'origin/main' into release/v4.5

This commit is contained in:
github-actions[bot]
2026-10-13 08:04:48 +00:00
4 changed files with 74 additions and 5 deletions
+29 -1
View File
@@ -4,12 +4,15 @@ namespace App\Livewire\Server;
use App\Models\Server;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Pagination\LengthAwarePaginator;
use Livewire\Attributes\Locked;
use Livewire\Component;
use Livewire\WithPagination;
class DockerImages extends Component
{
use AuthorizesRequests;
use WithPagination;
public Server $server;
@@ -27,6 +30,19 @@ class DockerImages extends Component
public bool $loaded = false;
public int $perPage = 10;
public function updatedSearch(): void
{
$this->resetPage();
}
public function updatedPerPage(): void
{
$this->perPage = max(1, min(100, $this->perPage));
$this->resetPage();
}
public function mount(string $server_uuid)
{
try {
@@ -159,10 +175,22 @@ class DockerImages extends Component
->contains($search, ignoreCase: true));
}
$this->perPage = max(1, min(100, $this->perPage));
$lastPage = max(1, (int) ceil($images->count() / $this->perPage));
$page = max(1, min((int) $this->getPage(), $lastPage));
if ($page !== $this->getPage()) {
$this->setPage($page);
}
return view('livewire.server.docker-images', [
// Not "images": Livewire shares public properties with the view, so that name is
// already taken by the unfiltered array.
'visibleImages' => $images->values(),
'visibleImages' => new LengthAwarePaginator(
$images->forPage($page, $this->perPage)->values(),
$images->count(),
$this->perPage,
$page,
),
]);
}
}
@@ -7,7 +7,7 @@
<section {{ $attributes->merge(['class' => 'application-settings-section', 'data-settings-section-title' => $title]) }}>
<header>
<div class="min-w-0 py-0.5">
<div @class(['min-w-0 py-0.5', 'flex flex-wrap items-center gap-2' => isset($badges)])>
@if (filled($description ?? $helper))
<h3>
<x-helper :helper="$description ?? $helper" :label="'More information about '.$title">
@@ -19,6 +19,7 @@
@else
<h3>{{ $title }}</h3>
@endif
{{ $badges ?? '' }}
</div>
@isset($actions)
<div class="flex min-w-0 max-w-full flex-wrap items-center gap-2">
@@ -13,11 +13,13 @@
<x-application.settings-section id="server-docker-images-section" title="Images"
helper="Docker images stored on this server. Images that no container uses can be deleted here."
flush>
<x-slot:actions>
@if ($usage)
@if ($usage)
<x-slot:badges>
<x-status-badge :status="'Total ' . $usage['size']" type="neutral" />
<x-status-badge :status="'Reclaimable ' . $usage['reclaimable']" type="warning" />
@endif
</x-slot:badges>
@endif
<x-slot:actions>
<x-forms.button wire:click="load">
<x-reicon name="refresh" class="size-3.5" />
Refresh
@@ -104,6 +106,15 @@
</div>
@endforeach
</div>
<x-table-pagination :from="$visibleImages->firstItem()" :to="$visibleImages->lastItem()"
:total="$visibleImages->total()" :current-page="$visibleImages->currentPage()"
:last-page="$visibleImages->lastPage()" wire-target="previousPage,nextPage,perPage"
previous-action="previousPage" next-action="nextPage">
<x-slot:pageSize>
<x-page-size-select model="perPage" livewire
storage-key="coolify.page-size.server-docker-images" />
</x-slot:pageSize>
</x-table-pagination>
@endif
</x-application.settings-section>
</div>
+29
View File
@@ -101,3 +101,32 @@ it('filters images by the search term', function () use ($fakeDocker, $nginxId,
->assertSee('1.27')
->assertDontSee(str_repeat('b', 12));
});
it('paginates images and returns to the first page when the search changes', function () {
Process::fake([
'*docker image ls*' => Process::result(output: collect(range(1, 12))
->map(fn (int $i) => json_encode([
'Repository' => sprintf('app-%02d', $i), 'Tag' => 'latest', 'ID' => 'sha256:'.str_repeat(dechex($i), 64),
'Size' => '1MB', 'CreatedSince' => '1 day ago',
]))
->implode("\n")),
'*docker ps -a*' => Process::result(output: ''),
'*docker system df*' => Process::result(output: ''),
]);
Livewire::test(DockerImages::class, ['server_uuid' => $this->server->uuid])
->call('load')
->assertSee('app-10')
->assertDontSee('app-11')
->assertSee('1–10 of 12')
->call('nextPage')
->assertSee('app-12')
->assertDontSee('app-01')
->assertSee('11–12 of 12')
->set('search', 'app-0')
->assertSee('app-01')
->assertSee('1–9 of 9')
->set('perPage', 5)
->assertSee('1–5 of 9')
->assertDontSee('app-06');
});