Files
crowdsec-dashy/web/templates/pages/bouncers.html
T

132 lines
4.9 KiB
HTML

{{template "base" .}}
{{define "content"}}
<div style="max-width:1200px">
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:16px">
<div>
<div class="page-title">Bouncers</div>
<div class="page-sub">Enforcement agents that consume CrowdSec decisions</div>
</div>
{{if .CLIAvailable}}
<button class="btn-primary" onclick="document.getElementById('add-modal').classList.remove('hidden')">Add Bouncer</button>
{{end}}
</div>
{{if not .CLIAvailable}}
<div class="cli-unavail-banner" style="margin-bottom:16px">
<div>
<strong style="display:block;margin-bottom:4px">cscli unavailable</strong>
Bouncer management requires the cscli binary. Mount it at the CSCLI_PATH configured in your environment.
</div>
</div>
{{end}}
{{if .NewBouncer}}
<div class="apikey-reveal" style="margin-bottom:16px">
<div class="apikey-header">
<strong>Bouncer "{{.NewBouncer.Name}}" registered.</strong>
Copy the API key below — it will not be shown again.
</div>
<div class="apikey-box" id="apikey-box" onclick="copyApiKey()" title="Click to copy">
<code style="font-family:'JetBrains Mono',monospace;font-size:13px;color:var(--safe);word-break:break-all">{{.NewBouncer.APIKey}}</code>
<span class="apikey-copy-hint" id="copy-hint">click to copy</span>
</div>
</div>
{{end}}
<div class="panel">
<div class="panel-header">
<span class="panel-title">Bouncers ({{len .Bouncers}})</span>
</div>
{{if .Bouncers}}
<div style="overflow-x:auto">
<table class="data-table">
<thead>
<tr>
<th>Name</th>
<th>IP Address</th>
<th>Last Pull</th>
<th>Version</th>
<th>Type</th>
<th>Status</th>
{{if $.CLIAvailable}}<th>Action</th>{{end}}
</tr>
</thead>
<tbody>
{{range .Bouncers}}
<tr>
<td style="font-family:'JetBrains Mono',monospace;font-size:12px;font-weight:600">{{.Name}}</td>
<td style="font-family:'JetBrains Mono',monospace;font-size:12px">{{.IPAddress}}</td>
<td style="font-size:12px;color:var(--muted)">{{truncate .LastPull 16}}</td>
<td style="font-family:'JetBrains Mono',monospace;font-size:11px;color:var(--muted)">{{.Version}}</td>
<td style="font-size:12px;color:var(--muted)">{{.Type}}</td>
<td>
{{if .Revoked}}
<span class="badge badge-red">revoked</span>
{{else}}
<span class="badge badge-green">valid</span>
{{end}}
</td>
{{if $.CLIAvailable}}
<td>
<form method="POST" action="/bouncers/delete" style="display:inline">
<input type="hidden" name="_csrf" value="{{$.CSRFToken}}">
<input type="hidden" name="name" value="{{.Name}}">
<button type="submit" class="btn-danger-sm" data-confirm="Delete bouncer {{.Name}}? This cannot be undone.">Delete</button>
</form>
</td>
{{end}}
</tr>
{{end}}
</tbody>
</table>
</div>
{{else}}
<div class="empty-state">
<div class="empty-text">No bouncers registered</div>
<div class="empty-sub">Add a bouncer to enforce CrowdSec decisions</div>
</div>
{{end}}
</div>
</div>
{{if .CLIAvailable}}
<div class="modal-backdrop hidden" id="add-modal">
<div class="modal">
<div class="modal-header">
<span class="modal-title">Add Bouncer</span>
<button class="modal-close" onclick="document.getElementById('add-modal').classList.add('hidden')">close</button>
</div>
<div class="modal-body">
<form method="POST" action="/bouncers/add">
<input type="hidden" name="_csrf" value="{{.CSRFToken}}">
<div style="margin-bottom:16px">
<label class="field-label">Bouncer Name</label>
<input class="field-input" type="text" name="name" placeholder="my-bouncer" required
pattern="[a-zA-Z0-9_\-]{1,64}" autofocus>
<div class="field-hint">1-64 characters: letters, digits, dash, underscore</div>
</div>
<div class="modal-footer">
<button type="button" class="btn-ghost" onclick="document.getElementById('add-modal').classList.add('hidden')">Cancel</button>
<button type="submit" class="btn-primary">Register Bouncer</button>
</div>
</form>
</div>
</div>
</div>
{{end}}
{{end}}
{{define "scripts"}}
<script>
function copyApiKey() {
var code = document.querySelector('#apikey-box code');
var hint = document.getElementById('copy-hint');
if (!code || !navigator.clipboard) return;
navigator.clipboard.writeText(code.textContent.trim()).then(function() {
if (hint) { hint.textContent = 'copied!'; setTimeout(function() { hint.textContent = 'click to copy'; }, 2500); }
});
}
</script>
{{end}}