Files
vibeproxy/internal/web/templates/proxy_host_form.html
T
owenandClaude Sonnet 5 ba1f7c4c03 Initial vibeproxy implementation
Self-contained HTTP/HTTPS/TCP/UDP reverse proxy manager written in Go,
with SQLite storage, a Bootstrap 5 admin UI (Go templates, no JS
framework), and a REST API under /api/v1.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QTXFrNP1imCW7jtfL5SZrw
2026-08-17 10:28:59 -05:00

267 lines
16 KiB
HTML

{{define "proxy_host_form"}}{{template "header" .}}
{{$d := .Data}}{{$h := $d.Host}}
<form method="post" action="{{if $d.IsNew}}/proxy-hosts/new{{else}}/proxy-hosts/{{$h.ID}}/edit{{end}}">
{{template "csrf_field" .CSRFToken}}
<ul class="nav nav-tabs mb-3" role="tablist">
<li class="nav-item"><button class="nav-link active" data-bs-toggle="tab" data-bs-target="#tab-details" type="button">Details</button></li>
<li class="nav-item"><button class="nav-link" data-bs-toggle="tab" data-bs-target="#tab-backends" type="button">Backends</button></li>
<li class="nav-item"><button class="nav-link" data-bs-toggle="tab" data-bs-target="#tab-ssl" type="button">SSL &amp; Access</button></li>
<li class="nav-item"><button class="nav-link" data-bs-toggle="tab" data-bs-target="#tab-headers" type="button">Headers</button></li>
<li class="nav-item"><button class="nav-link" data-bs-toggle="tab" data-bs-target="#tab-advanced" type="button">Advanced</button></li>
</ul>
<div class="tab-content">
<div class="tab-pane fade show active" id="tab-details">
<div class="card mb-3"><div class="card-body">
<div class="row g-3">
<div class="col-md-6">
<label class="form-label">Name</label>
<input class="form-control" name="name" value="{{$h.Name}}" required>
</div>
<div class="col-md-6">
<label class="form-label">Type</label>
<select class="form-select" name="type" id="hostType">
<option value="proxy" {{if eq $h.Type "proxy"}}selected{{end}}>Proxy</option>
<option value="redirect" {{if eq $h.Type "redirect"}}selected{{end}}>Redirect</option>
</select>
</div>
<div class="col-12">
<label class="form-label">Domains</label>
<div data-chip-input>
<div class="vp-chip-list"></div>
<input type="text" class="form-control" placeholder="example.com — press Enter to add">
<textarea name="domains" class="d-none">{{join $h.Domains "\n"}}</textarea>
</div>
</div>
<div class="col-md-4">
<label class="form-label">Listen Address</label>
<input class="form-control" name="listen_addr" value="{{$h.ListenAddr}}" placeholder="0.0.0.0 (all interfaces)">
</div>
<div class="col-12" id="redirectFields" style="{{if ne $h.Type "redirect"}}display:none{{end}}">
<div class="row g-3">
<div class="col-md-6">
<label class="form-label">Redirect Target URL</label>
<input class="form-control" name="redirect_target_url" value="{{$h.RedirectTargetURL}}" placeholder="https://new.example.com">
</div>
<div class="col-md-3">
<label class="form-label">Redirect Code</label>
<select class="form-select" name="redirect_code">
{{range $code := (slice 301 302 307 308)}}
<option value="{{$code}}" {{if eq $h.RedirectCode $code}}selected{{end}}>{{$code}}</option>
{{end}}
</select>
</div>
<div class="col-md-3 d-flex flex-column justify-content-end">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="redirect_preserve_path" id="rpp" {{if $h.RedirectPreservePath}}checked{{end}}>
<label class="form-check-label" for="rpp">Preserve path</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" name="redirect_preserve_qs" id="rpq" {{if $h.RedirectPreserveQS}}checked{{end}}>
<label class="form-check-label" for="rpq">Preserve query string</label>
</div>
</div>
</div>
</div>
<div class="col-12">
<label class="form-label">Comments</label>
<textarea class="form-control" name="comments" rows="2">{{$h.Comments}}</textarea>
</div>
<div class="col-12">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" name="enabled" id="enabled" {{if $h.Enabled}}checked{{end}}>
<label class="form-check-label" for="enabled">Enabled</label>
</div>
</div>
</div>
</div></div>
</div>
<div class="tab-pane fade" id="tab-backends">
<div class="card mb-3"><div class="card-body">
<div class="row g-3 mb-3">
<div class="col-md-4">
<label class="form-label">Upstream Scheme</label>
<select class="form-select" name="forward_scheme">
<option value="http" {{if eq $h.ForwardScheme "http"}}selected{{end}}>http</option>
<option value="https" {{if eq $h.ForwardScheme "https"}}selected{{end}}>https</option>
</select>
</div>
<div class="col-md-4">
<label class="form-label">Load Balancing Method</label>
<select class="form-select" name="load_balancing_method">
<option value="round_robin" {{if eq $h.LoadBalancingMethod "round_robin"}}selected{{end}}>Round robin</option>
<option value="least_conn" {{if eq $h.LoadBalancingMethod "least_conn"}}selected{{end}}>Least connections</option>
<option value="weighted" {{if eq $h.LoadBalancingMethod "weighted"}}selected{{end}}>Weighted</option>
</select>
</div>
<div class="col-md-4 d-flex align-items-end">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="websocket_support" id="ws" {{if $h.WebsocketSupport}}checked{{end}}>
<label class="form-check-label" for="ws">WebSocket support</label>
</div>
</div>
</div>
<table class="table table-sm align-middle" id="backendsTable">
<thead><tr><th>Host</th><th>Port</th><th>Weight</th><th>On</th><th>Health Check</th><th>Path</th><th>Status</th><th>Interval(s)</th><th>Fail</th><th>Recover</th><th></th></tr></thead>
<tbody>
{{range $i, $b := $h.Backends}}
<tr>
<td><input class="form-control form-control-sm" name="backend_host" value="{{$b.Host}}"></td>
<td><input class="form-control form-control-sm" style="width:5.5rem" name="backend_port" value="{{$b.Port}}"></td>
<td><input class="form-control form-control-sm" style="width:4.5rem" name="backend_weight" value="{{$b.Weight}}"></td>
<td>
<input type="checkbox" class="form-check-input" {{if $b.Enabled}}checked{{end}} onchange="this.nextElementSibling.value=this.checked">
<input type="hidden" name="backend_enabled" value="{{if $b.Enabled}}true{{else}}false{{end}}">
</td>
<td>
<select class="form-select form-select-sm" name="backend_hc_type">
<option value="tcp" {{if eq $b.HealthCheckType "tcp"}}selected{{end}}>TCP</option>
<option value="http" {{if eq $b.HealthCheckType "http"}}selected{{end}}>HTTP</option>
<option value="none" {{if eq $b.HealthCheckType "none"}}selected{{end}}>None</option>
</select>
</td>
<td><input class="form-control form-control-sm" style="width:6rem" name="backend_hc_path" value="{{$b.HealthCheckPath}}"></td>
<td><input class="form-control form-control-sm" style="width:4.5rem" name="backend_hc_status" value="{{$b.HealthCheckStatus}}"></td>
<td><input class="form-control form-control-sm" style="width:4.5rem" name="backend_hc_interval" value="{{$b.IntervalSeconds}}"></td>
<td><input class="form-control form-control-sm" style="width:4rem" name="backend_hc_fail" value="{{$b.FailureThreshold}}"></td>
<td><input class="form-control form-control-sm" style="width:4rem" name="backend_hc_recover" value="{{$b.RecoveryThreshold}}"></td>
<td><button type="button" class="btn btn-sm btn-outline-danger" data-remove-row><i class="bi bi-x"></i></button></td>
</tr>
{{end}}
</tbody>
</table>
<button type="button" class="btn btn-sm btn-outline-primary" data-add-row="backendsTable"><i class="bi bi-plus-lg"></i> Add Backend</button>
<template id="backendsTableRowTemplate"><tr>
<td><input class="form-control form-control-sm" name="backend_host"></td>
<td><input class="form-control form-control-sm" style="width:5.5rem" name="backend_port" value="80"></td>
<td><input class="form-control form-control-sm" style="width:4.5rem" name="backend_weight" value="1"></td>
<td>
<input type="checkbox" class="form-check-input" checked onchange="this.nextElementSibling.value=this.checked">
<input type="hidden" name="backend_enabled" value="true">
</td>
<td><select class="form-select form-select-sm" name="backend_hc_type">
<option value="tcp" selected>TCP</option><option value="http">HTTP</option><option value="none">None</option>
</select></td>
<td><input class="form-control form-control-sm" style="width:6rem" name="backend_hc_path" value="/"></td>
<td><input class="form-control form-control-sm" style="width:4.5rem" name="backend_hc_status" value="200"></td>
<td><input class="form-control form-control-sm" style="width:4.5rem" name="backend_hc_interval" value="10"></td>
<td><input class="form-control form-control-sm" style="width:4rem" name="backend_hc_fail" value="3"></td>
<td><input class="form-control form-control-sm" style="width:4rem" name="backend_hc_recover" value="2"></td>
<td><button type="button" class="btn btn-sm btn-outline-danger" data-remove-row><i class="bi bi-x"></i></button></td>
</tr></template>
</div></div>
</div>
<div class="tab-pane fade" id="tab-ssl">
<div class="card mb-3"><div class="card-body">
<div class="row g-3">
<div class="col-md-6">
<label class="form-label">SSL Certificate</label>
<select class="form-select" name="certificate_id">
<option value="0">None</option>
{{range $d.Certificates}}<option value="{{.ID}}" {{if and $h.CertificateID (eq (deref64 $h.CertificateID) .ID)}}selected{{end}}>{{.Name}}</option>{{end}}
</select>
</div>
<div class="col-md-6">
<label class="form-label">Access List</label>
<select class="form-select" name="access_list_id">
<option value="0">None</option>
{{range $d.AccessLists}}<option value="{{.ID}}" {{if and $h.AccessListID (eq (deref64 $h.AccessListID) .ID)}}selected{{end}}>{{.Name}}</option>{{end}}
</select>
</div>
<div class="col-md-4">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" name="force_https" id="fh" {{if $h.ForceHTTPS}}checked{{end}}>
<label class="form-check-label" for="fh">Force HTTPS</label>
</div>
</div>
<div class="col-md-4">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" name="hsts_enabled" id="hsts" {{if $h.HSTSEnabled}}checked{{end}}>
<label class="form-check-label" for="hsts">HSTS</label>
</div>
</div>
<div class="col-md-4">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" name="preserve_host_header" id="phh" {{if $h.PreserveHostHeader}}checked{{end}}>
<label class="form-check-label" for="phh">Preserve Host header</label>
</div>
</div>
</div>
</div></div>
</div>
<div class="tab-pane fade" id="tab-headers">
<div class="card mb-3"><div class="card-body">
<table class="table table-sm align-middle" id="headersTable">
<thead><tr><th>Direction</th><th>Action</th><th>Name</th><th>Value</th><th></th></tr></thead>
<tbody>
{{range $h.CustomHeaders}}
<tr>
<td><select class="form-select form-select-sm" name="header_direction">
<option value="request" {{if eq .Direction "request"}}selected{{end}}>Request</option>
<option value="response" {{if eq .Direction "response"}}selected{{end}}>Response</option>
</select></td>
<td><select class="form-select form-select-sm" name="header_action">
<option value="set" {{if eq .Action "set"}}selected{{end}}>Set</option>
<option value="remove" {{if eq .Action "remove"}}selected{{end}}>Remove</option>
</select></td>
<td><input class="form-control form-control-sm" name="header_name" value="{{.Name}}" placeholder="X-Frame-Options"></td>
<td><input class="form-control form-control-sm" name="header_value" value="{{.Value}}"></td>
<td><button type="button" class="btn btn-sm btn-outline-danger" data-remove-row><i class="bi bi-x"></i></button></td>
</tr>
{{end}}
</tbody>
</table>
<button type="button" class="btn btn-sm btn-outline-primary" data-add-row="headersTable"><i class="bi bi-plus-lg"></i> Add Header</button>
<template id="headersTableRowTemplate"><tr>
<td><select class="form-select form-select-sm" name="header_direction">
<option value="request" selected>Request</option><option value="response">Response</option>
</select></td>
<td><select class="form-select form-select-sm" name="header_action">
<option value="set" selected>Set</option><option value="remove">Remove</option>
</select></td>
<td><input class="form-control form-control-sm" name="header_name" placeholder="X-Frame-Options"></td>
<td><input class="form-control form-control-sm" name="header_value"></td>
<td><button type="button" class="btn btn-sm btn-outline-danger" data-remove-row><i class="bi bi-x"></i></button></td>
</tr></template>
</div></div>
</div>
<div class="tab-pane fade" id="tab-advanced">
<div class="card mb-3"><div class="card-body">
<div class="row g-3">
<div class="col-md-3">
<label class="form-label">Connect timeout (ms)</label>
<input class="form-control" name="connect_timeout_ms" value="{{$h.ConnectTimeoutMS}}">
</div>
<div class="col-md-3">
<label class="form-label">Read timeout (ms)</label>
<input class="form-control" name="read_timeout_ms" value="{{$h.ReadTimeoutMS}}">
</div>
<div class="col-md-3">
<label class="form-label">Write timeout (ms)</label>
<input class="form-control" name="write_timeout_ms" value="{{$h.WriteTimeoutMS}}">
</div>
<div class="col-md-3">
<label class="form-label">Idle timeout (ms)</label>
<input class="form-control" name="idle_timeout_ms" value="{{$h.IdleTimeoutMS}}">
</div>
</div>
</div></div>
</div>
</div>
<button type="submit" class="btn btn-primary"><i class="bi bi-check-lg"></i> Save</button>
<a href="/proxy-hosts" class="btn btn-outline-secondary">Cancel</a>
</form>
<script>
document.getElementById('hostType').addEventListener('change', function () {
document.getElementById('redirectFields').style.display = this.value === 'redirect' ? '' : 'none';
});
</script>
{{template "footer" .}}{{end}}