check / check (push) Waiting to run
Each row of the recent events on the webhook page links to the
event's own page, /hook/{id}/events/{eventID}, and expands to show its
body; only the newest starts expanded. The event's page shows its
details, its whole body and every delivery with its attempts.
One renderer, newBodyView with templates/event_body.html, shows a body
in all three places: whole up to 32 KiB, cut there in the lists with a
link to the event's page, JSON pretty-printed, a body of more than 200
lines or 32 KiB in a scrolling box, and a body that is not text left
out beside its download link. A resubmitted copy links to its
original's page.
Model: opus-5-5
116 lines
7.1 KiB
HTML
116 lines
7.1 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">← 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">{{.TotalEvents}} total event{{if ne .TotalEvents 1}}s{{end}}</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<div class="divide-y divide-gray-100">
|
|
{{range .Events}}
|
|
<div class="p-4" x-data="collapsible">
|
|
<button type="button" class="btn-small w-full flex flex-wrap justify-between gap-2 text-left" @click="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}}: {{.Status}}
|
|
</span>
|
|
{{end}}
|
|
<span class="text-xs text-gray-400">{{.CreatedAt.Format "2006-01-02 15:04:05"}}</span>
|
|
<svg class="w-4 h-4 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>
|
|
|
|
<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}}">
|
|
<input type="hidden" name="page" value="{{$.Page}}">
|
|
<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}}">{{.Status}}</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 .Status.Terminal}}
|
|
<form method="POST" action="/hook/{{$.Webhook.ID}}/deliveries/{{.ID}}/replay" class="inline">
|
|
<input type="hidden" name="csrf_token" value="{{$.CSRFToken}}">
|
|
<input type="hidden" name="page" value="{{$.Page}}">
|
|
<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">No events recorded yet.</div>
|
|
{{end}}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Pagination -->
|
|
{{if or .HasPrev .HasNext}}
|
|
<div class="flex justify-center gap-2 mt-6">
|
|
{{if .HasPrev}}
|
|
<a href="/hook/{{.Webhook.ID}}/events?page={{.PrevPage}}" class="btn-secondary text-sm">← Previous</a>
|
|
{{end}}
|
|
<span class="inline-flex items-center px-4 py-2 text-sm text-gray-500">Page {{.Page}} of {{.TotalPages}}</span>
|
|
{{if .HasNext}}
|
|
<a href="/hook/{{.Webhook.ID}}/events?page={{.NextPage}}" class="btn-secondary text-sm">Next →</a>
|
|
{{end}}
|
|
</div>
|
|
{{end}}
|
|
</div>
|
|
{{end}}
|