192 lines
7.1 KiB
JavaScript
192 lines
7.1 KiB
JavaScript
// Enhanced Peers UI functions
|
|
|
|
let peerChart = null;
|
|
|
|
// Render peers list - uses generic pagination system
|
|
async function renderPeers() {
|
|
if (window.genericFetch) {
|
|
await window.genericFetch('peers', true);
|
|
}
|
|
renderPeerGraph();
|
|
}
|
|
|
|
// Filter peers - uses generic filter system
|
|
function filterPeers() {
|
|
if (window.genericFilter) {
|
|
window.genericFilter('peers');
|
|
}
|
|
}
|
|
|
|
// Show peer details modal
|
|
async function showPeerDetails(peerId) {
|
|
try {
|
|
const [peerRes, historyRes] = await Promise.all([
|
|
fetch(`/api/peers/${encodeURIComponent(peerId)}`),
|
|
fetch(`/api/peers/${encodeURIComponent(peerId)}/history`)
|
|
]);
|
|
|
|
if (!peerRes.ok || !historyRes.ok) {
|
|
throw new Error('Failed to fetch peer details');
|
|
}
|
|
|
|
const peer = await peerRes.json();
|
|
const history = await historyRes.json();
|
|
|
|
const modal = document.getElementById('peerDetailsModal');
|
|
if (!modal) return;
|
|
|
|
const content = document.getElementById('peer-details-content');
|
|
if (!content) return;
|
|
|
|
const uptime = peer.uptime ? (window.formatUptime ? window.formatUptime(peer.uptime) : `${Math.floor(peer.uptime / 1000)}s`) : 'N/A';
|
|
const connectTime = peer.connectTime ? new Date(peer.connectTime).toLocaleString() : 'N/A';
|
|
const lastSeen = peer.metrics?.lastSeen ? new Date(peer.metrics.lastSeen).toLocaleString() : 'N/A';
|
|
|
|
content.innerHTML = `
|
|
<div class="space-y-4">
|
|
<div>
|
|
<h4 class="font-semibold mb-2">Peer Information</h4>
|
|
<div class="bg-gray-100 dark:bg-gray-700 p-3 rounded">
|
|
<p><strong>ID:</strong> <span class="font-mono text-sm break-all">${peer.id}</span></p>
|
|
<p><strong>Status:</strong> ${peer.connected ? '<span class="text-green-600">Connected</span>' : '<span class="text-gray-600">Disconnected</span>'}</p>
|
|
<p><strong>Uptime:</strong> ${uptime}</p>
|
|
<p><strong>Connected At:</strong> ${connectTime}</p>
|
|
<p><strong>Blocked:</strong> ${peer.isBlocked ? '<span class="text-red-600">Yes</span>' : '<span class="text-green-600">No</span>'}</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<h4 class="font-semibold mb-2">Metrics</h4>
|
|
<div class="bg-gray-100 dark:bg-gray-700 p-3 rounded">
|
|
<p><strong>Total Connections:</strong> ${peer.metrics?.connections || 0}</p>
|
|
<p><strong>Total Duration:</strong> ${peer.metrics?.totalDuration ? (window.formatDuration ? window.formatDuration(peer.metrics.totalDuration) : `${Math.floor(peer.metrics.totalDuration / 1000)}s`) : '0s'}</p>
|
|
<p><strong>Average Duration:</strong> ${peer.metrics?.avgDuration ? (window.formatDuration ? window.formatDuration(peer.metrics.avgDuration) : `${Math.floor(peer.metrics.avgDuration / 1000)}s`) : 'N/A'}</p>
|
|
<p><strong>Last Seen:</strong> ${lastSeen}</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<h4 class="font-semibold mb-2">Connection History (Last 50)</h4>
|
|
<div class="bg-gray-100 dark:bg-gray-700 p-3 rounded max-h-64 overflow-y-auto">
|
|
${history.length === 0
|
|
? '<p class="text-gray-500">No history available</p>'
|
|
: history.slice(-50).reverse().map(event => `
|
|
<div class="mb-2 pb-2 border-b border-gray-300 dark:border-gray-600">
|
|
<div class="flex justify-between">
|
|
<span class="font-semibold ${event.type === 'connect' ? 'text-green-600' : 'text-red-600'}">${event.type === 'connect' ? 'Connected' : 'Disconnected'}</span>
|
|
<span class="text-sm text-gray-600 dark:text-gray-400">${new Date(event.timestamp).toLocaleString()}</span>
|
|
</div>
|
|
${event.duration ? `<div class="text-sm text-gray-600 dark:text-gray-400">Duration: ${window.formatDuration ? window.formatDuration(event.duration) : `${Math.floor(event.duration / 1000)}s`}</div>` : ''}
|
|
${event.error ? `<div class="text-sm text-red-600">Error: ${event.error}</div>` : ''}
|
|
</div>
|
|
`).join('')
|
|
}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
|
|
modal.showModal();
|
|
} catch (err) {
|
|
console.error('Failed to fetch peer details:', err);
|
|
if (window.showNotification) window.showNotification('Failed to load peer details: ' + err.message, 'error');
|
|
}
|
|
}
|
|
|
|
// Block peer
|
|
async function blockPeer(peerId) {
|
|
if (window.showConfirm) {
|
|
window.showConfirm(`Block peer ${peerId.substring(0, 16)}...?`, async () => {
|
|
try {
|
|
const response = await fetch(`/api/peers/${encodeURIComponent(peerId)}/block`, {
|
|
method: 'POST'
|
|
});
|
|
if (!response.ok) {
|
|
throw new Error('Failed to block peer');
|
|
}
|
|
if (window.showNotification) window.showNotification('Peer blocked successfully');
|
|
await renderPeers();
|
|
} catch (err) {
|
|
console.error('Failed to block peer:', err);
|
|
if (window.showNotification) window.showNotification('Failed to block peer: ' + err.message, 'error');
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
// Unblock peer
|
|
async function unblockPeer(peerId) {
|
|
if (window.showConfirm) {
|
|
window.showConfirm(`Unblock peer ${peerId.substring(0, 16)}...?`, async () => {
|
|
try {
|
|
const response = await fetch(`/api/peers/${encodeURIComponent(peerId)}/unblock`, {
|
|
method: 'POST'
|
|
});
|
|
if (!response.ok) {
|
|
throw new Error('Failed to unblock peer');
|
|
}
|
|
if (window.showNotification) window.showNotification('Peer unblocked successfully');
|
|
await renderPeers();
|
|
} catch (err) {
|
|
console.error('Failed to unblock peer:', err);
|
|
if (window.showNotification) window.showNotification('Failed to unblock peer: ' + err.message, 'error');
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
// Render peer connection graph
|
|
function renderPeerGraph() {
|
|
const canvas = document.getElementById('peer-graph-chart');
|
|
if (!canvas) return;
|
|
|
|
const ctx = canvas.getContext('2d');
|
|
|
|
if (peerChart) {
|
|
peerChart.destroy();
|
|
}
|
|
|
|
// Get peers data from global state
|
|
const peersData = window.peersData || [];
|
|
|
|
// Group peers by connection status over time (simplified - using current data)
|
|
const connected = peersData.filter(p => p.connected).length;
|
|
const disconnected = peersData.filter(p => !p.connected).length;
|
|
const blocked = peersData.filter(p => p.isBlocked).length;
|
|
|
|
peerChart = new Chart(ctx, {
|
|
type: 'doughnut',
|
|
data: {
|
|
labels: ['Connected', 'Disconnected', 'Blocked'],
|
|
datasets: [{
|
|
data: [connected, disconnected, blocked],
|
|
backgroundColor: [
|
|
'rgb(34, 197, 94)',
|
|
'rgb(107, 114, 128)',
|
|
'rgb(239, 68, 68)'
|
|
]
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
plugins: {
|
|
legend: {
|
|
position: 'bottom',
|
|
labels: {
|
|
color: '#f1f5f9' // White text for better readability on dark background
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
// Make functions globally accessible
|
|
window.renderPeers = renderPeers;
|
|
window.showPeerDetails = showPeerDetails;
|
|
window.blockPeer = blockPeer;
|
|
window.unblockPeer = unblockPeer;
|
|
window.filterPeers = filterPeers;
|
|
|