{{ 'admin.maintenance.restart_pending'|trans({ '%seconds%': restartRequestedAgo }) }}
{{ 'admin.processes.empty'|trans }}
{% else %}| {{ 'admin.processes.type'|trans }} | {{ 'admin.processes.key'|trans }} | {{ 'admin.processes.pid'|trans }} | {{ 'admin.processes.last_beat'|trans }} | |
|---|---|---|---|---|
| {{ ui.dot(row.healthy) }} | {{ row.type }} | {{ row.key }} | {{ row.pid ?? '—' }} | {{ 'admin.ago'|trans({ '%age%': row.age }) }} |
{{ 'admin.maintenance.restart_title'|trans }}
{{ 'admin.maintenance.restart_help'|trans }}
{{ 'admin.maintenance.restart_app_title'|trans }}
{{ 'admin.maintenance.restart_app_help'|trans }}
{# data-turbo="false": this answers with a page, not a redirect, because the process that would have served the redirect is the one being restarted, and Turbo will not render a non-redirect response to a form submission. No data-turbo-confirm for the same reason — Turbo is not handling this submission, so it would never fire, and an attribute that looks like a guard but is not is worse than none. The action is a two-second outage that recovers itself, which is what makes that acceptable here and not on the reset buttons. #}{{ 'admin.maintenance.run_title'|trans }}
{{ 'admin.maintenance.run_help'|trans }}
{{ 'admin.maintenance.heartbeats_title'|trans }}
{{ 'admin.maintenance.heartbeats_help'|trans }}
{{ 'admin.webhooks.empty'|trans }}
{% else %}{{ 'admin.webhooks.delivery.no_token'|trans }}
{% elseif not pushDiagnostics.publicUrlUsable %}{{ 'admin.webhooks.delivery.no_public_url'|trans }}
{% else %}{{ 'admin.webhooks.delivery.endpoint_hint'|trans }}
{% endif %} {# Calendar push is a second delivery path with its own endpoints and its own way of failing, and neither is visible anywhere else in the app — the rows above are mail watches only. The two route literals stay literal — they are paths, not prose, and a translator asked to render them would only be given the chance to break them. #}{{ 'admin.push.calendar_routes'|trans({ '%google%': '/webhook/google/calendar', '%graph%': '/webhook/graph/calendar', }) }} {{ 'admin.push.calendar_domain_verification'|trans }} {{ 'admin.push.calendar_without_public_address'|trans }}
{% if pushDiagnostics.lastFailure %}{{ pushDiagnostics.lastFailure.message }} {% if pushDiagnostics.lastFailure.at %} · {{ pushDiagnostics.lastFailure.at|date('Y-m-d H:i') }} {% endif %}
{% if pushDiagnostics.lastFailure.context %}{{ pushDiagnostics.lastFailure.context|json_encode(constant('JSON_PRETTY_PRINT') b-or constant('JSON_UNESCAPED_SLASHES')) }}
{% endif %}
| {{ event.message }} | ×{{ event.count }} | {{ 'admin.ago'|trans({ '%age%': event.age }) }} |
{{ 'admin.webhooks.delivery.info_logs_off'|trans }}
{% endif %}{{ 'admin.tokens.empty'|trans }}
{% else %}{{ row.error }}
{% endif %}{{ 'admin.queues.empty'|trans }}
{% else %} {# In flight first, and above the totals. A queue that is not moving looks identical to a queue that is empty from the depth column alone; the question being answered here is "what is the worker actually doing right now", so it goes at the top and names the handler rather than counting it. Never paginated: there is one of these per worker process. #}{{ 'admin.queues.in_flight'|trans }} ({{ runningMessages|length }})
{{ 'admin.queues.none_running'|trans }}
{% else %}| {{ 'admin.queues.queue'|trans }} | {{ 'admin.queues.pending'|trans }} | {{ 'admin.queues.running'|trans }} | {{ 'admin.queues.oldest'|trans }} | {{ 'admin.queues.waiting_since'|trans }} |
|---|---|---|---|---|
| {{ row.queue }} | {{ row.pending }} | {% if row.running > 0 %} {{ row.running }} {% else %} 0 {% endif %} | {% if row.oldestAgeSeconds is not null %} {{ queue.duration(row.oldestAgeSeconds) }} {% else %} — {% endif %} | {# Age of the oldest waiting message, which unlike availability does not move when a retry backs off. #}{% if row.waitingSinceSeconds is not null %} {{ queue.duration(row.waitingSinceSeconds) }} {% else %} — {% endif %} |
{{ 'admin.queues.empty'|trans }}
{% endif %}{{ 'admin.queues.loading'|trans }}
{{ 'admin.failed.empty'|trans }}
{% else %} {# Bulk actions: a bad deploy fails messages by the hundred, and the per-row buttons are not a recovery path. #}{{ row.class }}
{% if row.error %}{{ row.error }}
{% endif %} {% if row.failedAt %}{{ row.failedAt|date('Y-m-d H:i:s') }}
{% endif %}| {{ 'admin.accounts.account'|trans }} | {{ 'admin.accounts.threads'|trans }} | {{ 'admin.accounts.messages'|trans }} | {{ 'admin.accounts.last_activity'|trans }} |
|---|---|---|---|
| {{ row.email }} | {{ row.threads }} | {{ row.messages }} | {{ row.last_activity ? row.last_activity|date('Y-m-d H:i') : '—' }} |
| {{ row.table }} | {{ row.size }} |