check / check (push) Successful in 6m32s
The receiver keeps the query string of the request it received on the event, in a new `raw_query` column of the per-webhook `events` table; a resubmitted copy carries its original's. The event log and the event's page show it with the request, the event log leaving out one over 32 KiB as it does request headers. The archive and log targets carry it. An HTTP target gets a `forwardQuery` setting, off by default, on both target forms and in the target list: on, each delivery, replays and resubmits included, appends the query string to the target URL, joined with `&` to one it already has. Model: opus-5-5
106 lines
6.0 KiB
HTML
106 lines
6.0 KiB
HTML
{{template "base" .}}
|
|
|
|
{{define "title"}}Edit {{.Target.Name}} - Webhooker{{end}}
|
|
|
|
{{define "content"}}
|
|
<div class="max-w-2xl mx-auto px-6 py-8">
|
|
<div class="mb-6">
|
|
<a href="/hook/{{.Webhook.ID}}" class="btn-small">← Back to {{.Webhook.Name}}</a>
|
|
<h1 class="text-2xl font-medium text-gray-900 mt-2">Edit Target</h1>
|
|
<p class="text-sm text-gray-500 mt-1">Type: {{if eq .Target.Type "database"}}archive{{else}}{{.Target.Type}}{{end}}. A target's type cannot be changed; create a new target to deliver a different way.</p>
|
|
</div>
|
|
|
|
<div class="card p-6">
|
|
{{if .Error}}
|
|
<div class="alert-error">{{.Error}}</div>
|
|
{{end}}
|
|
|
|
{{if or (eq .Target.Type "http") (eq .Target.Type "slack")}}
|
|
<div class="mb-6 rounded-md bg-gray-50 p-4 text-sm text-gray-700">
|
|
This form shows the target's destination in full, including any credential carried in its URL or headers. It is the only page that does; everywhere else the value is masked.
|
|
</div>
|
|
{{end}}
|
|
|
|
<form method="POST" action="/hook/{{.Webhook.ID}}/targets/{{.Target.ID}}/edit" class="space-y-6">
|
|
<input type="hidden" name="csrf_token" value="{{.CSRFToken}}">
|
|
|
|
<div class="form-group">
|
|
<label for="name" class="label">Name</label>
|
|
<input type="text" id="name" name="name" value="{{.TargetForm.Name}}" required class="input">
|
|
</div>
|
|
|
|
{{if eq .Target.Type "http"}}
|
|
<div class="form-group">
|
|
<label for="url" class="label">Destination URL</label>
|
|
<input type="url" id="url" name="url" value="{{.TargetForm.URL}}" required class="input">
|
|
<p class="text-xs text-gray-500 mt-1">Revalidated on save; destinations that resolve to private or link-local addresses are rejected.</p>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="headers" class="label">Headers</label>
|
|
<textarea id="headers" name="headers" rows="4" class="input" placeholder="Authorization: Bearer ...">{{.TargetForm.Headers}}</textarea>
|
|
<p class="text-xs text-gray-500 mt-1">One <code>Name: value</code> per line, sent with every delivery. Leave blank for none. <code>Host</code>, <code>Content-Length</code>, <code>Transfer-Encoding</code>, <code>Connection</code>, <code>Trailer</code> and <code>User-Agent</code> are set by the delivery engine and are rejected here rather than silently ignored. Headers set here are dropped if a redirect leaves the destination's own origin, so a credential cannot follow one to another host.</p>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="timeout" class="label">Timeout (seconds)</label>
|
|
<input type="number" id="timeout" name="timeout" value="{{.TargetForm.Timeout}}" min="0" max="{{.MaxTimeout}}" class="input">
|
|
<p class="text-xs text-gray-500 mt-1">Per-request timeout, at most {{.MaxTimeout}} seconds. Leave blank to use the default.</p>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label class="flex items-center gap-2 text-sm font-medium text-gray-700">
|
|
<input type="checkbox" id="forward_query" name="forward_query" value="on"{{if .TargetForm.ForwardQuery}} checked{{end}} class="h-4 w-4">
|
|
Pass the query string on to this target
|
|
</label>
|
|
<p class="text-xs text-gray-500 mt-1">Appends the query string each event arrived with to the destination URL, after any query string the URL already has.</p>
|
|
</div>
|
|
{{end}}
|
|
|
|
{{if eq .Target.Type "slack"}}
|
|
<div class="form-group">
|
|
<label for="url" class="label">Webhook URL</label>
|
|
<input type="url" id="url" name="url" value="{{.TargetForm.URL}}" required class="input">
|
|
<p class="text-xs text-gray-500 mt-1">Slack or Mattermost incoming webhook URL. Revalidated on save.</p>
|
|
</div>
|
|
{{end}}
|
|
|
|
{{if eq .Target.Type "database"}}
|
|
<div class="form-group">
|
|
<label for="expiry" class="label">Archive expiry</label>
|
|
<select id="expiry" name="expiry" class="input">
|
|
{{range .ArchiveExpiryChoices}}
|
|
<option value="{{.Value}}"{{if .Selected}} selected{{end}}>{{.Label}}</option>
|
|
{{end}}
|
|
</select>
|
|
<p class="text-xs text-gray-500 mt-1">Archived events older than this are deleted from the archive; never keeps them all.</p>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="rotation" class="label">Archive rotation</label>
|
|
<select id="rotation" name="rotation" class="input">
|
|
{{range .ArchiveRotationChoices}}
|
|
<option value="{{.Value}}"{{if .Selected}} selected{{end}}>{{.Label}}</option>
|
|
{{end}}
|
|
</select>
|
|
<p class="text-xs text-gray-500 mt-1">Starts a new archive file each month, day or hour (UTC), named for it; none keeps one file. A change applies from the next event; existing files keep their names.</p>
|
|
</div>
|
|
{{end}}
|
|
|
|
{{if or (eq .Target.Type "http") (eq .Target.Type "slack")}}
|
|
<div class="form-group">
|
|
<label for="max_retries" class="label">Delivery attempts</label>
|
|
<input type="number" id="max_retries" name="max_retries" value="{{.TargetForm.MaxRetries}}" min="0" max="20" class="input">
|
|
<p class="text-xs text-gray-500 mt-1">How many times each delivery is attempted in all, the first attempt included. 0 means a single attempt with no retries and no circuit breaker.</p>
|
|
</div>
|
|
{{end}}
|
|
|
|
<div class="flex gap-3">
|
|
<button type="submit" class="btn-primary">Save Changes</button>
|
|
<a href="/hook/{{.Webhook.ID}}" class="btn-secondary">Cancel</a>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
{{end}}
|