sub-aligator/templates/index.html

185 lines
6.9 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{% extends "base.html" %}
{% block content %}
<div id="flash-container" hx-swap-oob="true">
{% include "fragments/flash.html" %}
</div>
{% if pools.len() == 0 %}
<section class="box">
<div class="box-title">No pools configured</div>
<p>Create at least one pool before allocating subnets.</p>
<a href="/setup" class="btn">Create first pool</a>
<a href="/pools" class="btn btn-secondary">Manage pools</a>
</section>
{% else %}
<section class="grid">
{% for pool in pools %}
<article class="box" id="pool-card-{{ pool.slug }}">
<div class="box-title">{{ pool.name }}</div>
<p><span class="label">Parent prefix:</span> <span class="value">{{ pool.cidr }}</span></p>
<p><span class="label">Type:</span> <span class="value">{{ pool.kind }}</span></p>
<form
hx-get="/partials/pools/{{ pool.slug }}/preview"
hx-target="#preview-{{ pool.slug }}"
hx-trigger="change from:select, load"
hx-indicator="#indicator-{{ pool.slug }}"
>
<label for="prefix-{{ pool.slug }}">Subnet size</label>
<select name="prefix_length" id="prefix-{{ pool.slug }}" onchange="updateModalPrefix('{{ pool.slug }}', this.value)">
{% for pl in pool.allowed_prefixes %}
<option value="{{ pl }}" {% if pl == "24" %}selected{% endif %}>/{{ pl }}</option>
{% endfor %}
</select>
<div id="indicator-{{ pool.slug }}" class="small" style="display:none;">Loading...</div>
<div id="preview-{{ pool.slug }}"></div>
</form>
<button
class="btn"
style="margin-top: 1rem;"
onclick="openAllocateModal('{{ pool.slug }}')"
>
[ Allocate next free subnet ]
</button>
</article>
{% endfor %}
</section>
{% endif %}
<section class="box">
<div class="box-title">Allocated subnets</div>
<form method="get" action="/" class="filters">
<div>
<label for="q">Search</label>
<input type="text" id="q" name="q" value="{{ query }}" placeholder="CIDR or note">
</div>
<div>
<label for="pool">Pool</label>
<select id="pool" name="pool">
<option value="" {% if pool_filter == "" %}selected{% endif %}>All</option>
{% for p in all_pools %}
<option value="{{ p.slug }}" {% if pool_filter == p.slug %}selected{% endif %}>{{ p.name }}</option>
{% endfor %}
</select>
</div>
<div>
<label for="status">Status</label>
<select id="status" name="status">
<option value="" {% if status_filter == "" %}selected{% endif %}>All</option>
<option value="active" {% if status_filter == "active" %}selected{% endif %}>active</option>
<option value="reserved" {% if status_filter == "reserved" %}selected{% endif %}>reserved</option>
<option value="released" {% if status_filter == "released" %}selected{% endif %}>released</option>
</select>
</div>
<div>
<button type="submit" class="btn">Filter</button>
<a href="/" class="btn btn-secondary">Reset</a>
</div>
</form>
<div id="allocations-table">
{% include "fragments/allocations_table.html" %}
</div>
</section>
<div id="allocate-modal" class="modal-overlay" style="display:none;" onclick="if (event.target === this) closeAllocateModal();">
<div class="modal" onclick="event.stopPropagation();">
<h2 class="modal-title">Confirm subnet allocation</h2>
<form method="post" action="/allocations" class="modal-body" id="allocate-form">
<input type="hidden" name="pool_slug" id="modal-pool-slug">
<input type="hidden" name="prefix_length" id="modal-prefix-length">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<div class="detail-grid">
<div class="detail-item">
<div class="label">Pool</div>
<div class="value" id="modal-pool-name"></div>
</div>
<div class="detail-item">
<div class="label">Prefix</div>
<div class="value" id="modal-prefix-display"></div>
</div>
<div class="detail-item">
<div class="label">Proposed subnet</div>
<div class="value" id="modal-cidr"></div>
</div>
<div class="detail-item">
<div class="label">Total addresses</div>
<div class="value" id="modal-address-count"></div>
</div>
<div class="detail-item">
<div class="label">Usable hosts</div>
<div class="value" id="modal-usable-hosts"></div>
</div>
</div>
<p class="small" id="modal-warning"></p>
<label for="note">Note *</label>
<textarea id="note" name="note" rows="3" required minlength="3" maxlength="500"></textarea>
<label for="ticket">Ticket / reference</label>
<input type="text" id="ticket" name="ticket" maxlength="100">
<div class="modal-actions">
<button type="button" class="btn btn-secondary" onclick="closeAllocateModal()">Cancel</button>
<button type="submit" class="btn">Confirm allocation</button>
</div>
</form>
</div>
</div>
<script>
const poolData = {
{% for pool in pools %}
"{{ pool.slug }}": {
name: "{{ pool.name }}",
allowed_prefixes: {{ pool.allowed_prefixes_json|safe }}
},
{% endfor %}
};
function updateModalPrefix(slug, prefixLength) {
// preview is updated via HTMX automatically
}
async function openAllocateModal(slug) {
const select = document.getElementById('prefix-' + slug);
const prefixLength = select.value;
const modal = document.getElementById('allocate-modal');
document.getElementById('modal-pool-slug').value = slug;
document.getElementById('modal-prefix-length').value = prefixLength;
document.getElementById('modal-pool-name').textContent = poolData[slug].name;
document.getElementById('modal-prefix-display').textContent = '/' + prefixLength;
try {
const resp = await fetch('/partials/pools/' + slug + '/preview?prefix_length=' + prefixLength);
const html = await resp.text();
const parser = new DOMParser();
const doc = parser.parseFromString(html, 'text/html');
const cidr = doc.getElementById('preview-cidr')?.textContent || '–';
const addressCount = doc.getElementById('preview-address-count')?.textContent || '–';
const usableHosts = doc.getElementById('preview-usable-hosts')?.textContent || '–';
const warning = doc.getElementById('preview-warning')?.textContent || '';
document.getElementById('modal-cidr').textContent = cidr;
document.getElementById('modal-address-count').textContent = addressCount;
document.getElementById('modal-usable-hosts').textContent = usableHosts;
document.getElementById('modal-warning').textContent = warning;
} catch (e) {
document.getElementById('modal-warning').textContent = 'Could not load preview.';
}
modal.style.display = 'flex';
}
function closeAllocateModal() {
document.getElementById('allocate-modal').style.display = 'none';
}
</script>
{% endblock %}