61 lines
3.3 KiB
HTML
61 lines
3.3 KiB
HTML
{% extends "ui/templates/base/layout.html" %}
|
|
{% block content %}
|
|
<div class="space-y-6">
|
|
<div class="rounded-2xl bg-white p-6 shadow-card ring-1 ring-slate-200">
|
|
<div class="flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between">
|
|
<div>
|
|
<h2 class="text-xl font-semibold text-slate-900">Email Queue & Retry</h2>
|
|
<p class="mt-1 text-sm text-slate-500">Pending and failed emails that can be retried without disturbing the original business transaction.</p>
|
|
</div>
|
|
<div class="flex flex-wrap items-center gap-2">
|
|
<a href="/email/settings" class="rounded-xl border border-slate-300 px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-50">Settings</a>
|
|
<a href="/email/logs" class="rounded-xl border border-slate-300 px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-50">Logs</a>
|
|
<form method="post" action="/email/queue/process" class="flex items-center gap-2">
|
|
<input type="hidden" name="csrf_token" value="{{ csrf_token }}" />
|
|
<input type="number" name="limit" value="25" min="1" max="100" class="w-20 rounded-xl border border-slate-300 px-3 py-2 text-sm" />
|
|
<button class="rounded-xl bg-brand-600 px-4 py-2 text-sm font-semibold text-white hover:bg-brand-700">Process Queue</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
{% if flash %}
|
|
<div class="mt-4 rounded-xl border border-emerald-200 bg-emerald-50 px-4 py-3 text-sm text-emerald-800">{{ flash }}</div>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<section class="rounded-2xl bg-white p-6 shadow-card ring-1 ring-slate-200">
|
|
<div class="overflow-x-auto">
|
|
<table class="min-w-full divide-y divide-slate-200 text-sm">
|
|
<thead>
|
|
<tr class="text-left text-xs uppercase tracking-wide text-slate-500">
|
|
<th class="py-2 pr-4">Queued</th>
|
|
<th class="py-2 pr-4">Next Retry</th>
|
|
<th class="py-2 pr-4">Attempts</th>
|
|
<th class="py-2 pr-4">To</th>
|
|
<th class="py-2 pr-4">Template</th>
|
|
<th class="py-2 pr-4">Subject</th>
|
|
<th class="py-2 pr-4">Status</th>
|
|
<th class="py-2 pr-4">Error</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody class="divide-y divide-slate-100">
|
|
{% for log in queue_rows %}
|
|
<tr class="align-top">
|
|
<td class="py-3 pr-4 text-slate-500 whitespace-nowrap">{{ log.queued_at or log.created_at_utc }}</td>
|
|
<td class="py-3 pr-4 text-slate-500 whitespace-nowrap">{{ log.next_retry_at or 'Ready' }}</td>
|
|
<td class="py-3 pr-4 whitespace-nowrap">{{ log.attempt_count or 0 }} / {{ log.max_attempts or 3 }}</td>
|
|
<td class="py-3 pr-4">{{ log.recipient_email }}</td>
|
|
<td class="py-3 pr-4 text-slate-600">{{ log.template_code or '-' }}</td>
|
|
<td class="py-3 pr-4 max-w-sm truncate">{{ log.subject }}</td>
|
|
<td class="py-3 pr-4"><span class="rounded-full bg-slate-100 px-2 py-1 text-xs font-semibold">{{ log.status }}</span></td>
|
|
<td class="py-3 pr-4 max-w-md truncate text-red-600">{{ log.error_message or '' }}</td>
|
|
</tr>
|
|
{% else %}
|
|
<tr><td colspan="8" class="py-10 text-center text-slate-500">No pending or failed retryable emails.</td></tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
{% endblock %}
|