Files
2026-05-07 12:30:51 -04:00

98 lines
4.0 KiB
HTML

{% extends "layout.html" %}
{% set active_page = 'network_clients' %}
{% block title %}Network Clients - {{ super() }}{% endblock %}
{% block content %}
<div class="d-flex justify-content-between align-items-center mb-4">
<h2 id="page-title" class="mb-0">Network Clients (SUPI)</h2>
</div>
<div class="row align-items-end">
<div class="col-md-5" id="host-ip-wrapper">
<label for="host" class="form-label">5GC Host IP</label>
<input type="text" class="form-control" id="host" placeholder="IPv4 or IPv6 Address">
</div>
<div class="col-auto">
<i class="bi bi-info-circle" data-bs-toggle="tooltip" data-bs-placement="right" title="Enter the IPv4 or IPv6 address. IPv6 addresses are automatically enclosed in [ ] if needed."></i>
</div>
</div>
<hr>
<div id="subscriber-view">
<p>Retrieve a list of all Network Clients (SUPIs) from the specified 5GC Host.</p>
<button class="btn btn-primary" id="listSupiBtn">List Network Clients</button>
</div>
<div class="mt-4">
<h4>Results</h4>
<div id="spinner" class="d-none spinner-border text-primary" role="status"><span class="visually-hidden">Loading...</span></div>
<div id="results-output" class="p-3"></div>
</div>
{% endblock %}
{% block extra_scripts %}
<script defer>
function renderSupisTable(items = []) {
resultsOutput.innerHTML = '';
if (!Array.isArray(items) || items.length === 0) {
resultsOutput.innerHTML = '<div class="alert alert-info mb-0">No network clients returned for this host.</div>';
return;
}
const preferred = ['supi', 'imsi', 'msisdn', 'profile', 'slice', 'dnn', 'status'];
const columns = preferred.filter(key => items.some(item => item[key] !== undefined));
if (columns.length === 0) {
columns.push(...Object.keys(items[0]).slice(0, 6));
}
const summary = document.createElement('div');
summary.className = 'mb-2 text-white-50';
summary.textContent = `Showing ${items.length} record${items.length === 1 ? '' : 's'}.`;
resultsOutput.appendChild(summary);
const wrapper = document.createElement('div');
wrapper.className = 'table-responsive';
const table = document.createElement('table');
table.className = 'table table-dark table-hover table-sm table-compact align-middle';
const thead = document.createElement('thead');
const headRow = document.createElement('tr');
columns.forEach(col => {
const th = document.createElement('th');
th.textContent = col.replace(/_/g, ' ').toUpperCase();
headRow.appendChild(th);
});
thead.appendChild(headRow);
table.appendChild(thead);
const tbody = document.createElement('tbody');
items.forEach(item => {
const row = document.createElement('tr');
columns.forEach(col => {
const cell = document.createElement('td');
let value = item[col];
if (Array.isArray(value) || (value && typeof value === 'object')) {
value = JSON.stringify(value);
}
cell.textContent = value ?? '';
row.appendChild(cell);
});
tbody.appendChild(row);
});
table.appendChild(tbody);
wrapper.appendChild(table);
resultsOutput.appendChild(wrapper);
}
document.getElementById('listSupiBtn').addEventListener('click', async () => {
const rawHost = document.getElementById('host').value;
if (!rawHost) {
alert('Please enter a 5GC Host IP address.');
return;
}
const host = formatHostIp(rawHost);
const response = await apiCall('/api/supis/list', { host });
if (response && response.supis) {
renderSupisTable(response.supis);
}
});
</script>
{% endblock %}