wip
This commit is contained in:
parent
9433d9d235
commit
7b6837cf96
7 changed files with 370 additions and 63 deletions
181
app/static/js/ports.js
Normal file
181
app/static/js/ports.js
Normal file
|
@ -0,0 +1,181 @@
|
|||
document.addEventListener('DOMContentLoaded', function () {
|
||||
// Initialize the compact port display
|
||||
initPortDisplay();
|
||||
|
||||
// Add event listener for copy buttons
|
||||
document.addEventListener('click', function (e) {
|
||||
if (e.target.classList.contains('copy-port')) {
|
||||
const port = e.target.dataset.port;
|
||||
copyToClipboard(port);
|
||||
|
||||
// Visual feedback
|
||||
const originalText = e.target.innerHTML;
|
||||
e.target.innerHTML = '<span class="ti ti-check"></span>';
|
||||
setTimeout(() => {
|
||||
e.target.innerHTML = originalText;
|
||||
}, 1000);
|
||||
}
|
||||
});
|
||||
|
||||
// Get free port button
|
||||
const getFreePortBtn = document.getElementById('get-free-port');
|
||||
if (getFreePortBtn) {
|
||||
getFreePortBtn.addEventListener('click', function () {
|
||||
fetch(`/api/server/${serverId}/free-port`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
copyToClipboard(data.port);
|
||||
showNotification('success', `Free port ${data.port} copied to clipboard`);
|
||||
} else {
|
||||
showNotification('error', data.error || 'Error finding free port');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
showNotification('error', 'Failed to get free port');
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function initPortDisplay() {
|
||||
const portRangesContainer = document.getElementById('port-ranges');
|
||||
const usedPortsList = document.getElementById('used-ports-list');
|
||||
|
||||
if (!portRangesContainer || !usedPortsList) return;
|
||||
|
||||
// Get port usage data from server
|
||||
fetch(`/api/server/${serverId}/ports`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
// Process the data and organize into ranges
|
||||
const usedPorts = data.used_ports || [];
|
||||
const ranges = generatePortRanges(usedPorts);
|
||||
|
||||
// Render port ranges visualization
|
||||
renderPortRanges(ranges, portRangesContainer);
|
||||
|
||||
// Render list of used ports with copy buttons
|
||||
renderUsedPorts(usedPorts, usedPortsList);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error fetching port data:', error);
|
||||
portRangesContainer.innerHTML = '<div class="alert alert-danger">Failed to load port data</div>';
|
||||
});
|
||||
}
|
||||
|
||||
function generatePortRanges(usedPorts) {
|
||||
// Create a simplified representation of port ranges
|
||||
const ranges = [];
|
||||
const portMax = 9100;
|
||||
const segmentSize = 100;
|
||||
|
||||
for (let i = 0; i < portMax; i += segmentSize) {
|
||||
const start = i;
|
||||
const end = Math.min(i + segmentSize - 1, portMax);
|
||||
|
||||
// Count used ports in this range
|
||||
const usedCount = usedPorts.filter(port => port >= start && port <= end).length;
|
||||
const percentageUsed = (usedCount / segmentSize) * 100;
|
||||
|
||||
ranges.push({
|
||||
start,
|
||||
end,
|
||||
percentageUsed,
|
||||
isEmpty: usedCount === 0,
|
||||
isFull: usedCount === segmentSize
|
||||
});
|
||||
}
|
||||
|
||||
return ranges;
|
||||
}
|
||||
|
||||
function renderPortRanges(ranges, container) {
|
||||
let html = '';
|
||||
|
||||
ranges.forEach(range => {
|
||||
const width = (range.end - range.start + 1) / 91; // Calculate relative width
|
||||
const cssClass = range.percentageUsed > 0 ? 'port-range-used' : 'port-range-free';
|
||||
|
||||
html += `<div
|
||||
class="port-range ${cssClass}"
|
||||
style="flex-grow: ${width};"
|
||||
title="${range.start}-${range.end}: ${range.percentageUsed.toFixed(1)}% used"
|
||||
></div>`;
|
||||
});
|
||||
|
||||
container.innerHTML = html;
|
||||
}
|
||||
|
||||
function renderUsedPorts(usedPorts, container) {
|
||||
if (usedPorts.length === 0) {
|
||||
container.innerHTML = '<div class="text-muted">No ports in use</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
let html = '';
|
||||
usedPorts.sort((a, b) => a - b).forEach(port => {
|
||||
html += `
|
||||
<div class="used-port-tag">
|
||||
${port}
|
||||
<span class="ti ti-copy copy-port" data-port="${port}" title="Copy port"></span>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
|
||||
container.innerHTML = html;
|
||||
}
|
||||
|
||||
function copyToClipboard(text) {
|
||||
// Use modern clipboard API with fallback
|
||||
if (navigator.clipboard) {
|
||||
navigator.clipboard.writeText(text)
|
||||
.catch(err => {
|
||||
console.error('Failed to copy: ', err);
|
||||
fallbackCopyToClipboard(text);
|
||||
});
|
||||
} else {
|
||||
fallbackCopyToClipboard(text);
|
||||
}
|
||||
}
|
||||
|
||||
function fallbackCopyToClipboard(text) {
|
||||
const textArea = document.createElement('textarea');
|
||||
textArea.value = text;
|
||||
textArea.style.position = 'fixed';
|
||||
textArea.style.left = '-999999px';
|
||||
document.body.appendChild(textArea);
|
||||
textArea.focus();
|
||||
textArea.select();
|
||||
|
||||
try {
|
||||
document.execCommand('copy');
|
||||
} catch (err) {
|
||||
console.error('Fallback copy failed:', err);
|
||||
}
|
||||
|
||||
document.body.removeChild(textArea);
|
||||
}
|
||||
|
||||
function showNotification(type, message) {
|
||||
const notificationArea = document.getElementById('notification-area');
|
||||
if (!notificationArea) return;
|
||||
|
||||
const notification = document.createElement('div');
|
||||
notification.className = `alert alert-${type === 'error' ? 'danger' : type} alert-dismissible fade show notification`;
|
||||
notification.innerHTML = `
|
||||
${message}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
`;
|
||||
|
||||
notificationArea.appendChild(notification);
|
||||
|
||||
// Auto dismiss after 5 seconds
|
||||
setTimeout(() => {
|
||||
notification.classList.remove('show');
|
||||
setTimeout(() => {
|
||||
notificationArea.removeChild(notification);
|
||||
}, 300);
|
||||
}, 5000);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue