mirror of
https://github.com/karatektus/pl_mail.git
synced 2026-10-25 01:54:10 +00:00
Four kinds, each of which ignored the theme it was drawn in: - Checkboxes and radios asked for the accent through `text-accent`. A native box is coloured by accent-color; `color` reaches it only through @tailwindcss/forms, which this app does not load, so every one of them was ticked in the browser's own blue. They use `accent-accent`, and modal_form_theme says why. - Icons and icon buttons in admin, settings and the thread row's hover actions were Tailwind's zinc-400 and gray-400, with dark: variants and grey hover washes. They are ink-faint, with hover:text-ink and hover:bg-hover, or hover:bg-danger-soft for the destructive ones. - The state pills on bg-raised wrote ink-faint, a tier held to 4.5:1 on the surface, which the raised tint under them takes as low as 3.85:1 (14 of 39 themes under 4.5). They use ink-muted. - Accent buttons wrote text-white, which a light accent cannot carry. They use the accent's own ink. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
116 lines
6.3 KiB
Twig
116 lines
6.3 KiB
Twig
{#
|
|
settings/_push_devices.html.twig — the devices this account can be pushed to.
|
|
|
|
Accepts:
|
|
devices — list<App\Entity\User\PushSubscription>, newest first
|
|
lastDeliveries — map of deviceClientId => App\Domain\DTO\Push\LastDelivery,
|
|
with no entry for a device nothing has been sent to yet
|
|
|
|
Sits under the browser toggle, and answers a different question from it. The
|
|
toggle is about THIS browser and is resolved by JavaScript on connect; this is
|
|
every device registered against the account — the phone, the tablet, the other
|
|
laptop — which the person asking "why did my phone stop buzzing?" cannot see
|
|
anywhere else.
|
|
|
|
Three facts per row, and each is here because its absence produced a support
|
|
question. The **transport** because a device on Firebase and one on a
|
|
UnifiedPush distributor fail for entirely different reasons. **Verified**
|
|
because an unverified subscription receives NOTHING by design (RFC 8620
|
|
§7.2.2), which looks exactly like a broken one. And the **last delivery**,
|
|
because "we tried and Firebase said the token is dead" and "nothing has ever
|
|
been sent to this device" are the two answers, and they are opposites.
|
|
|
|
Each row can also be removed, which is the only way to be rid of a subscription
|
|
that is working exactly as designed and should not exist — the classic case
|
|
being an old build of an app still registered under a stale device id, so one
|
|
phone receives everything twice. The delivery log is addressed by device id and
|
|
not by a relation, so the removed device's history stays readable afterwards.
|
|
|
|
What is deliberately NOT shown: what was pushed. The log stores the payload's
|
|
`@type` and nothing else — see the PushDelivery docblock — so this line can say
|
|
a state change was delivered and can never say which mail it was about.
|
|
#}
|
|
<div class="px-4 py-3.5 border-t border-line">
|
|
|
|
<p class="text-sm text-ink">{{ 'settings.notifications.devices.heading'|trans }}</p>
|
|
|
|
{% if devices|length == 0 %}
|
|
<p class="mt-1.5 text-[11px] text-ink-faint leading-relaxed">
|
|
{{ 'settings.notifications.devices.empty'|trans }}
|
|
</p>
|
|
{% else %}
|
|
<ul class="mt-2.5 space-y-2.5">
|
|
{% for device in devices %}
|
|
{# Keyed by the client's own device id, which is what the log
|
|
records — a subscription that rotated its endpoint or its FCM
|
|
token keeps it, so its history survives the rotation. #}
|
|
{% set last = lastDeliveries[device.deviceClientId] ?? null %}
|
|
{% set toneClass = last is null ? 'badge-neutral' : {
|
|
success: 'badge-success',
|
|
danger: 'badge-danger',
|
|
warning: 'badge-warning',
|
|
neutral: 'badge-neutral',
|
|
}[last.outcome.tone] %}
|
|
|
|
<li class="flex flex-wrap items-center gap-x-2.5 gap-y-1">
|
|
<span class="text-xs text-ink-soft font-mono truncate max-w-[12rem]">{{ device.deviceClientId }}</span>
|
|
|
|
<span class="text-[10px] font-medium px-2 py-0.5 rounded-full bg-raised text-ink-muted">
|
|
{{ ('settings.notifications.devices.transport.' ~ device.transport.value)|trans }}
|
|
</span>
|
|
|
|
{% if device.verified %}
|
|
<span class="text-[10px] font-medium px-2 py-0.5 rounded-full badge-success">
|
|
{{ 'settings.notifications.devices.verified'|trans }}
|
|
</span>
|
|
{% else %}
|
|
{# Amber rather than red: the handshake being incomplete
|
|
is the normal state for the first few seconds after
|
|
registering, and only a problem if it stays. #}
|
|
<span class="text-[10px] font-medium px-2 py-0.5 rounded-full badge-warning">
|
|
{{ 'settings.notifications.devices.unverified'|trans }}
|
|
</span>
|
|
{% endif %}
|
|
|
|
<span class="w-full @2xl:w-auto text-[11px] text-ink-faint">
|
|
{% if last is null %}
|
|
{{ 'settings.notifications.devices.never_delivered'|trans }}
|
|
{% else %}
|
|
<span class="text-[10px] font-medium px-2 py-0.5 rounded-full {{ toneClass }}">
|
|
{{ ('settings.notifications.devices.outcome.' ~ last.outcome.value)|trans }}
|
|
</span>
|
|
{{ last.at|date('Y-m-d H:i') }}
|
|
{% if last.payloadType is not null %}
|
|
· {{ last.payloadType }}
|
|
{% endif %}
|
|
{% endif %}
|
|
</span>
|
|
|
|
{# The only way to be rid of a device that is working
|
|
perfectly and should not be — an old build of an app
|
|
still registered under a device id nobody uses, pushing
|
|
a second copy of everything at the same phone. Automatic
|
|
retirement never reaches it, because nothing about it
|
|
fails.
|
|
|
|
Confirmed inline like the app-password row rather than
|
|
through a modal, and the confirm text carries the honest
|
|
half: this stops deliveries, it does not uninstall
|
|
anything, and a device whose app still wants push will
|
|
register itself again. #}
|
|
<form method="post"
|
|
action="{{ path('app_push_device_remove', { id: device.id }) }}"
|
|
data-turbo-stream class="ml-auto shrink-0"
|
|
data-turbo-confirm="{{ 'settings.notifications.devices.remove_confirm'|trans({ '%device%': device.deviceClientId }) }}">
|
|
<input type="hidden" name="_token" value="{{ csrf_token('push-device-remove' ~ device.id) }}">
|
|
<button type="submit"
|
|
class="text-[11px] text-ink-faint hover:text-red-400 transition-colors cursor-pointer">
|
|
{{ 'settings.notifications.devices.remove'|trans }}
|
|
</button>
|
|
</form>
|
|
</li>
|
|
{% endfor %}
|
|
</ul>
|
|
{% endif %}
|
|
</div>
|