Files
webhooker/templates/source_logs.html
T
clawbot ae2ce55575
check / check (push) Successful in 3m14s
Event log: show only the events with a failed or a pending delivery (closes #390)
The event log gains three links above the list: All, Failed (N) and Pending (N), carried in a `show` query parameter (`failed`, `pending`); any other value shows every event. Failed lists the events with at least one failed delivery, Pending those with one pending or retrying, under the same 50-row limit and newest-first order as the full list. Events are picked by their deliveries' status through `idx_deliveries_status`; each count is the number of distinct matching events, read from the deliveries alone, and can exceed the 50 shown. An empty filtered list says that no event matches. The README and the comments that name the query parameters the service reads now include `show`.

Model: opus-5-5
2026-10-03 02:08:35 +00:00

110 lines
8.2 KiB
HTML

{{template "base" .}}
{{define "title"}}Full Event Log - {{.Webhook.Name}} - Webhooker{{end}}
{{define "content"}}
<div class="max-w-6xl mx-auto px-6 py-8">
<div class="mb-6">
<a href="/hook/{{.Webhook.ID}}" class="btn-small">&larr; Back to {{.Webhook.Name}}</a>
<div class="flex justify-between items-center mt-2">
<h1 class="text-2xl font-medium text-gray-900">Full Event Log</h1>
<span class="text-sm text-gray-500">{{if gt .TotalEvents (len .Events)}}{{len .Events}} most recent of {{.TotalEvents}} events{{else}}{{.TotalEvents}} total event{{if ne .TotalEvents 1}}s{{end}}{{end}}</span>
</div>
<!-- Plain links, so they work without the page's script library. The current one is marked. -->
<div class="mt-3 flex flex-wrap gap-2">
<a href="/hook/{{.Webhook.ID}}/events" class="btn-small{{if eq .Show ""}} bg-primary-50 border-primary-500{{end}}"{{if eq .Show ""}} aria-current="page"{{end}}>All</a>
<a href="/hook/{{.Webhook.ID}}/events?show=failed" title="Events with at least one failed delivery" class="btn-small{{if eq .Show "failed"}} bg-primary-50 border-primary-500{{end}}"{{if eq .Show "failed"}} aria-current="page"{{end}}>Failed ({{.FailedEvents}})</a>
<a href="/hook/{{.Webhook.ID}}/events?show=pending" title="Events with a delivery still pending or retrying" class="btn-small{{if eq .Show "pending"}} bg-primary-50 border-primary-500{{end}}"{{if eq .Show "pending"}} aria-current="page"{{end}}>Pending ({{.PendingEvents}})</a>
</div>
</div>
<div class="card">
<div class="divide-y divide-gray-100">
<!-- Only the newest event starts expanded. -->
{{range $i, $event := .Events}}
<div class="p-4" x-data="collapsible"{{if eq $i 0}} data-open{{end}}>
<!-- Not a button element: browsers do not let a button's text be selected, and an event's ID must be. -->
<div role="button" tabindex="0" class="btn-small w-full flex flex-wrap justify-between gap-2" :aria-expanded="open" @mousedown="cancelPendingToggle" @click="toggleUnlessSelecting" @keydown.enter.prevent="toggle" @keydown.space.prevent="toggle">
<span class="flex flex-wrap items-center gap-3">
<span class="badge-info">{{.Method}}</span>
<span class="text-sm font-mono text-gray-700">{{.ID}}</span>
<span class="text-sm text-gray-500">{{.ContentType}}</span>
{{if .ResubmittedFrom}}
<span class="text-xs text-gray-500" title="This event is a copy of {{.ResubmittedFromID}}">resubmitted copy</span>
{{end}}
{{if .ResubmitCount}}
<span class="text-xs text-gray-500">resubmitted {{.ResubmitCount}} time{{if ne .ResubmitCount 1}}s{{end}}</span>
{{end}}
</span>
<span class="flex flex-wrap items-center gap-4">
{{range .Deliveries}}
<span class="text-xs {{if eq .Status "delivered"}}text-green-600{{else if eq .Status "failed"}}text-red-600{{else if eq .Status "retrying"}}text-yellow-600{{else}}text-gray-400{{end}}">
{{.Target.DisplayName}}: {{if .Paused}}waiting{{else}}{{.Status}}{{end}}
</span>
{{end}}
<span class="text-xs text-gray-400">{{.CreatedAt.Format "2006-01-02 15:04:05"}}</span>
<!-- The caret has no text to select, so a click on it toggles at once. -->
<svg class="w-4 h-4 text-gray-400 transition-transform" :class="caretClass" @click.stop="toggle" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
</svg>
</span>
</div>
<div x-show="open" x-cloak class="mt-3 p-3 bg-gray-50 rounded-md">
<div class="mb-3 flex flex-wrap items-center justify-between gap-2">
<div class="text-xs text-gray-500">
{{if .ResubmittedFrom}}Resubmitted from event <a href="/hook/{{$.Webhook.ID}}/events/{{.ResubmittedFromID}}" class="btn-small font-mono">{{.ResubmittedFromID}}</a>.{{end}}
{{if .ResubmitCount}}Resubmitted as {{.ResubmitCount}} new event{{if ne .ResubmitCount 1}}s{{end}}.{{end}}
</div>
<form method="POST" action="/hook/{{$.Webhook.ID}}/events/{{.ID}}/resubmit" class="inline">
<input type="hidden" name="csrf_token" value="{{$.CSRFToken}}">
<button type="submit" class="btn-small" title="Submit this event again as a new event, to every currently active target">Resubmit</button>
</form>
</div>
{{template "event_body" .Body}}
{{if .Deliveries}}
<div class="mt-4 border-t border-gray-200 pt-3">
<h3 class="text-xs font-medium uppercase tracking-wide text-gray-500">Deliveries</h3>
<div class="mt-2 divide-y divide-gray-200">
{{range .Deliveries}}
<div class="py-2" x-data="collapsible">
<div class="flex items-center gap-3">
<button type="button" class="btn-small flex-1 flex-wrap justify-between gap-2 text-left" @click="toggle">
<span class="flex flex-wrap items-center gap-3">
<span class="text-sm text-gray-700">{{.Target.DisplayName}}</span>
<span class="text-xs {{if eq .Status "delivered"}}text-green-600{{else if eq .Status "failed"}}text-red-600{{else if eq .Status "retrying"}}text-yellow-600{{else}}text-gray-400{{end}}">{{with .Paused}}waiting: target paused after repeated failures, next try no earlier than {{.Until}} ({{.Relative}}){{else}}{{.Status}}{{end}}</span>
</span>
<span class="flex flex-wrap items-center gap-3">
<span class="text-xs text-gray-400">{{.AttemptCount}} attempt{{if ne .AttemptCount 1}}s{{end}}</span>
<svg class="w-3 h-3 text-gray-400 transition-transform" :class="caretClass" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
</svg>
</span>
</button>
{{if and .Status.Terminal (not .Target.Deleted)}}
<form method="POST" action="/hook/{{$.Webhook.ID}}/deliveries/{{.ID}}/replay" class="inline">
<input type="hidden" name="csrf_token" value="{{$.CSRFToken}}">
<button type="submit" class="btn-small" title="Send this event to the target again">Replay</button>
</form>
{{end}}
</div>
<div x-show="open" x-cloak class="mt-2 space-y-2">
{{template "delivery_attempts" .}}
</div>
</div>
{{end}}
</div>
</div>
{{end}}
</div>
</div>
{{else}}
<div class="p-12 text-center text-sm text-gray-500">{{if eq $.Show "failed"}}No event has a failed delivery.{{else if eq $.Show "pending"}}No event has a delivery pending or retrying.{{else}}No events recorded yet.{{end}}</div>
{{end}}
</div>
</div>
</div>
{{end}}