Monorepo for Tangled tangled.org

appview/pages: list webhook deliveries in repo settings

Signed-off-by: Anirudh Oppiliappan <anirudh@tangled.org>

+166 -6
+21 -5
appview/pages/pages.go
··· 965 965 } 966 966 967 967 type RepoWebhooksSettingsParams struct { 968 - LoggedInUser *oauth.MultiAccountUser 969 - RepoInfo repoinfo.RepoInfo 970 - Active string 971 - Tab string 972 - Webhooks []models.Webhook 968 + LoggedInUser *oauth.MultiAccountUser 969 + RepoInfo repoinfo.RepoInfo 970 + Active string 971 + Tab string 972 + Webhooks []models.Webhook 973 + WebhookDeliveries map[int64][]models.WebhookDelivery 973 974 } 974 975 975 976 func (p *Pages) RepoWebhooksSettings(w io.Writer, params RepoWebhooksSettingsParams) error { 976 977 params.Active = "settings" 977 978 params.Tab = "hooks" 978 979 return p.executeRepo("repo/settings/hooks", w, params) 980 + } 981 + 982 + type WebhookDeliveriesListParams struct { 983 + LoggedInUser *oauth.MultiAccountUser 984 + RepoInfo repoinfo.RepoInfo 985 + Webhook *models.Webhook 986 + Deliveries []models.WebhookDelivery 987 + } 988 + 989 + func (p *Pages) WebhookDeliveriesList(w io.Writer, params WebhookDeliveriesListParams) error { 990 + tpl, err := p.parse("repo/settings/fragments/webhookDeliveries") 991 + if err != nil { 992 + return err 993 + } 994 + return tpl.ExecuteTemplate(w, "repo/settings/fragments/webhookDeliveries", params) 979 995 } 980 996 981 997 type RepoIssuesParams struct {
+74
appview/pages/templates/repo/settings/fragments/webhookDeliveries.html
··· 1 + {{define "repo/settings/fragments/webhookDeliveries"}} 2 + <div class="flex flex-col gap-4"> 3 + <div class="flex items-center justify-between"> 4 + <h3 class="text-lg font-bold uppercase text-sm">Recent Deliveries</h3> 5 + <button 6 + type="button" 7 + onclick="this.closest('[popover]').hidePopover()" 8 + class="btn text-sm flex items-center gap-1" 9 + > 10 + {{ i "x" "size-4" }} close 11 + </button> 12 + </div> 13 + 14 + <div class="text-sm text-gray-600 dark:text-gray-400"> 15 + <span class="font-mono break-all">{{ .Webhook.Url }}</span> 16 + </div> 17 + 18 + {{ if .Deliveries }} 19 + <div class="flex flex-col divide-y divide-gray-200 dark:divide-gray-700 border border-gray-200 dark:border-gray-700 rounded max-h-[60vh] overflow-y-auto"> 20 + {{ range .Deliveries }} 21 + <details class="group"> 22 + <summary class="p-4 hover:bg-gray-50 dark:hover:bg-gray-800 cursor-pointer list-none"> 23 + <div class="flex items-center gap-2 mb-2"> 24 + {{ if .Success }} 25 + <span class="inline-flex items-center gap-1 px-2 py-1 text-xs rounded bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200"> 26 + {{ i "circle-check" "size-3" }} 27 + {{ .ResponseCode }} 28 + </span> 29 + {{ else }} 30 + <span class="inline-flex items-center gap-1 px-2 py-1 text-xs rounded bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200"> 31 + {{ i "circle-x" "size-3" }} 32 + {{ if .ResponseCode }}{{ .ResponseCode }}{{ else }}failed{{ end }} 33 + </span> 34 + {{ end }} 35 + <span class="text-xs text-gray-500 dark:text-gray-400 font-mono"> 36 + {{ .DeliveryId }} 37 + </span> 38 + <span class="ml-auto text-xs text-gray-400 dark:text-gray-500 group-open:rotate-180 transition-transform"> 39 + {{ i "chevron-down" "size-4" }} 40 + </span> 41 + </div> 42 + <div class="text-sm text-gray-700 dark:text-gray-300 mb-1"> 43 + <span class="font-semibold">Event:</span> {{ .Event }} 44 + </div> 45 + <div class="text-xs text-gray-500 dark:text-gray-400"> 46 + {{ .CreatedAt.Format "2006-01-02 15:04:05 MST" }} 47 + </div> 48 + </summary> 49 + 50 + <div class="px-4 pb-4 pt-2 bg-gray-50 dark:bg-gray-800/50"> 51 + <div class="flex flex-col gap-3 text-sm"> 52 + <div class="flex flex-col gap-2"> 53 + <h5 class="font-semibold text-gray-700 dark:text-gray-300">Request Body</h5> 54 + <pre class="bg-white dark:bg-gray-900 p-3 rounded text-xs overflow-x-auto border border-gray-200 dark:border-gray-700">{{ .RequestBody }}</pre> 55 + </div> 56 + 57 + {{ if .ResponseBody }} 58 + <div class="flex flex-col gap-2"> 59 + <h5 class="font-semibold text-gray-700 dark:text-gray-300">Response Body</h5> 60 + <pre class="bg-white dark:bg-gray-900 p-3 rounded text-xs overflow-x-auto border border-gray-200 dark:border-gray-700">{{ .ResponseBody }}</pre> 61 + </div> 62 + {{ end }} 63 + </div> 64 + </div> 65 + </details> 66 + {{ end }} 67 + </div> 68 + {{ else }} 69 + <div class="flex items-center justify-center p-8 text-gray-500 dark:text-gray-400 border border-gray-200 dark:border-gray-700 rounded"> 70 + No deliveries yet 71 + </div> 72 + {{ end }} 73 + </div> 74 + {{end}}
+71 -1
appview/pages/templates/repo/settings/hooks.html
··· 82 82 </div> 83 83 {{ end }} 84 84 </div> 85 + 85 86 {{ if $.RepoInfo.Roles.IsOwner }} 86 - <div class="flex items-center"> 87 + <div class="flex items-center mt-2"> 87 88 <label class="flex items-center gap-2 cursor-pointer"> 88 89 <input 89 90 type="checkbox" ··· 95 96 <span class="text-sm">Active</span> 96 97 </label> 97 98 </div> 99 + {{ end }} 100 + 101 + <!-- Recent Deliveries --> 102 + {{ $deliveries := index $.WebhookDeliveries .Id }} 103 + {{ if $deliveries }} 104 + <div class="mt-3 border-t border-gray-200 dark:border-gray-700 pt-3"> 105 + <div class="flex items-center justify-between mb-2"> 106 + <h4 class="text-sm font-semibold text-gray-700 dark:text-gray-300 uppercase">Recent Deliveries</h4> 107 + </div> 108 + <div class="flex flex-col gap-2"> 109 + {{ range $deliveries }} 110 + <div class="flex items-center gap-3 text-xs p-2 bg-gray-50 dark:bg-gray-800 rounded"> 111 + {{ if .Success }} 112 + <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200"> 113 + {{ i "circle-check" "size-3" }} 114 + {{ .ResponseCode }} 115 + </span> 116 + {{ else }} 117 + <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200"> 118 + {{ i "circle-x" "size-3" }} 119 + {{ if .ResponseCode }}{{ .ResponseCode }}{{ else }}failed{{ end }} 120 + </span> 121 + {{ end }} 122 + <span class="flex-1 font-mono text-gray-600 dark:text-gray-400 truncate"> 123 + {{ .DeliveryId }} 124 + </span> 125 + <span class="text-gray-500 dark:text-gray-400"> 126 + {{ .Event }} 127 + </span> 128 + <span class="text-gray-500 dark:text-gray-400 whitespace-nowrap"> 129 + {{ .CreatedAt.Format "Jan 02, 15:04" }} 130 + </span> 131 + </div> 132 + {{ end }} 133 + </div> 134 + <div class="mt-2"> 135 + <button 136 + class="btn text-xs flex items-center gap-1" 137 + hx-get="/{{ $.RepoInfo.FullName }}/settings/hooks/{{ .Id }}/deliveries" 138 + hx-target="#webhook-deliveries-modal-{{ .Id }}" 139 + hx-swap="innerHTML" 140 + popovertarget="webhook-deliveries-modal-{{ .Id }}" 141 + popovertargetaction="toggle" 142 + > 143 + {{ i "list" "size-3" }} 144 + show all 145 + </button> 146 + </div> 147 + </div> 148 + {{ else }} 149 + <div class="mt-3 border-t border-gray-200 dark:border-gray-700 pt-3"> 150 + <div class="text-xs text-gray-500 dark:text-gray-400 text-center py-2"> 151 + No deliveries yet 152 + </div> 153 + </div> 154 + {{ end }} 155 + 156 + <!-- Deliveries Modal --> 157 + <div 158 + id="webhook-deliveries-modal-{{ .Id }}" 159 + popover 160 + class="bg-white w-full sm:w-[50rem] dark:bg-gray-800 p-6 max-h-dvh overflow-y-auto rounded border border-gray-200 dark:border-gray-700 drop-shadow dark:text-white backdrop:bg-gray-400/50 dark:backdrop:bg-gray-800/50" 161 + > 162 + <div class="flex items-center justify-center p-4"> 163 + {{ i "loader-circle" "size-6 animate-spin" }} 164 + </div> 165 + </div> 166 + 167 + {{ if $.RepoInfo.Roles.IsOwner }} 98 168 <div 99 169 id="edit-webhook-modal-{{.Id}}" 100 170 popover