2024-11-01 01:31:42 +08:00
|
|
|
<!DOCTYPE html>
|
|
|
|
<!--
|
|
|
|
# _
|
|
|
|
# | |
|
|
|
|
# _ __ ___ ___ _ __ ___ ___ _ _| | _ _ ___
|
|
|
|
# | '_ ` _ \ / _ \| '_ \ / _ \ / __| | | | || | | / __|
|
|
|
|
# | | | | | | (_) | | | | (_) | (__| |_| | || |_| \__ \
|
|
|
|
# |_| |_| |_|\___/|_| |_|\___/ \___|\__,_|_(_)__,_|___/
|
|
|
|
#
|
|
|
|
# (c) Andrea Santaniello 31/10/24 - FRN Weblist
|
2024-11-01 02:11:26 +08:00
|
|
|
-->
|
|
|
|
<html lang="en">
|
2024-11-01 01:31:42 +08:00
|
|
|
<head>
|
|
|
|
<meta charset="UTF-8">
|
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
|
<title>FRN Servers Client Status</title>
|
|
|
|
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
|
|
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
|
|
|
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
|
|
|
|
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
|
|
|
|
<style>
|
|
|
|
body {
|
|
|
|
background-color: #121212;
|
|
|
|
color: #e0e0e0;
|
2024-11-01 02:11:26 +08:00
|
|
|
background-image: url('https://archive.monocul.us/monoculus_sketch_2024_min.png');
|
|
|
|
background-position: bottom right;
|
|
|
|
background-repeat: no-repeat;
|
2024-11-01 01:31:42 +08:00
|
|
|
}
|
|
|
|
.container-fluid {
|
|
|
|
margin-top: 20px;
|
|
|
|
}
|
|
|
|
.form-control {
|
|
|
|
background-color: #333;
|
|
|
|
color: #e0e0e0;
|
|
|
|
border: 1px solid #444;
|
|
|
|
}
|
|
|
|
.form-control::placeholder {
|
|
|
|
color: #bbb;
|
|
|
|
}
|
|
|
|
.card {
|
|
|
|
background-color: #1e1e1e;
|
|
|
|
border: 1px solid #444;
|
|
|
|
}
|
|
|
|
.card-header {
|
|
|
|
background-color: #333;
|
|
|
|
color: #e0e0e0;
|
|
|
|
}
|
|
|
|
.table {
|
|
|
|
color: #e0e0e0;
|
|
|
|
}
|
|
|
|
.table thead {
|
|
|
|
background-color: #333;
|
|
|
|
}
|
|
|
|
.status-icon {
|
|
|
|
font-size: 1.5rem;
|
|
|
|
}
|
|
|
|
.available {
|
|
|
|
color: #4caf50;
|
|
|
|
}
|
|
|
|
.unavailable {
|
|
|
|
color: #f44336;
|
|
|
|
}
|
|
|
|
.modal-body {
|
|
|
|
font-size: 1.1rem;
|
|
|
|
background-color: #1e1e1e;
|
|
|
|
color: #e0e0e0;
|
|
|
|
}
|
|
|
|
.modal-header {
|
|
|
|
background-color: #333;
|
|
|
|
color: #e0e0e0;
|
|
|
|
}
|
|
|
|
.modal-footer {
|
|
|
|
background-color: #222;
|
|
|
|
}
|
|
|
|
.modal-title {
|
|
|
|
font-weight: bold;
|
|
|
|
}
|
2024-11-01 02:11:26 +08:00
|
|
|
.favorite {
|
|
|
|
color: yellow;
|
|
|
|
}
|
2024-11-01 01:31:42 +08:00
|
|
|
</style>
|
|
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<div class="container-fluid">
|
|
|
|
<h2 class="text-center mt-4">FRN Servers Client Status</h2>
|
|
|
|
<div class="form-group">
|
|
|
|
<input type="text" id="searchInput" class="form-control" placeholder="Search clients...">
|
|
|
|
</div>
|
|
|
|
<div id="servers-container" class="client-table"></div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class="modal fade" id="clientModal" tabindex="-1" role="dialog" aria-labelledby="clientModalLabel" aria-hidden="true">
|
|
|
|
<div class="modal-dialog" role="document">
|
|
|
|
<div class="modal-content">
|
|
|
|
<div class="modal-header">
|
|
|
|
<h5 class="modal-title" id="clientModalLabel">Client Details</h5>
|
|
|
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
|
|
|
<span aria-hidden="true">×</span>
|
|
|
|
</button>
|
|
|
|
</div>
|
|
|
|
<div class="modal-body">
|
|
|
|
<p><strong>Status:</strong> <span id="modalStatus"></span></p>
|
|
|
|
<p><strong>Muted:</strong> <span id="modalMuted"></span></p>
|
|
|
|
<p><strong>Country:</strong> <span id="modalCountry"></span></p>
|
|
|
|
<p><strong>City:</strong> <span id="modalCity"></span></p>
|
|
|
|
<p><strong>Band/Channel:</strong> <span id="modalBandChannel"></span></p>
|
|
|
|
<p><strong>Client Type:</strong> <span id="modalClientType"></span></p>
|
|
|
|
<p><strong>Callsign:</strong> <span id="modalCallsign"></span></p>
|
|
|
|
<p><strong>Description:</strong> <span id="modalDescription"></span></p>
|
|
|
|
<p><strong>ID:</strong> <pre id="modalId" style="color: #ffffff;"></pre></p>
|
|
|
|
</div>
|
|
|
|
<div class="modal-footer">
|
|
|
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<script>
|
|
|
|
function updateClientStatus() {
|
|
|
|
$.get("http://localhost:8181/clients", function (data) {
|
2024-11-01 02:11:26 +08:00
|
|
|
localStorage.setItem('serversData', JSON.stringify(data.servers));
|
2024-11-01 01:31:42 +08:00
|
|
|
renderServers(data.servers);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function renderServers(servers) {
|
2024-11-01 02:11:26 +08:00
|
|
|
let favoriteServers = JSON.parse(localStorage.getItem('favoriteServers')) || [];
|
|
|
|
servers.sort((a, b) => {
|
|
|
|
const aFav = favoriteServers.includes(a.server_name) ? 1 : 0;
|
|
|
|
const bFav = favoriteServers.includes(b.server_name) ? 1 : 0;
|
|
|
|
return bFav - aFav;
|
|
|
|
});
|
|
|
|
|
2024-11-01 01:31:42 +08:00
|
|
|
let serversHtml = "";
|
|
|
|
servers.forEach(server => {
|
2024-11-01 02:11:26 +08:00
|
|
|
const isFavorite = favoriteServers.includes(server.server_name);
|
2024-11-01 01:31:42 +08:00
|
|
|
serversHtml += `<div class="card mb-4 server-card">
|
|
|
|
<div class="card-header">
|
2024-11-01 02:11:26 +08:00
|
|
|
<h5>
|
|
|
|
<i class="fa-solid fa-star star-icon ${isFavorite ? 'favorite' : ''}" data-server-name="${server.server_name}"></i>
|
|
|
|
${server.server_name}
|
|
|
|
</h5>
|
2024-11-01 01:31:42 +08:00
|
|
|
</div>
|
|
|
|
<div class="card-body">
|
2024-11-01 02:11:26 +08:00
|
|
|
<div class="table-responsive"><table class="table table-bordered w-100">
|
2024-11-01 01:31:42 +08:00
|
|
|
<thead class="thead-dark">
|
|
|
|
<tr>
|
|
|
|
<th>Status</th>
|
|
|
|
<th>Muted</th>
|
|
|
|
<th>Country</th>
|
|
|
|
<th>City</th>
|
|
|
|
<th>Band/Channel</th>
|
|
|
|
<th>Client Type</th>
|
|
|
|
<th>Callsign</th>
|
|
|
|
<th>Description</th>
|
|
|
|
</tr>
|
|
|
|
</thead>
|
|
|
|
<tbody>`;
|
|
|
|
|
|
|
|
server.clients.forEach(client => {
|
|
|
|
let clientIcon = "";
|
|
|
|
if (client.client_type === "Gateway") {
|
|
|
|
clientIcon = `<i class="fa-solid fa-tower-broadcast"></i>`;
|
|
|
|
} else if (client.client_type === "Crosslink") {
|
|
|
|
clientIcon = `<i class="fa-solid fa-arrows-alt"></i>`;
|
|
|
|
} else if (client.client_type === "PC Only") {
|
|
|
|
clientIcon = `<i class="fa fa-desktop"></i>`;
|
|
|
|
}
|
|
|
|
|
|
|
|
serversHtml += `<tr class="client-row" data-client='${JSON.stringify(client)}'>
|
|
|
|
<td class="text-center">
|
|
|
|
<i class="fas fa-circle status-icon ${client.status === 'Available' ? 'available' : 'unavailable'}"></i>
|
|
|
|
</td>
|
|
|
|
<td>${client.muted}</td>
|
|
|
|
<td>${client.country}</td>
|
|
|
|
<td>${client.city}</td>
|
|
|
|
<td>${client.band_channel}</td>
|
|
|
|
<td>${clientIcon} ${client.client_type}</td>
|
|
|
|
<td>${client.callsign}</td>
|
|
|
|
<td>${client.description}</td>
|
|
|
|
</tr>`;
|
|
|
|
});
|
|
|
|
|
|
|
|
serversHtml += `</tbody>
|
2024-11-01 02:11:26 +08:00
|
|
|
</table></div>
|
2024-11-01 01:31:42 +08:00
|
|
|
</div>
|
|
|
|
</div>`;
|
|
|
|
});
|
|
|
|
|
|
|
|
$('#servers-container').html(serversHtml);
|
|
|
|
}
|
|
|
|
|
|
|
|
$(document).ready(function () {
|
|
|
|
updateClientStatus();
|
|
|
|
setInterval(updateClientStatus, 5000); // Update every 5 seconds
|
|
|
|
|
|
|
|
$(document).on('click', '.client-row', function () {
|
|
|
|
const client = $(this).data('client');
|
|
|
|
$('#modalStatus').text(client.status);
|
|
|
|
$('#modalMuted').text(client.muted);
|
|
|
|
$('#modalCountry').text(client.country);
|
|
|
|
$('#modalCity').text(client.city);
|
|
|
|
$('#modalBandChannel').text(client.band_channel);
|
|
|
|
$('#modalClientType').text(client.client_type);
|
|
|
|
$('#modalCallsign').text(client.callsign);
|
|
|
|
$('#modalDescription').text(client.description);
|
|
|
|
$('#modalId').text(client.id);
|
|
|
|
$('#clientModal').modal('show');
|
|
|
|
});
|
|
|
|
|
|
|
|
$('#searchInput').on('keyup', function () {
|
|
|
|
const value = $(this).val().toLowerCase();
|
2024-11-01 02:11:26 +08:00
|
|
|
localStorage.setItem('searchValue', value);
|
|
|
|
filterServers(value);
|
|
|
|
});
|
2024-11-01 01:31:42 +08:00
|
|
|
|
2024-11-01 02:11:26 +08:00
|
|
|
function filterServers(value) {
|
2024-11-01 01:31:42 +08:00
|
|
|
$('.server-card').each(function () {
|
|
|
|
let serverVisible = false;
|
|
|
|
$(this).find('.client-row').each(function () {
|
|
|
|
const clientVisible = $(this).text().toLowerCase().indexOf(value) > -1;
|
|
|
|
$(this).toggle(clientVisible);
|
|
|
|
if (clientVisible) {
|
|
|
|
serverVisible = true;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
$(this).toggle(serverVisible);
|
|
|
|
});
|
2024-11-01 02:11:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
$(document).on('click', '.star-icon', function () {
|
|
|
|
const serverName = $(this).data('server-name');
|
|
|
|
let favoriteServers = JSON.parse(localStorage.getItem('favoriteServers')) || [];
|
|
|
|
|
|
|
|
if (favoriteServers.includes(serverName)) {
|
|
|
|
favoriteServers = favoriteServers.filter(name => name !== serverName);
|
|
|
|
$(this).removeClass('favorite');
|
|
|
|
} else {
|
|
|
|
favoriteServers.push(serverName);
|
|
|
|
$(this).addClass('favorite');
|
|
|
|
}
|
|
|
|
|
|
|
|
localStorage.setItem('favoriteServers', JSON.stringify(favoriteServers));
|
|
|
|
renderServers(JSON.parse(localStorage.getItem('serversData')) || []);
|
|
|
|
const searchValue = localStorage.getItem('searchValue') || "";
|
|
|
|
filterServers(searchValue);
|
2024-11-01 01:31:42 +08:00
|
|
|
});
|
2024-11-01 02:11:26 +08:00
|
|
|
|
|
|
|
const savedSearchValue = localStorage.getItem('searchValue') || "";
|
|
|
|
$('#searchInput').val(savedSearchValue);
|
|
|
|
filterServers(savedSearchValue);
|
2024-11-01 01:31:42 +08:00
|
|
|
});
|
|
|
|
</script>
|
|
|
|
</body>
|
2024-11-01 02:11:26 +08:00
|
|
|
</html>
|