98 lines
4.0 KiB
HTML
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 %}
|