{{ $c['name'] }}
{{ $c['image'] }}
@if($running){{ __('client.hosting.containers.running') }}
@elseif($c['state'] === 'restarting')
{{-- Restarting on a loop means the app is failing to start.
Saying "restarting" leaves the customer watching a
spinner that never ends. --}}
{{ __('client.hosting.containers.crashing') }}
@else{{ $c['state'] ?: __('client.hosting.containers.stopped') }}@endif
@if($running)
@else
@endif
{{ __('client.hosting.containers.crashing_hint') }}
@endif
@if($components)
{{-- The app's helpers (database, cache). Drawn inside the app's
card, without their own action buttons: start, stop and delete
act on the whole app, and a database cannot be removed from
under a running site. --}}
{{ __('client.hosting.containers.components') }}
@foreach($components as $comp)
{{ ucfirst($comp['role'] ?: $comp['name']) }}
@endforeach
@endif
CPU{{ $running ? number_format($c['cpu_percent'], 1).'%' : '—' }}
RAM{{ $running && $c['mem_usage'] >= 1048576 ? number_format($c['mem_usage']/1048576, 0).' MB' : '—' }}@if($running && $c['mem_limit'] > 0) / {{ number_format($c['mem_limit']/1048576, 0) }} MB @endif
{{ __('client.hosting.containers.ports') }}
@forelse($c['ports'] as $p){{ $p }}@empty — @endforelse
{{ __('client.hosting.containers.domain') }}
@if($linkedId)
{{ $domains[$linkedId] }}
@elseif($running && $freeDomains)
@elseif(! $running)
{{ __('client.hosting.containers.domain_needs_running') }}
@else
{{ __('client.hosting.containers.domain_none') }}
@endif
@if($acc && $acc->accessUrl())
{{-- The address is the first thing anyone wants after installing,
so it is a button, not a line inside a disclosure. --}}
{{ __('client.hosting.containers.open_app') }}
@endif
{{-- A plain OS container runs `sleep infinity` and has no SSH in
it, so the only way in is a shell through the panel. Root or
the image's own user, because a hardened image drops to a
non-root user and half the work needs the other one. --}}
@endif
{{ __('client.hosting.containers.terminal') }}
{{ __('client.hosting.containers.terminal_default') }}
{{ __('client.hosting.containers.terminal_root') }}
@if($acc && ($acc->items() || $acc->notes()))
@php
// The raw list mixed URLs, logins and infrastructure in
// whatever order they were stored. Read top to bottom it
// should answer "where do I go, who am I, what's the
// password" - so: addresses, then usernames, then secrets,
// then the plumbing.
$accWeight = function (string $label, string $value): int {
if (\Illuminate\Support\Str::startsWith($value, ['http://', 'https://'])) return 0;
if (preg_match('/(user|login|email)/i', $label) && ! preg_match('/(password|passwd|secret|token)/i', $label)) return 1;
if (preg_match('/(password|passwd|secret|token|key)/i', $label)) return 2;
if (preg_match('/(dir|path|directory)/i', $label)) return 4;
return 3;
};
$accItems = collect($acc->items())
->sortBy(fn ($v, $k) => $accWeight((string) $k, (string) $v))
->all();
// ENV_STYLE_LABELS read like configuration, not like a page.
$accLabel = function (string $label): string {
if (! preg_match('/^[A-Z0-9_]+$/', $label)) return $label;
$t = ucwords(strtolower(str_replace('_', ' ', $label)));
return str_ireplace(['Db ', 'Wp ', 'Url', 'Ftp ', 'Ssh '], ['DB ', 'WP ', 'URL', 'FTP ', 'SSH '], $t);
};
@endphp
{{ __('client.hosting.containers.access_title') }}
@foreach($accItems as $label => $value)
@php
// A generated password should not sit on screen in a
// shared office; it is one click away instead.
$secret = (bool) preg_match('/(password|passwd|secret|token|key)/i', $label);
$isUrl = Str::startsWith($value, ['http://', 'https://']);
@endphp
@endif
{{-- On the customer's own request the same details land in
their inbox - passwords included, that is the point. --}}
{{ $accLabel($label) }}
@if($isUrl)
{{ $value }}
@else
@endforeach
@if($acc->notes())
$secret]) data-value="{{ $value }}">{{ $secret ? str_repeat('•', 10) : $value }}
@endif
{{ __('client.hosting.containers.notes_title') }}
{{ $acc->notes() }}