diff --git a/app/Livewire/Docker/Index.php b/app/Livewire/Docker/Index.php
index ba0c1c0..e9b2450 100644
--- a/app/Livewire/Docker/Index.php
+++ b/app/Livewire/Docker/Index.php
@@ -117,7 +117,7 @@ class Index extends Component
}
/** Open the read-only logs modal for a host container (ref re-validated in DockerService). */
- public function viewLogs(string $id): void
+ public function viewLogs(string $id, string $name = ''): void
{
abort_unless(Auth::user()?->can('manage-fleet'), 403);
@@ -125,6 +125,7 @@ class Index extends Component
// 0 is the sentinel the logs modal resolves to the Clusev host (no persisted id).
'serverId' => 0,
'ref' => $id,
+ 'name' => $name,
]);
}
diff --git a/app/Livewire/Modals/ContainerLogs.php b/app/Livewire/Modals/ContainerLogs.php
index 204f406..e16d481 100644
--- a/app/Livewire/Modals/ContainerLogs.php
+++ b/app/Livewire/Modals/ContainerLogs.php
@@ -17,16 +17,20 @@ class ContainerLogs extends ModalComponent
public string $ref;
+ /** Display name for the modal title (the real ref stays the docker target). */
+ public string $name = '';
+
public string $logs = '';
public bool $loaded = false;
public ?string $error = null;
- public function mount(int $serverId, string $ref): void
+ public function mount(int $serverId, string $ref, string $name = ''): void
{
$this->serverId = $serverId;
$this->ref = $ref;
+ $this->name = $name;
}
public static function modalMaxWidth(): string
diff --git a/app/Livewire/Servers/ServerDocker.php b/app/Livewire/Servers/ServerDocker.php
index 720fff4..f8872e2 100644
--- a/app/Livewire/Servers/ServerDocker.php
+++ b/app/Livewire/Servers/ServerDocker.php
@@ -88,13 +88,14 @@ class ServerDocker extends Component
}
/** Open the read-only logs modal for a container on this server (ref re-validated in DockerService). */
- public function viewLogs(string $id): void
+ public function viewLogs(string $id, string $name = ''): void
{
abort_unless(Auth::user()?->can('operate'), 403);
$this->dispatch('openModal', component: 'modals.container-logs', arguments: [
'serverId' => (int) $this->server->id,
'ref' => $id,
+ 'name' => $name,
]);
}
diff --git a/app/Services/DockerService.php b/app/Services/DockerService.php
index 94eac85..d5ec201 100644
--- a/app/Services/DockerService.php
+++ b/app/Services/DockerService.php
@@ -66,9 +66,11 @@ class DockerService
}
$p = explode("\t", $line);
$status = trim($p[3] ?? '');
+ $name = trim($p[1] ?? '');
$out[] = [
'id' => trim($p[0] ?? ''),
- 'name' => trim($p[1] ?? ''),
+ 'name' => $name,
+ 'display' => self::displayName($name),
'image' => trim($p[2] ?? ''),
'state' => $this->stateFromStatus($status),
'status' => $status,
@@ -79,6 +81,15 @@ class DockerService
return $out;
}
+ /**
+ * Display-only container name: strip the compose replica suffix ("clusev-app-1" -> "clusev-app").
+ * NEVER use for docker commands — actions/logs keep the real name/id.
+ */
+ public static function displayName(string $name): string
+ {
+ return preg_replace('/-\d+$/', '', $name) ?: $name;
+ }
+
/** Derive a coarse state from docker's Status text (portable across versions that lack .State). */
private function stateFromStatus(string $status): string
{
diff --git a/resources/views/components/badge.blade.php b/resources/views/components/badge.blade.php
index 0f91072..3839323 100644
--- a/resources/views/components/badge.blade.php
+++ b/resources/views/components/badge.blade.php
@@ -1,4 +1,4 @@
-@props(['tone' => 'neutral'])
+@props(['tone' => 'neutral', 'size' => 'sm'])
@php
$c = [
'neutral' => 'text-ink-2 border-line bg-line',
@@ -6,5 +6,8 @@
'cyan' => 'text-cyan-bright border-cyan/20 bg-cyan/10',
'warning' => 'text-warning border-warning/25 bg-warning/10',
][$tone] ?? 'text-ink-2 border-line bg-line';
+ // md = control-row height (matches x-status-pill/x-btn h-8) for badges sitting in a row
+ // with pills/buttons; sm stays the compact inline chip for badges next to plain text.
+ $s = $size === 'md' ? 'h-8 px-2.5 text-xs' : 'px-2 py-0.5 text-[11px]';
@endphp
-merge(['class' => "inline-flex items-center gap-1 rounded-sm border px-2 py-0.5 font-mono text-[11px] $c"]) }}>{{ $slot }}
+merge(['class' => "inline-flex items-center gap-1 rounded-sm border font-mono $s $c"]) }}>{{ $slot }}
diff --git a/resources/views/components/btn.blade.php b/resources/views/components/btn.blade.php
index 37a89bf..8a0b6ca 100644
--- a/resources/views/components/btn.blade.php
+++ b/resources/views/components/btn.blade.php
@@ -14,10 +14,13 @@
// sm = compact toolbar/row buttons; lg = full-height primary CTA (≥44px touch target, R7).
// sm stays 32px visually on a fine pointer (mouse) for density, but grows to the 44px R7
// minimum on a COARSE pointer (touch) so row actions are tappable — desktop is unaffected.
+ // field = form-row button that must line up with an h-9 input on EVERY device: fixed h-9,
+ // NO coarse min-h-11 bump (which would make it taller than the field it sits beside on touch).
$sizes = [
'sm' => ($icon
? 'h-8 w-8 [@media(pointer:coarse)]:h-11 [@media(pointer:coarse)]:w-11'
: 'h-8 px-3 [@media(pointer:coarse)]:min-h-11').' text-xs',
+ 'field' => 'h-9 px-3 text-xs',
'lg' => ($icon ? 'h-11 w-11' : 'h-11 px-4').' text-sm',
];
$classes = 'inline-flex items-center justify-center gap-1.5 rounded-md font-medium transition-colors '
diff --git a/resources/views/components/docker-container-row.blade.php b/resources/views/components/docker-container-row.blade.php
index 60aef84..aa60be4 100644
--- a/resources/views/components/docker-container-row.blade.php
+++ b/resources/views/components/docker-container-row.blade.php
@@ -15,14 +15,15 @@
-
{{ $c['name'] }}
+ {{-- Display name strips the compose replica suffix; hover shows the real name. --}}
+
{{ $c['display'] ?? $c['name'] }}
{{ $c['image'] }}
{{ $c['state'] ?: '—' }}
@if ($canOperate)
-
{{ __('docker.logs') }}
+
{{ __('docker.logs') }}
@if ($c['state'] === 'running')
{{ __('docker.restart') }}
{{ __('docker.stop') }}
diff --git a/resources/views/components/lang-switch.blade.php b/resources/views/components/lang-switch.blade.php
index 6cfc39f..e8b69e6 100644
--- a/resources/views/components/lang-switch.blade.php
+++ b/resources/views/components/lang-switch.blade.php
@@ -1,7 +1,7 @@
{{-- DE/EN language switch (R16). Plain links → full reload so the whole UI re-renders
in the chosen language; persists per-user + session via the locale route. --}}
@php $current = app()->getLocale(); @endphp
-
-
{{ __('certs.add') }}
+
{{ __('certs.add') }}
{{-- Endpoints --}}
@if ($endpoints->isEmpty())
-
+
+
+
+
{{ __('certs.no_endpoints_title') }}
-
{{ __('certs.no_endpoints') }}
+
{{ __('certs.no_endpoints') }}
@else
diff --git a/resources/views/livewire/commands/index.blade.php b/resources/views/livewire/commands/index.blade.php
index c53615e..c0504cb 100644
--- a/resources/views/livewire/commands/index.blade.php
+++ b/resources/views/livewire/commands/index.blade.php
@@ -112,14 +112,14 @@
{{ __('commands.new_runbook') }}
diff --git a/resources/views/livewire/dashboard.blade.php b/resources/views/livewire/dashboard.blade.php
index 594d604..d1782a9 100644
--- a/resources/views/livewire/dashboard.blade.php
+++ b/resources/views/livewire/dashboard.blade.php
@@ -84,10 +84,13 @@
+
-
- {{ __('dashboard.axis_minus_15min') }} -10 -5 {{ __('dashboard.axis_now') }}
-
+ {{-- X axis OUTSIDE the relative wrapper (mirrors servers/show.blade.php): keeps the
+ y-rail's inset-y-0 spanning exactly the plot, so the "0" tick lands on the bottom
+ gridline instead of colliding with "-15 Min" down here. --}}
+
+ {{ __('dashboard.axis_minus_15min') }} -10 -5 {{ __('dashboard.axis_now') }}
diff --git a/resources/views/livewire/health/index.blade.php b/resources/views/livewire/health/index.blade.php
index 0693a9f..61a68af 100644
--- a/resources/views/livewire/health/index.blade.php
+++ b/resources/views/livewire/health/index.blade.php
@@ -41,16 +41,19 @@
@error('port') {{ $message }}
@enderror
- {{ __('health.add') }}
+ {{ __('health.add') }}
{{-- Checks --}}
@if ($checks->isEmpty())
-
+
+
+
+
{{ __('health.no_checks_title') }}
-
{{ __('health.no_checks') }}
+
{{ __('health.no_checks') }}
@else
diff --git a/resources/views/livewire/modals/container-logs.blade.php b/resources/views/livewire/modals/container-logs.blade.php
index 77a2f52..582ab42 100644
--- a/resources/views/livewire/modals/container-logs.blade.php
+++ b/resources/views/livewire/modals/container-logs.blade.php
@@ -4,7 +4,7 @@
-
{{ $ref }}
+
{{ $name !== '' ? $name : $ref }}
{{ __('docker.logs_subtitle') }}
diff --git a/resources/views/livewire/servers/groups.blade.php b/resources/views/livewire/servers/groups.blade.php
index eaf7913..95bf857 100644
--- a/resources/views/livewire/servers/groups.blade.php
+++ b/resources/views/livewire/servers/groups.blade.php
@@ -41,7 +41,7 @@
@endforeach
- {{ __('groups.create') }}
+ {{ __('groups.create') }}
diff --git a/resources/views/livewire/servers/show.blade.php b/resources/views/livewire/servers/show.blade.php
index 2588ca3..cd0af9b 100644
--- a/resources/views/livewire/servers/show.blade.php
+++ b/resources/views/livewire/servers/show.blade.php
@@ -121,7 +121,7 @@
{{ $cred->name ?: $cred->username }}
{{ $credStatusLabel }}
-
{{ $credAuthLabel }}
+
{{ $credAuthLabel }}
{{ $cred->username }} @{{ $server->ip }}
diff --git a/resources/views/livewire/settings/index.blade.php b/resources/views/livewire/settings/index.blade.php
index 78841d9..7934d4d 100644
--- a/resources/views/livewire/settings/index.blade.php
+++ b/resources/views/livewire/settings/index.blade.php
@@ -38,7 +38,7 @@
class="inline-flex h-8 items-center gap-1.5 rounded-md border border-line px-3 font-mono text-[11px] text-ink-2 transition-colors hover:border-accent/40 hover:text-accent-text">
{{ __('onboarding.relaunch') }}
- {{ $u->role?->label() ?? __('settings.role_admin') }}
+ {{ $u->role?->label() ?? __('settings.role_admin') }}
diff --git a/resources/views/livewire/settings/webauthn-keys.blade.php b/resources/views/livewire/settings/webauthn-keys.blade.php
index 35eba2f..a35c716 100644
--- a/resources/views/livewire/settings/webauthn-keys.blade.php
+++ b/resources/views/livewire/settings/webauthn-keys.blade.php
@@ -31,7 +31,7 @@
-
+
{{ __('auth.webauthn_add') }}
diff --git a/resources/views/livewire/system/index.blade.php b/resources/views/livewire/system/index.blade.php
index d33b587..56434f2 100644
--- a/resources/views/livewire/system/index.blade.php
+++ b/resources/views/livewire/system/index.blade.php
@@ -82,7 +82,7 @@
placeholder="{{ __('system.domain_placeholder') }}"
class="h-9 w-full rounded-md border border-line bg-inset px-3 font-mono text-sm text-ink placeholder:text-ink-4 focus:border-accent/40 focus:outline-none" />
@can('manage-panel')
-
+
{{ __('common.save') }}
@endcan
diff --git a/resources/views/livewire/threats/index.blade.php b/resources/views/livewire/threats/index.blade.php
index 818b786..0fad308 100644
--- a/resources/views/livewire/threats/index.blade.php
+++ b/resources/views/livewire/threats/index.blade.php
@@ -131,7 +131,7 @@
@if ($events->lastPage() > 1)
onFirstPage())
- class="inline-flex items-center gap-1 rounded-md border border-line bg-raised px-2.5 py-3 font-mono text-[11px] text-ink-2 transition-colors hover:border-accent/30 hover:text-ink disabled:cursor-not-allowed disabled:opacity-40 disabled:hover:border-line disabled:hover:text-ink-2 lg:py-1.5">
+ class="inline-flex h-11 items-center gap-1 rounded-md border border-line bg-raised px-2.5 font-mono text-[11px] text-ink-2 transition-colors hover:border-accent/30 hover:text-ink disabled:cursor-not-allowed disabled:opacity-40 disabled:hover:border-line disabled:hover:text-ink-2 lg:h-7">
{{ __('threats.pagination_prev') }}
@@ -153,7 +153,7 @@
hasMorePages())
- class="inline-flex items-center gap-1 rounded-md border border-line bg-raised px-2.5 py-3 font-mono text-[11px] text-ink-2 transition-colors hover:border-accent/30 hover:text-ink disabled:cursor-not-allowed disabled:opacity-40 disabled:hover:border-line disabled:hover:text-ink-2 lg:py-1.5">
+ class="inline-flex h-11 items-center gap-1 rounded-md border border-line bg-raised px-2.5 font-mono text-[11px] text-ink-2 transition-colors hover:border-accent/30 hover:text-ink disabled:cursor-not-allowed disabled:opacity-40 disabled:hover:border-line disabled:hover:text-ink-2 lg:h-7">
{{ __('threats.pagination_next') }}
diff --git a/resources/views/livewire/versions/index.blade.php b/resources/views/livewire/versions/index.blade.php
index 060c1d8..0b1041f 100644
--- a/resources/views/livewire/versions/index.blade.php
+++ b/resources/views/livewire/versions/index.blade.php
@@ -226,7 +226,7 @@
@if ($totalPages > 1)
+ class="inline-flex h-11 items-center gap-1 rounded-md border border-line bg-raised px-2.5 font-mono text-[11px] text-ink-2 transition-colors hover:border-accent/30 hover:text-ink disabled:cursor-not-allowed disabled:opacity-40 disabled:hover:border-line disabled:hover:text-ink-2 lg:h-7">
{{ __('versions.pagination_prev') }}
@@ -248,7 +248,7 @@
= $totalPages)
- class="inline-flex items-center gap-1 rounded-md border border-line bg-raised px-2.5 py-3 font-mono text-[11px] text-ink-2 transition-colors hover:border-accent/30 hover:text-ink disabled:cursor-not-allowed disabled:opacity-40 disabled:hover:border-line disabled:hover:text-ink-2 lg:py-1.5">
+ class="inline-flex h-11 items-center gap-1 rounded-md border border-line bg-raised px-2.5 font-mono text-[11px] text-ink-2 transition-colors hover:border-accent/30 hover:text-ink disabled:cursor-not-allowed disabled:opacity-40 disabled:hover:border-line disabled:hover:text-ink-2 lg:h-7">
{{ __('versions.pagination_next') }}
diff --git a/resources/views/livewire/wireguard/index.blade.php b/resources/views/livewire/wireguard/index.blade.php
index d3ca331..6659694 100644
--- a/resources/views/livewire/wireguard/index.blade.php
+++ b/resources/views/livewire/wireguard/index.blade.php
@@ -111,12 +111,12 @@
{{ __('wireguard.ssh_lock') }}
@if ($status['gate']['ssh'])
- {{ __('wireguard.ssh_lock_on_state') }}
+ {{ __('wireguard.ssh_lock_on_state') }}
{{ __('wireguard.ssh_lock_turn_off') }}
@else
- {{ __('wireguard.ssh_lock_off_state') }}
+ {{ __('wireguard.ssh_lock_off_state') }}
{{ __('wireguard.ssh_lock_turn_on') }}
@endif
diff --git a/tests/Feature/DockerServiceTest.php b/tests/Feature/DockerServiceTest.php
index 2e37599..7d592ce 100644
--- a/tests/Feature/DockerServiceTest.php
+++ b/tests/Feature/DockerServiceTest.php
@@ -47,11 +47,20 @@ class DockerServiceTest extends TestCase
$this->assertCount(3, $rows);
$this->assertSame('web', $rows[0]['name']);
+ $this->assertSame('web', $rows[0]['display']); // no replica suffix -> unchanged
$this->assertSame('running', $rows[0]['state']); // "Up ..."
$this->assertSame('exited', $rows[1]['state']); // "Exited ..."
$this->assertSame('paused', $rows[2]['state']); // "Up ... (Paused)"
}
+ public function test_display_name_strips_the_compose_replica_suffix_only(): void
+ {
+ $this->assertSame('clusev-app', DockerService::displayName('clusev-app-1'));
+ $this->assertSame('web', DockerService::displayName('web-12'));
+ $this->assertSame('unruffled_leavitt', DockerService::displayName('unruffled_leavitt'));
+ $this->assertSame('clusev-app', DockerService::displayName('clusev-app'));
+ }
+
public function test_containers_throws_the_real_error_when_docker_fails(): void
{
[$docker, $fleet] = $this->make();