let agentData = []; let isCyInitialized = false; let cy; function initializeCytoscape() { if (isCyInitialized) return; cy = cytoscape({ container: document.getElementById('cyto-graph'), style: [ { selector: 'node', style: { 'background-color': '#007bff', 'label': 'data(name)', // Ensure the label uses the AgentName 'color': 'white', 'text-outline-width': 2, 'text-outline-color': '#333', 'width': '50px', 'height': '50px' } }, { selector: 'edge', style: { 'width': 3, 'line-color': '#ccc', 'target-arrow-color': '#ccc', 'target-arrow-shape': 'triangle' } } ], layout: { name: 'grid', rows: 2 } }); isCyInitialized = true; // Mark Cytoscape as initialized } // Load the graph after the page has fully loaded document.addEventListener('DOMContentLoaded', function () { console.log('DOMContentLoaded fired.'); initializeCytoscape(); loadGraphData(); }); // Load the graph after HTMX swap document.body.addEventListener('htmx:afterSwap', function (event) { console.log('htmx:afterSwap fired.'); if (event.target.id === 'agentList') { initializeCytoscape(); loadGraphData(); } }); async function updateGraph(agentData) { if (!cy) { console.error('Cytoscape is not initialized yet.'); return; } console.log('Updating graph with agent data:', agentData); // Clear existing nodes and edges cy.elements().remove(); // Add nodes for each agent with the AgentName as the label agentData.forEach(agent => { const id = agent.agentId; const name = agent.agentName; const status = agent.status; if (id && name) { let nodeColor = (status === 'Connected') ? '#28a745' : '#dc3545'; // Green for connected, Red for disconnected cy.add({ group: 'nodes', data: { id: id, name: name, status: status, type: agent.agentType, ip: agent.IPv4Address }, style: { 'background-color': nodeColor, 'label': name, // Display agent's name 'color': 'white', 'text-outline-width': 2, 'text-outline-color': '#333', 'width': '50px', 'height': '50px' } }); } else { console.warn('Skipping agent with missing data:', agent); } }); // Define the target node (`g2` in your case) const targetNode = 'g2'; // Ensure the target node (`g2`) exists, if not, create it if (cy.getElementById(targetNode).length === 0) { cy.add({ group: 'nodes', data: { id: targetNode, name: 'g2', status: 'Target', type: 'Server', ip: 'N/A' }, style: { 'background-color': '#6c757d', // Gray for target node 'label': 'g2', 'color': 'white', 'text-outline-width': 2, 'text-outline-color': '#333', 'width': '50px', 'height': '50px' } }); } // Connect each agent to the target node (`g2`) agentData.forEach(agent => { const id = agent.agentId; if (id) { cy.add({ group: 'edges', data: { source: id, target: targetNode } }); } else { console.warn('Skipping edge for agent with missing agentId:', agent); } }); // Force a layout update cy.layout({ name: 'grid', rows: 2 }).run(); } async function fetchData() { const url = "http://localhost:3333/agents"; try { const response = await fetch(url, {headers: {Accept: 'application/json'}}); if (!response.ok) { throw new Error(`Response status: ${response.status}`); } const data = await response.json(); return data; // Return the fetched data } catch (error) { console.error(error.message); return []; // Return an empty array on error } } // Function to get agent data and update the graph async function loadGraphData() { console.log("Function loadGraphData()"); // Fetch agent data asynchronously agentData = await fetchData(); // Check if the data is valid console.log('Extracted agent data:', agentData); // Only update the graph if agent data is available if (agentData && agentData.length > 0) { await updateGraph(agentData); } else { console.log('No agent data found or extracted.'); } }