{{ __('admin_settings.title') }}

{{ __('admin_settings.subtitle') }}

{{-- Version & update --}} @if ($canManageSite) {{-- Polls itself: an operator watching an update run should not have to reload the page to find out whether it finished. Fast while something is happening, slow when nothing is. wire:poll alone is not enough, because the thing being watched restarts the thing doing the watching. Mid-run the requests fail, and what answers afterwards is a NEW build being questioned by the old page's JavaScript — so the card sat on "läuft" until somebody reloaded. The watcher below rides through that: it asks a plain JSON endpoint, treats a failed request as the restart rather than as an error, and reloads the page once the build it is looking at is no longer the build it started with. --}}

{{ __('admin_settings.update_title') }}

@if ($update['running']) {{ __('admin_settings.update_running') }} @elseif ($update['available']) {{ __('admin_settings.update_available', ['n' => $update['behind']]) }} @elseif ($update['behind'] === 0) {{ __('admin_settings.update_current') }} @else {{-- Never shown as "up to date": not knowing and being current are different answers. --}} {{ __('admin_settings.update_unknown') }} @endif
{{ __('admin_settings.update_version') }}:
{{ $update['version'] }}@if ($update['commit']) · {{ substr($update['commit'], 0, 7) }}@endif
@if ($update['source'])
{{ __('admin_settings.update_source') }}:
{{ $update['source'] }}
@endif @if ($update['deployed_at'])
{{ __('admin_settings.update_deployed') }}:
{{ $update['deployed_at']->diffForHumans() }}
@endif @if ($update['checked_at'])
{{ __('admin_settings.update_checked') }}:
{{ $update['checked_at']->diffForHumans() }}
@endif
{{-- Bound, not @disabled(): the directive compiles to inline PHP inside the component tag, and Blade then stops seeing a component. The button used to be offered ONLY when the last check had found something. But "behind" is a READING, taken every few minutes — it is not the state of the world. Push a commit and for the next few minutes the console insists everything is current and refuses to do anything about it, which is precisely how it was reported. The agent fetches before it decides, so asking against a stale reading costs one fetch and finds nothing; being locked out costs the deployment. Still disabled for the two cases where the request really would go nowhere: a run already in flight, and no agent. --}}
@if ($update['running']) {{ __('admin_settings.update_running') }} @elseif (! $update['agent_seen']) {{ __('admin_settings.update_unknown') }} @elseif ($update['available']) {{ __('admin_settings.update_now') }} @else {{-- Named for what it does rather than for what the last reading said: it re-checks, and updates if there is anything to update. --}} {{ __('admin_settings.update_recheck') }} @endif
@if (! $update['agent_seen']) {{ __('admin_settings.update_no_agent') }} @elseif ($update['last_error']) {{ $update['last_error'] }} @endif {{-- Where it is. "Läuft gerade" alone is what sends an operator to the shell: the service checks on a timer, so a queued update does nothing at all for up to five minutes, and while it runs the site is in maintenance mode and this page is unreachable. Both of those look identical to "wedged" without a time. --}} @if ($update['running'])
@if ($update['phase'])

{{ __('admin_settings.update_step', ['step' => $update['phase']]) }}

@if ($update['started_at'])

{{ __('admin_settings.update_since', ['when' => $update['started_at']->diffForHumans()]) }}

@endif @elseif ($update['next_check_at'])

{{ __('admin_settings.update_queued', ['time' => $update['next_check_at']->local()->format('H:i')]) }}

@endif

{{ __('admin_settings.update_offline_hint') }}

@endif @if ($update['last_state'] !== null && ! $update['running'])

{{ __('admin_settings.update_last_run', [ 'state' => __('admin_settings.update_state.'.$update['last_state']), 'when' => $update['last_finished_at']?->diffForHumans() ?? '—', ]) }} @if ($update['last_started_at'] && $update['last_finished_at']) · {{ __('admin_settings.update_took', ['duration' => $update['last_started_at']->diffForHumans($update['last_finished_at'], true)]) }} @endif {{-- Only on a failure: on a run that worked the last step is "left maintenance mode", which says nothing. --}} @if ($update['last_state'] === 'failed' && $update['last_phase']) · {{ __('admin_settings.update_failed_at', ['step' => $update['last_phase']]) }} @endif

@endif {{-- Open while it runs: "läuft gerade" on its own tells an operator nothing about whether it is progressing or wedged. --}} @if ($updateLog)
{{ __('admin_settings.update_log') }}
{{ $updateLog }}
@endif
@endif {{-- My account --}} @if ($canManageSite)

{{ __('admin_settings.site_title') }}

{{ $sitePublic ? __('admin_settings.site_public') : __('admin_settings.site_hidden') }}

{{ $sitePublic ? __('admin_settings.site_public_body') : __('admin_settings.site_hidden_body') }}

{{ __('admin_settings.site_your_view', ['ip' => request()->ip()]) }} {{ $viewerOnVpn ? __('admin_settings.site_via_vpn') : __('admin_settings.site_not_vpn') }}

{{ $sitePublic ? __('admin_settings.site_hide') : __('admin_settings.site_show') }}
@endif {{-- Who may reach this console --}} @if ($canManageSite)

{{ __('admin_settings.console_title') }}

{{ $consoleRestricted ? __('admin_settings.console_locked_badge') : __('admin_settings.console_open_badge') }}

{{ $consoleRestricted ? __('admin_settings.console_locked_body') : __('admin_settings.console_open_body') }}

{{ __('admin_settings.console_your_ip', ['ip' => $viewerIp]) }}

{{ $consoleRestricted ? __('admin_settings.console_unlock') : __('admin_settings.console_lock') }}

{{ __('admin_settings.console_always') }}

@foreach ($consoleVpnRanges as $range)
{{ $range }} {{ __('admin_settings.console_vpn_note') }}
@endforeach

{{ __('admin_settings.console_extra') }}

@forelse ($consoleIps as $ip)
{{ $ip }} {{ __('admin_settings.console_remove') }}
@empty

{{ __('admin_settings.console_none') }}

@endforelse {{-- The hint sits under the row, not inside it: as a sibling of the field it made the flex row as tall as field-plus-hint, and the button stretched to match. --}}
{{ __('admin_settings.console_add') }}

{{ __('admin_settings.console_ip_hint') }}

@endif {{-- Own password. There was no way to change one at all: an account created with a generated password kept it until someone opened a shell. --}}

{{ __('admin_settings.password_title') }}

{{ __('admin_settings.password_sub') }}

{{ __('admin_settings.password_save') }}

{{ __('admin_settings.account_title') }}

{{ __('admin_settings.twofa_hint') }}

{{ __('admin_settings.save') }}
{{-- Staff & access (Owner-only) --}} @if ($canManageStaff)

{{ __('admin_settings.staff_title') }}

{{ __('admin_settings.staff_sub') }}

{{-- Invite --}}
@error('staffName')

{{ $message }}

@enderror
@error('staffEmail')

{{ $message }}

@enderror
@error('staffRole')

{{ $message }}

@enderror
{{ __('admin_settings.invite') }}

{{ __('admin_settings.invite_hint') }}

@if ($invitedPassword)

{{ __('admin_settings.temp_title') }}

{{ __('admin_settings.temp_hint') }}

{{ __('admin_settings.email') }}:
{{ $invitedEmail }}
{{ __('admin_settings.temp_password') }}:
{{ $invitedPassword }}
@endif {{-- Staff list --}}
@foreach ($staff as $s) @endforeach
{{ __('admin_settings.col_person') }} {{ __('admin_settings.role') }} {{ __('admin_settings.col_actions') }}

{{ $s['name'] }} @if ($s['self'])({{ __('admin_settings.you') }})@endif

{{ $s['email'] }}

@if ($s['self']) {{ __('admin_settings.role_'.\Illuminate\Support\Str::slug($s['role'])) }} @else @endif {{-- Your own row has no actions — you cannot revoke yourself — and an empty cell reads as a bug rather than as a rule. --}} @if ($s['self']) @endif @unless ($s['self']) @endunless
@endif