check / check (push) Successful in 3m39s
An event's ID or content type, or a name with no place to break, ran past its row and was cut off by the card at 390 pixels, and a long webhook name made the webhook page scroll sideways. Both pages' outer containers now carry wrap-anywhere, so such a value breaks only where it must; the event log's title row wraps like the webhook page's. The browser test gains a 390-pixel check of both pages: neither scrolls sideways and nothing shown runs past the page's or its card's edge. Its seeded webhook name and newer event's content type are long enough to fail without the change. Model: opus-5-5
113 lines
8.1 KiB
HTML
113 lines
8.1 KiB
HTML
{{template "base" .}}
|
|
|
|
{{define "title"}}Full Event Log - {{.Webhook.Name}} - Webhooker{{end}}
|
|
|
|
{{define "content"}}
|
|
<!-- wrap-anywhere: a value with no place to break, such as an event's
|
|
ID or content type, breaks where it must instead of running past
|
|
the edge of a phone's screen. -->
|
|
<div class="max-w-6xl mx-auto px-6 py-8 wrap-anywhere">
|
|
<div class="mb-6">
|
|
<a href="/hook/{{.Webhook.ID}}" class="btn-small">← Back to {{.Webhook.Name}}</a>
|
|
<div class="flex flex-wrap justify-between items-center gap-2 mt-2">
|
|
<h1 class="text-2xl font-medium text-gray-900">Full Event Log</h1>
|
|
<!-- Under a filter, this counts the events the filter lists. -->
|
|
<span class="text-sm text-gray-500">{{if gt .TotalEvents (len .Events)}}{{len .Events}} most recent of {{.TotalEvents}} events{{else}}{{.TotalEvents}}{{if not .Show}} total{{end}} event{{if ne .TotalEvents 1}}s{{end}}{{end}}{{if eq .Show "failed"}} with a failed delivery{{else if eq .Show "pending"}} with a delivery pending or retrying{{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 .Replay}} (replay){{end}}: {{if .Paused}}waiting{{else}}{{.Status}}{{end}}
|
|
</span>
|
|
{{end}}
|
|
<span class="text-xs text-gray-400" title="{{.ReceivedUTC}}">{{.Received}}</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>
|
|
<div class="mb-3">
|
|
{{template "event_request" .}}
|
|
</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 gap-3 text-left" @click="toggle">
|
|
{{template "delivery_row" .}}
|
|
<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>
|
|
</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}}">
|
|
<!-- The list to return to. -->
|
|
<input type="hidden" name="show" value="{{$.Show}}">
|
|
<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}}
|