This commit is contained in:
pika 2025-04-03 13:51:52 +02:00
parent 78ce15e82d
commit 0a31714a93
10 changed files with 159 additions and 149 deletions

View file

@ -119,8 +119,6 @@
<select name="protocols[]" class="form-select">
<option value="TCP" {% if port.protocol=='TCP' %}selected{% endif %}>TCP</option>
<option value="UDP" {% if port.protocol=='UDP' %}selected{% endif %}>UDP</option>
<option value="SCTP" {% if port.protocol=='SCTP' %}selected{% endif %}>SCTP</option>
<option value="OTHER" {% if port.protocol=='OTHER' %}selected{% endif %}>OTHER</option>
</select>
</td>
<td>
@ -144,8 +142,6 @@
<select name="protocols[]" class="form-select">
<option value="TCP" selected>TCP</option>
<option value="UDP">UDP</option>
<option value="SCTP">SCTP</option>
<option value="OTHER">OTHER</option>
</select>
</td>
<td>
@ -251,9 +247,48 @@
</script>
<script>
// Make sure removePortRow is in the global scope
window.removePortRow = function (button) {
const tbody = document.querySelector('#ports-table tbody');
const row = button.closest('tr');
// Get current number of rows
const rowCount = tbody.querySelectorAll('tr').length;
// If this is the last row, clear its values instead of removing
if (rowCount <= 1) {
const inputs = row.querySelectorAll('input');
inputs.forEach(input => {
input.value = '';
});
// Reset protocol to TCP
const protocolSelect = row.querySelector('select[name="protocols[]"]');
if (protocolSelect) {
protocolSelect.value = 'TCP';
}
// Add a visual indicator that this row is empty
row.classList.add('table-secondary', 'opacity-50');
// Show a helping message
showNotification('Application saved with no ports. Use "Add Port" to add ports.', 'info');
} else {
// Remove the row if there are other rows
row.remove();
}
};
// Port management functions
function addPortRow(portNumber = '', protocol = 'TCP', description = '') {
const tbody = document.querySelector('#ports-table tbody');
// Remove the empty row indicator if present
const emptyRows = tbody.querySelectorAll('tr.table-secondary.opacity-50');
if (emptyRows.length > 0) {
emptyRows.forEach(row => row.remove());
}
const newRow = document.createElement('tr');
newRow.innerHTML = `
<td class="position-relative">
@ -265,8 +300,6 @@
<select name="protocols[]" class="form-select">
<option value="TCP" ${protocol === 'TCP' ? 'selected' : ''}>TCP</option>
<option value="UDP" ${protocol === 'UDP' ? 'selected' : ''}>UDP</option>
<option value="SCTP" ${protocol === 'SCTP' ? 'selected' : ''}>SCTP</option>
<option value="OTHER" ${protocol === 'OTHER' ? 'selected' : ''}>OTHER</option>
</select>
</td>
<td>
@ -285,10 +318,6 @@
setTimeout(setupPortValidation, 50);
}
function removePortRow(button) {
button.closest('tr').remove();
}
async function generateRandomPort() {
try {
const serverId = document.querySelector('select[name="server_id"]').value;

View file

@ -156,7 +156,7 @@
<label class="form-label required">Port Number</label>
<div class="input-group">
<input type="number" class="form-control" name="port_number" min="1" max="65535" required>
<button class="btn btn-outline-secondary" type="button" id="randomPortBtn">
<button class="btn btn-outline-secondary" type="button" id="suggestRandomPort">
<span class="ti ti-dice"></span>
</button>
</div>
@ -166,8 +166,6 @@
<select class="form-select" name="protocol">
<option value="TCP">TCP</option>
<option value="UDP">UDP</option>
<option value="SCTP">SCTP</option>
<option value="OTHER">OTHER</option>
</select>
</div>
<div class="mb-3">
@ -350,56 +348,62 @@
{% block extra_js %}
<script>
// Store app ID for JavaScript use
const appId = {{ app.id }};
let portToDelete = null;
// Global variable to store the port ID to delete
let portIdToDelete = null;
// IMPORTANT: Define confirmDeletePort outside the DOMContentLoaded event
// so it's available in the global scope
// Function to confirm port deletion
function confirmDeletePort(portId) {
portToDelete = portId;
const modal = new bootstrap.Modal(document.getElementById('deletePortModal'));
modal.show();
portIdToDelete = portId;
// Show the delete modal
const deleteModal = new bootstrap.Modal(document.getElementById('deletePortModal'));
deleteModal.show();
}
// Set up event listeners when DOM is ready
// Set up the confirm button in the delete modal
document.addEventListener('DOMContentLoaded', function () {
// Handle random port button click
const randomPortBtn = document.getElementById('randomPortBtn');
if (randomPortBtn) {
randomPortBtn.addEventListener('click', function () {
fetch('/api/ports/random')
.then(response => response.json())
.then(data => {
document.querySelector('#addPortForm input[name="port_number"]').value = data.port;
})
.catch(error => {
console.error('Error fetching random port:', error);
});
});
}
// Handle port deletion confirmation
const confirmDeleteBtn = document.getElementById('confirmDeleteBtn');
if (confirmDeleteBtn) {
confirmDeleteBtn.addEventListener('click', function () {
if (portToDelete) {
// Create a form and submit it programmatically
if (portIdToDelete) {
// Create a form to submit the delete request
const form = document.createElement('form');
form.method = 'POST';
form.action = `/api/app/${appId}/port/${portToDelete}/delete`;
form.action = `/api/app/{{ app.id }}/port/${portIdToDelete}/delete`;
// Add CSRF token
const csrfInput = document.createElement('input');
csrfInput.type = 'hidden';
csrfInput.name = 'csrf_token';
csrfInput.value = '{{ csrf_token() }}';
form.appendChild(csrfInput);
// Append to body, submit, and remove
document.body.appendChild(form);
form.submit();
document.body.removeChild(form);
}
});
}
// Set up the random port button
const randomPortBtn = document.getElementById('randomPortBtn');
if (randomPortBtn) {
randomPortBtn.addEventListener('click', function () {
fetch(`/api/server/{{ app.server.id }}/free-port`)
.then(response => response.json())
.then(data => {
if (data.success && data.port) {
document.querySelector('input[name="port_number"]').value = data.port;
} else {
alert(data.error || 'Could not generate a random port');
}
})
.catch(error => {
console.error('Error generating random port:', error);
alert('Error generating random port');
});
});
}
});
</script>
{% endblock %}

View file

@ -17,8 +17,8 @@
<link rel="stylesheet" href="{{ url_for('static', filename='css/app.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/tabler.min.css') }}"
onerror="this.onerror=null;this.href='https://cdn.jsdelivr.net/npm/@tabler/core@latest/dist/css/tabler.min.css';">
<link rel="stylesheet" href="{{ url_for('static', filename='libs/tabler-icons/tabler-icons.min.css') }}"
onerror="this.onerror=null;this.href='https://cdn.jsdelivr.net/npm/@tabler/icons@latest/iconfont/tabler-icons.min.css';">
<!-- <link rel="stylesheet" href="{{ url_for('static', filename='libs/tabler-icons/tabler-icons.min.css') }}" -->
<!-- onerror="this.onerror=null;this.href='https://cdn.jsdelivr.net/npm/@tabler/icons@latest/iconfont/tabler-icons.min.css';"> -->
<link rel="stylesheet" href="{{ url_for('static', filename='css/custom.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/github-markdown-reading-view.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/github-markdown-source-view.css') }}">