Update static/js/pages/visual-route.js

This commit is contained in:
Blackwhitebear8 2025-07-06 16:22:38 +02:00
parent 418dba4bb6
commit a23bb7f94c

View file

@ -1,107 +1,143 @@
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
let network = null;
let allNodes = new vis.DataSet();
let allEdges = new vis.DataSet();
const form = document.getElementById('bgprtv-form'); const form = document.getElementById('bgprtv-form');
if (!form) { if (!form) return;
return;
}
const ipAddressInput = document.getElementById('bgprtv-ip-address'); const ipAddressInput = document.getElementById('bgprtv-ip-address');
const loader = document.getElementById('bgprtv-loader'); const loader = document.getElementById('bgprtv-loader');
const errorMessageContainer = document.getElementById('bgprtv-error-message'); const errorMessageContainer = document.getElementById('bgprtv-error-message');
const networkContainer = document.getElementById('bgprtv-mynetwork'); const networkContainer = document.getElementById('bgprtv-mynetwork');
const graphUrl = networkContainer.dataset.graphUrl; const graphUrl = networkContainer.dataset.graphUrl;
const filterControls = document.querySelectorAll('input[name="bgprtv-filter"]');
const allCommunitiesCheckbox = document.querySelector('input[value="all"]');
const activeCheckbox = document.querySelector('input[value="active"]');
if (!graphUrl) { if (!graphUrl) {
errorMessageContainer.textContent = 'Configuration Error: The graph URL is missing. Ensure the network container div in your HTML has a "data-graph-url" attribute pointing to the correct API endpoint.'; errorMessageContainer.textContent = 'Configuration Error: The graph URL is missing.';
errorMessageContainer.style.display = 'block'; errorMessageContainer.style.display = 'block';
const submitButton = form.querySelector('input[type="submit"]'); form.querySelector('input[type="submit"]').disabled = true;
if (submitButton) {
submitButton.disabled = true;
}
return; return;
} }
form.addEventListener('submit', function(event) { form.addEventListener('submit', function(event) {
event.preventDefault(); event.preventDefault();
const ipAddress = ipAddressInput.value; const ipAddress = ipAddressInput.value;
loader.style.display = 'block'; loader.style.display = 'block';
errorMessageContainer.style.display = 'none'; errorMessageContainer.style.display = 'none';
errorMessageContainer.textContent = ''; errorMessageContainer.textContent = '';
if (network) {
const visContent = networkContainer.querySelector('.vis-network'); network.destroy();
if (visContent) { network = null;
visContent.remove();
} }
fetch(graphUrl, { fetch(graphUrl, {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ ip_address: ipAddress }) body: JSON.stringify({ ip_address: ipAddress })
}) })
.then(response => { .then(response => {
return response.json().then(data => { if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
if (!response.ok && data.error) { return response.json();
throw new Error(data.error);
}
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return data;
});
}) })
.then(data => { .then(data => {
loader.style.display = 'none'; loader.style.display = 'none';
if (data.nodes && data.nodes.length > 0) { if (data.error) {
errorMessageContainer.textContent = data.error;
errorMessageContainer.style.display = 'block';
} else if (data.nodes && data.nodes.length > 0) {
drawGraph(data); drawGraph(data);
} else { } else {
errorMessageContainer.textContent = data.error || 'Could not parse any valid AS paths from the API response.'; errorMessageContainer.textContent = 'Could not parse any valid AS paths from the API response.';
errorMessageContainer.style.display = 'block'; errorMessageContainer.style.display = 'block';
} }
}) })
.catch(error => { .catch(error => {
loader.style.display = 'none'; loader.style.display = 'none';
errorMessageContainer.textContent = error.message; errorMessageContainer.textContent = `An unexpected error occurred: ${error.message}`;
errorMessageContainer.style.display = 'block'; errorMessageContainer.style.display = 'block';
console.error('Error:', error); console.error('Error:', error);
}); });
}); });
function drawGraph(data) { function drawGraph(data) {
const nodes = new vis.DataSet(data.nodes); allNodes = new vis.DataSet(data.nodes);
const edges = new vis.DataSet(data.edges); allEdges = new vis.DataSet(data.edges);
const graphData = { nodes: nodes, edges: edges };
const options = {
const options = { layout: { hierarchical: false },
layout: { hierarchical: false }, edges: {
edges: { arrows: { to: { enabled: true, scaleFactor: 0.7 } }
arrows: { to: { enabled: true, scaleFactor: 0.7 } }, },
smooth: { nodes: {
enabled: true, shape: 'box',
type: "cubicBezier", margin: 15,
forceDirection: "horizontal", font: { size: 14, color: '#343a40', multi: 'html', align: 'left' },
roundness: 0.85 borderWidth: 2
} },
}, physics: { enabled: false },
nodes: { interaction: { dragNodes: true, dragView: true, zoomView: true }
shape: 'box', };
margin: 15,
font: { network = new vis.Network(networkContainer, {}, options);
size: 14,
color: '#343a40', activeCheckbox.checked = false;
multi: 'html', allCommunitiesCheckbox.checked = true;
align: 'left' filterControls.forEach(cb => { if (cb.value !== 'all' && cb.value !== 'active') cb.checked = false; });
}, filterGraph();
borderWidth: 2 }
},
physics: { enabled: false }, function filterGraph() {
interaction: { if (!network) return;
dragNodes: true,
dragView: true, const showOnlyActive = activeCheckbox.checked;
zoomView: true const selectedCategories = Array.from(filterControls)
} .filter(cb => cb.checked && cb.value !== 'active' && cb.value !== 'all')
.map(cb => cb.value);
const showAllCommunities = allCommunitiesCheckbox.checked;
const itemFilter = (item) => {
const activeFilterPassed = !showOnlyActive || item.is_active;
const categoryFilterPassed = showAllCommunities || selectedCategories.includes(item.path_category);
return item.path_category === 'global' || (activeFilterPassed && categoryFilterPassed);
}; };
new vis.Network(networkContainer, graphData, options);
const edgeFilter = (item) => {
const activeFilterPassed = !showOnlyActive || item.is_active;
const categoryFilterPassed = showAllCommunities || selectedCategories.includes(item.path_category);
return activeFilterPassed && categoryFilterPassed;
};
const filteredNodes = allNodes.get({ filter: itemFilter });
const filteredEdges = allEdges.get({ filter: edgeFilter });
network.setData({ nodes: new vis.DataSet(filteredNodes), edges: new vis.DataSet(filteredEdges) });
} }
filterControls.forEach(checkbox => {
checkbox.addEventListener('change', function(e) {
const changedValue = e.target.value;
if (changedValue === 'all' && e.target.checked) {
filterControls.forEach(cb => {
if (cb.value !== 'all' && cb.value !== 'active') {
cb.checked = false;
}
});
} else if (changedValue !== 'all' && changedValue !== 'active' && e.target.checked) {
allCommunitiesCheckbox.checked = false;
}
const specificCommunityChecked = Array.from(filterControls).some(cb => cb.checked && cb.value !== 'all' && cb.value !== 'active');
if (!specificCommunityChecked) {
allCommunitiesCheckbox.checked = true;
}
filterGraph();
});
});
}); });