wip
This commit is contained in:
parent
1ab129b798
commit
af4b75acb4
3 changed files with 93 additions and 6 deletions
|
@ -547,3 +547,59 @@
|
||||||
.app-link:hover {
|
.app-link:hover {
|
||||||
color: var(--highlight-color);
|
color: var(--highlight-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Validation styles */
|
||||||
|
.is-invalid {
|
||||||
|
border-color: #dc3545 !important;
|
||||||
|
padding-right: calc(1.5em + 0.75rem);
|
||||||
|
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: right calc(0.375em + 0.1875rem) center;
|
||||||
|
background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-valid {
|
||||||
|
border-color: #198754 !important;
|
||||||
|
padding-right: calc(1.5em + 0.75rem);
|
||||||
|
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: right calc(0.375em + 0.1875rem) center;
|
||||||
|
background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
.invalid-feedback {
|
||||||
|
display: none;
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 0.25rem;
|
||||||
|
font-size: 0.875em;
|
||||||
|
color: #dc3545;
|
||||||
|
}
|
||||||
|
|
||||||
|
.invalid-feedback.d-block {
|
||||||
|
display: block !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.valid-feedback {
|
||||||
|
display: none;
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 0.25rem;
|
||||||
|
font-size: 0.875em;
|
||||||
|
color: #198754;
|
||||||
|
}
|
||||||
|
|
||||||
|
.valid-feedback.d-block {
|
||||||
|
display: block !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fix position for validation messages in table cells */
|
||||||
|
td.position-relative {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
td .feedback {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
left: 0;
|
||||||
|
top: 100%;
|
||||||
|
z-index: 5;
|
||||||
|
}
|
|
@ -53,6 +53,13 @@ function validateAppName() {
|
||||||
// Port Validation
|
// Port Validation
|
||||||
function validatePort(portField, protocolField) {
|
function validatePort(portField, protocolField) {
|
||||||
const serverField = document.getElementById('server-id');
|
const serverField = document.getElementById('server-id');
|
||||||
|
// Create feedback element if it doesn't exist
|
||||||
|
if (!portField.nextElementSibling || !portField.nextElementSibling.classList.contains('feedback')) {
|
||||||
|
const feedback = document.createElement('div');
|
||||||
|
feedback.className = 'feedback';
|
||||||
|
portField.parentNode.insertBefore(feedback, portField.nextSibling);
|
||||||
|
}
|
||||||
|
|
||||||
const feedbackElement = portField.nextElementSibling;
|
const feedbackElement = portField.nextElementSibling;
|
||||||
const submitButton = document.querySelector('button[type="submit"]');
|
const submitButton = document.querySelector('button[type="submit"]');
|
||||||
|
|
||||||
|
@ -65,6 +72,26 @@ function validatePort(portField, protocolField) {
|
||||||
|
|
||||||
if (!port || !serverId) {
|
if (!port || !serverId) {
|
||||||
clearFeedback(feedbackElement);
|
clearFeedback(feedbackElement);
|
||||||
|
portField.classList.remove('is-invalid');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for duplicate ports within the form first
|
||||||
|
const allPortFields = document.querySelectorAll('input[name="port_numbers[]"]');
|
||||||
|
const allProtocolFields = document.querySelectorAll('select[name="protocols[]"]');
|
||||||
|
let duplicateFound = false;
|
||||||
|
|
||||||
|
allPortFields.forEach((field, index) => {
|
||||||
|
if (field !== portField &&
|
||||||
|
field.value === port &&
|
||||||
|
allProtocolFields[index].value === protocol) {
|
||||||
|
duplicateFound = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (duplicateFound) {
|
||||||
|
portField.classList.add('is-invalid');
|
||||||
|
showError(feedbackElement, `Duplicate port ${port}/${protocol} in your form`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,22 +102,22 @@ function validatePort(portField, protocolField) {
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
if (!data.valid) {
|
if (!data.valid) {
|
||||||
|
portField.classList.add('is-invalid');
|
||||||
showError(feedbackElement, data.message);
|
showError(feedbackElement, data.message);
|
||||||
if (data.edit_url) {
|
if (data.edit_url) {
|
||||||
feedbackElement.innerHTML += ` <a href="${data.edit_url}" class="alert-link">Edit the conflicting app?</a>`;
|
feedbackElement.innerHTML += ` <a href="${data.edit_url}" class="alert-link">Edit conflicting app</a>`;
|
||||||
}
|
}
|
||||||
portField.classList.add('is-invalid');
|
|
||||||
submitButton.disabled = true;
|
|
||||||
} else {
|
} else {
|
||||||
clearFeedback(feedbackElement);
|
|
||||||
portField.classList.remove('is-invalid');
|
portField.classList.remove('is-invalid');
|
||||||
portField.classList.add('is-valid');
|
portField.classList.add('is-valid');
|
||||||
submitButton.disabled = false;
|
showSuccess(feedbackElement, "Port available");
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.error('Validation error:', error);
|
console.error('Validation error:', error);
|
||||||
clearFeedback(feedbackElement);
|
clearFeedback(feedbackElement);
|
||||||
|
portField.classList.remove('is-invalid');
|
||||||
|
portField.classList.remove('is-valid');
|
||||||
});
|
});
|
||||||
}, 300);
|
}, 300);
|
||||||
}
|
}
|
||||||
|
|
|
@ -256,9 +256,10 @@
|
||||||
const tbody = document.querySelector('#ports-table tbody');
|
const tbody = document.querySelector('#ports-table tbody');
|
||||||
const newRow = document.createElement('tr');
|
const newRow = document.createElement('tr');
|
||||||
newRow.innerHTML = `
|
newRow.innerHTML = `
|
||||||
<td>
|
<td class="position-relative">
|
||||||
<input type="number" name="port_numbers[]" class="form-control"
|
<input type="number" name="port_numbers[]" class="form-control"
|
||||||
min="1" max="65535" value="${portNumber}" required>
|
min="1" max="65535" value="${portNumber}" required>
|
||||||
|
<div class="feedback"></div>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<select name="protocols[]" class="form-select">
|
<select name="protocols[]" class="form-select">
|
||||||
|
@ -279,6 +280,9 @@
|
||||||
</td>
|
</td>
|
||||||
`;
|
`;
|
||||||
tbody.appendChild(newRow);
|
tbody.appendChild(newRow);
|
||||||
|
|
||||||
|
// Set up validation for the new row
|
||||||
|
setTimeout(setupPortValidation, 50);
|
||||||
}
|
}
|
||||||
|
|
||||||
function removePortRow(button) {
|
function removePortRow(button) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue