fixed deletion
This commit is contained in:
parent
e9d1f985ae
commit
78ce15e82d
2 changed files with 94 additions and 58 deletions
|
@ -409,15 +409,27 @@ def app_edit(app_id):
|
||||||
@bp.route("/app/<int:app_id>/delete", methods=["POST"])
|
@bp.route("/app/<int:app_id>/delete", methods=["POST"])
|
||||||
@login_required
|
@login_required
|
||||||
def app_delete(app_id):
|
def app_delete(app_id):
|
||||||
"""Delete an application"""
|
"""Delete an application and all its ports"""
|
||||||
app = App.query.get_or_404(app_id)
|
app = App.query.get_or_404(app_id)
|
||||||
|
app_name = app.name
|
||||||
server_id = app.server_id
|
server_id = app.server_id
|
||||||
|
|
||||||
db.session.delete(app)
|
try:
|
||||||
db.session.commit()
|
# First explicitly delete all associated ports
|
||||||
|
Port.query.filter_by(app_id=app_id).delete()
|
||||||
flash("Application deleted successfully", "success")
|
|
||||||
return redirect(url_for("dashboard.server_view", server_id=server_id))
|
# Then delete the application
|
||||||
|
db.session.delete(app)
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
flash(f"Application '{app_name}' has been deleted", "success")
|
||||||
|
|
||||||
|
# Redirect back to server view
|
||||||
|
return redirect(url_for("dashboard.server_view", server_id=server_id))
|
||||||
|
except Exception as e:
|
||||||
|
db.session.rollback()
|
||||||
|
flash(f"Error deleting application: {str(e)}", "danger")
|
||||||
|
return redirect(url_for("dashboard.app_view", app_id=app_id))
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/settings", methods=["GET", "POST"])
|
@bp.route("/settings", methods=["GET", "POST"])
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
// Application Name Validation
|
// Application Name Validation
|
||||||
function validateAppName() {
|
function validateAppName() {
|
||||||
const nameField = document.getElementById('app-name');
|
const nameField = document.getElementById("app-name");
|
||||||
const serverField = document.getElementById('server-id');
|
const serverField = document.getElementById("server-id");
|
||||||
const feedbackElement = document.getElementById('name-feedback');
|
const feedbackElement = document.getElementById("name-feedback");
|
||||||
const submitButton = document.querySelector('button[type="submit"]');
|
const submitButton = document.querySelector('button[type="submit"]');
|
||||||
|
|
||||||
if (!nameField || !serverField) return;
|
if (!nameField || !serverField) return;
|
||||||
|
|
||||||
const name = nameField.value.trim();
|
const name = nameField.value.trim();
|
||||||
const serverId = serverField.value;
|
const serverId = serverField.value;
|
||||||
const appId = document.getElementById('app-id')?.value;
|
const appId = document.getElementById("app-id")?.value;
|
||||||
|
|
||||||
if (!name || !serverId) {
|
if (!name || !serverId) {
|
||||||
clearFeedback(feedbackElement);
|
clearFeedback(feedbackElement);
|
||||||
|
@ -19,9 +19,11 @@ function validateAppName() {
|
||||||
// Debounce to avoid too many requests
|
// Debounce to avoid too many requests
|
||||||
clearTimeout(nameField.timer);
|
clearTimeout(nameField.timer);
|
||||||
nameField.timer = setTimeout(() => {
|
nameField.timer = setTimeout(() => {
|
||||||
fetch(`/api/validate/app-name?name=${encodeURIComponent(name)}&server_id=${serverId}${appId ? '&app_id=' + appId : ''}`)
|
fetch(
|
||||||
.then(response => response.json())
|
`/api/validate/app-name?name=${encodeURIComponent(name)}&server_id=${serverId}${appId ? "&app_id=" + appId : ""}`,
|
||||||
.then(data => {
|
)
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((data) => {
|
||||||
if (!data.valid) {
|
if (!data.valid) {
|
||||||
showError(feedbackElement, data.message);
|
showError(feedbackElement, data.message);
|
||||||
if (data.edit_url) {
|
if (data.edit_url) {
|
||||||
|
@ -32,10 +34,10 @@ function validateAppName() {
|
||||||
showWarning(feedbackElement, data.warning);
|
showWarning(feedbackElement, data.warning);
|
||||||
if (data.similar_apps && data.similar_apps.length > 0) {
|
if (data.similar_apps && data.similar_apps.length > 0) {
|
||||||
feedbackElement.innerHTML += '<ul class="mb-0 mt-1">';
|
feedbackElement.innerHTML += '<ul class="mb-0 mt-1">';
|
||||||
data.similar_apps.forEach(app => {
|
data.similar_apps.forEach((app) => {
|
||||||
feedbackElement.innerHTML += `<li><a href="/dashboard/app/${app.id}/edit" class="alert-link">${app.name}</a></li>`;
|
feedbackElement.innerHTML += `<li><a href="/dashboard/app/${app.id}/edit" class="alert-link">${app.name}</a></li>`;
|
||||||
});
|
});
|
||||||
feedbackElement.innerHTML += '</ul>';
|
feedbackElement.innerHTML += "</ul>";
|
||||||
}
|
}
|
||||||
submitButton.disabled = false;
|
submitButton.disabled = false;
|
||||||
} else {
|
} else {
|
||||||
|
@ -43,8 +45,8 @@ function validateAppName() {
|
||||||
submitButton.disabled = false;
|
submitButton.disabled = false;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch((error) => {
|
||||||
console.error('Validation error:', error);
|
console.error("Validation error:", error);
|
||||||
clearFeedback(feedbackElement);
|
clearFeedback(feedbackElement);
|
||||||
});
|
});
|
||||||
}, 300);
|
}, 300);
|
||||||
|
@ -52,11 +54,14 @@ 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
|
// Create feedback element if it doesn't exist
|
||||||
if (!portField.nextElementSibling || !portField.nextElementSibling.classList.contains('feedback')) {
|
if (
|
||||||
const feedback = document.createElement('div');
|
!portField.nextElementSibling ||
|
||||||
feedback.className = 'feedback';
|
!portField.nextElementSibling.classList.contains("feedback")
|
||||||
|
) {
|
||||||
|
const feedback = document.createElement("div");
|
||||||
|
feedback.className = "feedback";
|
||||||
portField.parentNode.insertBefore(feedback, portField.nextSibling);
|
portField.parentNode.insertBefore(feedback, portField.nextSibling);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,56 +73,69 @@ function validatePort(portField, protocolField) {
|
||||||
const port = portField.value.trim();
|
const port = portField.value.trim();
|
||||||
const protocol = protocolField.value;
|
const protocol = protocolField.value;
|
||||||
const serverId = serverField.value;
|
const serverId = serverField.value;
|
||||||
const appId = document.getElementById('app-id')?.value;
|
const appId = document.getElementById("app-id")?.value;
|
||||||
|
|
||||||
if (!port || !serverId) {
|
if (!port || !serverId) {
|
||||||
clearFeedback(feedbackElement);
|
clearFeedback(feedbackElement);
|
||||||
portField.classList.remove('is-invalid');
|
portField.classList.remove("is-invalid");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for duplicate ports within the form first
|
// Check for duplicate ports within the form first
|
||||||
const allPortFields = document.querySelectorAll('input[name="port_numbers[]"]');
|
const allPortFields = document.querySelectorAll(
|
||||||
const allProtocolFields = document.querySelectorAll('select[name="protocols[]"]');
|
'input[name="port_numbers[]"]',
|
||||||
|
);
|
||||||
|
const allProtocolFields = document.querySelectorAll(
|
||||||
|
'select[name="protocols[]"]',
|
||||||
|
);
|
||||||
let duplicateFound = false;
|
let duplicateFound = false;
|
||||||
|
|
||||||
allPortFields.forEach((field, index) => {
|
allPortFields.forEach((field, index) => {
|
||||||
if (field !== portField &&
|
if (
|
||||||
|
field !== portField &&
|
||||||
field.value === port &&
|
field.value === port &&
|
||||||
allProtocolFields[index].value === protocol) {
|
allProtocolFields[index].value === protocol
|
||||||
|
) {
|
||||||
duplicateFound = true;
|
duplicateFound = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (duplicateFound) {
|
if (duplicateFound) {
|
||||||
portField.classList.add('is-invalid');
|
portField.classList.add("is-invalid");
|
||||||
showError(feedbackElement, `Duplicate port ${port}/${protocol} in your form`);
|
clearFeedback(feedbackElement);
|
||||||
|
showError(
|
||||||
|
feedbackElement,
|
||||||
|
`Duplicate port ${port}/${protocol} in your form`,
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Debounce to avoid too many requests
|
// Debounce to avoid too many requests
|
||||||
clearTimeout(portField.timer);
|
clearTimeout(portField.timer);
|
||||||
portField.timer = setTimeout(() => {
|
portField.timer = setTimeout(() => {
|
||||||
fetch(`/api/validate/app-port?port_number=${encodeURIComponent(port)}&protocol=${protocol}&server_id=${serverId}${appId ? '&app_id=' + appId : ''}`)
|
fetch(
|
||||||
.then(response => response.json())
|
`/api/validate/app-port?port_number=${encodeURIComponent(port)}&protocol=${protocol}&server_id=${serverId}${appId ? "&app_id=" + appId : ""}`,
|
||||||
.then(data => {
|
)
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((data) => {
|
||||||
|
clearFeedback(feedbackElement);
|
||||||
if (!data.valid) {
|
if (!data.valid) {
|
||||||
portField.classList.add('is-invalid');
|
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 conflicting app</a>`;
|
feedbackElement.innerHTML += ` <a href="${data.edit_url}" class="alert-link">Edit conflicting app</a>`;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
portField.classList.remove('is-invalid');
|
portField.classList.remove("is-invalid");
|
||||||
portField.classList.add('is-valid');
|
portField.classList.add("is-valid");
|
||||||
showSuccess(feedbackElement, "Port available");
|
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-invalid");
|
||||||
portField.classList.remove('is-valid');
|
portField.classList.remove("is-valid");
|
||||||
});
|
});
|
||||||
}, 300);
|
}, 300);
|
||||||
}
|
}
|
||||||
|
@ -125,38 +143,38 @@ function validatePort(portField, protocolField) {
|
||||||
// Helper functions for feedback display
|
// Helper functions for feedback display
|
||||||
function showError(element, message) {
|
function showError(element, message) {
|
||||||
if (!element) return;
|
if (!element) return;
|
||||||
element.className = 'invalid-feedback d-block';
|
element.className = "invalid-feedback d-block";
|
||||||
element.textContent = message;
|
element.textContent = message;
|
||||||
}
|
}
|
||||||
|
|
||||||
function showWarning(element, message) {
|
function showWarning(element, message) {
|
||||||
if (!element) return;
|
if (!element) return;
|
||||||
element.className = 'text-warning d-block';
|
element.className = "text-warning d-block";
|
||||||
element.textContent = message;
|
element.textContent = message;
|
||||||
}
|
}
|
||||||
|
|
||||||
function showSuccess(element, message) {
|
function showSuccess(element, message) {
|
||||||
if (!element) return;
|
if (!element) return;
|
||||||
element.className = 'valid-feedback d-block';
|
element.className = "valid-feedback d-block";
|
||||||
element.textContent = message;
|
element.textContent = message;
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearFeedback(element) {
|
function clearFeedback(element) {
|
||||||
if (!element) return;
|
if (!element) return;
|
||||||
element.className = '';
|
element.className = "";
|
||||||
element.textContent = '';
|
element.textContent = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up event listeners when the document is loaded
|
// Set up event listeners when the document is loaded
|
||||||
document.addEventListener('DOMContentLoaded', function () {
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
const nameField = document.getElementById('app-name');
|
const nameField = document.getElementById("app-name");
|
||||||
const serverField = document.getElementById('server-id');
|
const serverField = document.getElementById("server-id");
|
||||||
|
|
||||||
if (nameField) {
|
if (nameField) {
|
||||||
nameField.addEventListener('input', validateAppName);
|
nameField.addEventListener("input", validateAppName);
|
||||||
|
|
||||||
if (serverField) {
|
if (serverField) {
|
||||||
serverField.addEventListener('change', validateAppName);
|
serverField.addEventListener("change", validateAppName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,9 +182,9 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||||
setupPortValidation();
|
setupPortValidation();
|
||||||
|
|
||||||
// Make sure new port rows get validation too
|
// Make sure new port rows get validation too
|
||||||
const addPortButton = document.getElementById('add-port-btn');
|
const addPortButton = document.getElementById("add-port-btn");
|
||||||
if (addPortButton) {
|
if (addPortButton) {
|
||||||
addPortButton.addEventListener('click', function () {
|
addPortButton.addEventListener("click", function () {
|
||||||
// Wait a moment for the new row to be added
|
// Wait a moment for the new row to be added
|
||||||
setTimeout(setupPortValidation, 100);
|
setTimeout(setupPortValidation, 100);
|
||||||
});
|
});
|
||||||
|
@ -175,30 +193,36 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
|
||||||
function setupPortValidation() {
|
function setupPortValidation() {
|
||||||
const portFields = document.querySelectorAll('input[name="port_numbers[]"]');
|
const portFields = document.querySelectorAll('input[name="port_numbers[]"]');
|
||||||
const protocolFields = document.querySelectorAll('select[name="protocols[]"]');
|
const protocolFields = document.querySelectorAll(
|
||||||
|
'select[name="protocols[]"]',
|
||||||
|
);
|
||||||
|
|
||||||
portFields.forEach((field, index) => {
|
portFields.forEach((field, index) => {
|
||||||
if (!field.hasValidationSetup) {
|
if (!field.hasValidationSetup) {
|
||||||
const protocolField = protocolFields[index];
|
const protocolField = protocolFields[index];
|
||||||
|
|
||||||
field.addEventListener('input', function () {
|
field.addEventListener("input", function () {
|
||||||
validatePort(field, protocolField);
|
validatePort(field, protocolField);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (protocolField) {
|
if (protocolField) {
|
||||||
protocolField.addEventListener('change', function () {
|
protocolField.addEventListener("change", function () {
|
||||||
validatePort(field, protocolField);
|
validatePort(field, protocolField);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a div for feedback if it doesn't exist
|
// Add a div for feedback if it doesn't exist
|
||||||
if (!field.nextElementSibling || !field.nextElementSibling.classList.contains('feedback')) {
|
if (
|
||||||
const feedback = document.createElement('div');
|
!field.nextElementSibling ||
|
||||||
feedback.className = 'feedback';
|
!field.nextElementSibling.classList.contains("feedback")
|
||||||
|
) {
|
||||||
|
const feedback = document.createElement("div");
|
||||||
|
feedback.className = "feedback";
|
||||||
field.parentNode.insertBefore(feedback, field.nextSibling);
|
field.parentNode.insertBefore(feedback, field.nextSibling);
|
||||||
}
|
}
|
||||||
|
|
||||||
field.hasValidationSetup = true;
|
field.hasValidationSetup = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue