cleanup and styling
| 
						 | 
				
			
			@ -3,42 +3,74 @@ let isCyInitialized = false;
 | 
			
		|||
let cy;
 | 
			
		||||
 | 
			
		||||
function initializeCytoscape() {
 | 
			
		||||
    if (isCyInitialized) return;
 | 
			
		||||
  if (isCyInitialized) return;
 | 
			
		||||
 | 
			
		||||
    cy = cytoscape({
 | 
			
		||||
        container: document.getElementById('cyto-graph'),
 | 
			
		||||
  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
 | 
			
		||||
    /* --- single, central stylesheet -------------------------------- */
 | 
			
		||||
    style: [
 | 
			
		||||
      /* base node look (shared) */
 | 
			
		||||
      /* background-opacity: 0 will remove the node color and background of the svg */
 | 
			
		||||
      {
 | 
			
		||||
        selector: 'node',
 | 
			
		||||
        style: {
 | 
			
		||||
          'width'              : 50,
 | 
			
		||||
          'height'             : 50,
 | 
			
		||||
          'label'              : 'data(name)',
 | 
			
		||||
          'text-outline-width' : 2,
 | 
			
		||||
          'text-outline-color' : '#333',
 | 
			
		||||
          'color'              : '#fff',
 | 
			
		||||
          'background-opacity' : 1,
 | 
			
		||||
          'background-color': '#f8f9fa'
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
    isCyInitialized = true;  // Mark Cytoscape as initialized
 | 
			
		||||
      /* agent nodes — online / offline variants */
 | 
			
		||||
      {
 | 
			
		||||
        selector: 'node.online[type = "Agent"]',
 | 
			
		||||
        style: {
 | 
			
		||||
          'background-image' : 'url(static/img/computer-online.svg)',
 | 
			
		||||
          'background-fit'   : 'contain'
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        selector: 'node.offline[type = "Agent"]',
 | 
			
		||||
        style: {
 | 
			
		||||
          'background-image' : 'url(static/img/computer-offline.svg)',
 | 
			
		||||
          'background-fit'   : 'contain'
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      /* target / server node */
 | 
			
		||||
      {
 | 
			
		||||
        selector: 'node.server',
 | 
			
		||||
        style: {
 | 
			
		||||
          'background-image' : 'url(static/img/server-online.svg)',
 | 
			
		||||
          'background-fit'   : 'contain'
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      /* edge style */
 | 
			
		||||
      {
 | 
			
		||||
        selector: 'edge',
 | 
			
		||||
        style: {
 | 
			
		||||
          'width'             : 3,
 | 
			
		||||
          'line-color'        : '#ccc',
 | 
			
		||||
          'target-arrow-color': '#ccc',
 | 
			
		||||
          'target-arrow-shape': 'triangle'
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        selector: 'node.darkTheme',
 | 
			
		||||
        style   : { 'background-color': '#212529' }
 | 
			
		||||
      }
 | 
			
		||||
    ],
 | 
			
		||||
 | 
			
		||||
    layout: { name: 'grid', rows: 2 }
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  isCyInitialized = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Load the graph after the page has fully loaded
 | 
			
		||||
| 
						 | 
				
			
			@ -57,108 +89,58 @@ document.addEventListener('DOMContentLoaded', function () {
 | 
			
		|||
// Load the graph after HTMX swap
 | 
			
		||||
 | 
			
		||||
async function updateGraph(agentData) {
 | 
			
		||||
    if (!cy) {
 | 
			
		||||
        console.error('Cytoscape is not initialized yet.');
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
  if (!cy) {
 | 
			
		||||
    console.error('Cytoscape not initialised');
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
    // console.log('Updating graph with agent data:', agentData);
 | 
			
		||||
  cy.elements().remove();                // clear existing
 | 
			
		||||
 | 
			
		||||
    // Clear existing nodes and edges
 | 
			
		||||
    cy.elements().remove();
 | 
			
		||||
  /* --- add agent nodes ------------------------------------------- */
 | 
			
		||||
  agentData.forEach(agent => {
 | 
			
		||||
    const id     = agent.agentId;
 | 
			
		||||
    const name   = agent.agentName;
 | 
			
		||||
    const online = agent.status === 'Connected';
 | 
			
		||||
 | 
			
		||||
    // 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) return;
 | 
			
		||||
 | 
			
		||||
        if (id && name) {
 | 
			
		||||
            // let nodeColor = (status === 'Connected') ? '#28a745' : '#dc3545'; // Green for connected, Red for disconnected
 | 
			
		||||
            let nodeBg = (status === 'Connected') ? 'url(static/computer-online.svg)' : 'url(static/computer-offline.svg)'; // 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': '#f8f9fa',
 | 
			
		||||
                    'background-opacity': '0',
 | 
			
		||||
                    'background-image': nodeBg,
 | 
			
		||||
                    'background-fit': 'contain',
 | 
			
		||||
                    'background-clip': 'none',
 | 
			
		||||
                    '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);
 | 
			
		||||
        }
 | 
			
		||||
    cy.add({
 | 
			
		||||
      group  : 'nodes',
 | 
			
		||||
      data   : {
 | 
			
		||||
        id   : id,
 | 
			
		||||
        name : name,
 | 
			
		||||
        type : 'Agent',
 | 
			
		||||
        ip   : agent.IPv4Address,
 | 
			
		||||
        status: agent.status
 | 
			
		||||
      },
 | 
			
		||||
      classes: online ? 'online' : 'offline'    //  ← only classes
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
    // 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
 | 
			
		||||
                'background-opacity': '0',
 | 
			
		||||
                'background-image': 'url(static/server-online.svg)',
 | 
			
		||||
                'background-fit': 'contain',
 | 
			
		||||
                'background-clip': 'none',
 | 
			
		||||
                '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);
 | 
			
		||||
        }
 | 
			
		||||
  /* --- ensure target/server node exists --------------------------- */
 | 
			
		||||
  const targetId = 'g2';
 | 
			
		||||
  if (cy.getElementById(targetId).length === 0) {
 | 
			
		||||
    cy.add({
 | 
			
		||||
      group  : 'nodes',
 | 
			
		||||
      data   : { id: targetId, name: 'g2' },
 | 
			
		||||
      classes: 'server'
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
    // Force a layout update
 | 
			
		||||
    cy.layout({
 | 
			
		||||
        name: 'grid',
 | 
			
		||||
        rows: 2
 | 
			
		||||
    }).run();
 | 
			
		||||
  /* --- connect every agent to the target ------------------------- */
 | 
			
		||||
  agentData.forEach(agent => {
 | 
			
		||||
    if (agent.agentId) {
 | 
			
		||||
      cy.add({
 | 
			
		||||
        group: 'edges',
 | 
			
		||||
        data : { source: agent.agentId, target: targetId }
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  /* --- relayout --------------------------------------------------- */
 | 
			
		||||
  cy.layout({ name: 'grid', rows: 2 }).run();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async function fetchData() {
 | 
			
		||||
    const url = "http://localhost:3333/agents";
 | 
			
		||||
    try {
 | 
			
		||||
| 
						 | 
				
			
			@ -176,7 +158,7 @@ async function fetchData() {
 | 
			
		|||
 | 
			
		||||
// Function to get agent data and update the graph
 | 
			
		||||
async function loadGraphData() {
 | 
			
		||||
    console.log("Function loadGraphData()");
 | 
			
		||||
    // console.log("Function loadGraphData()");
 | 
			
		||||
 | 
			
		||||
    // Fetch agent data asynchronously
 | 
			
		||||
    agentData = await fetchData();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,7 +11,7 @@ document.addEventListener('DOMContentLoaded', () => {
 | 
			
		|||
    document.body.addEventListener('htmx:afterSwap', function(event) {
 | 
			
		||||
        if (event.target.id === "agentList") {
 | 
			
		||||
            restoreCheckboxState();
 | 
			
		||||
            updateAgentDropdown();
 | 
			
		||||
            updateAgentStatus();
 | 
			
		||||
            bindRowClicks();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -24,6 +24,7 @@ document.addEventListener('DOMContentLoaded', () => {
 | 
			
		|||
    restoreCheckboxState();
 | 
			
		||||
 | 
			
		||||
    themeToggle();
 | 
			
		||||
    focusCommandInput();
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
let cachedAgentNames = '';
 | 
			
		||||
| 
						 | 
				
			
			@ -83,6 +84,7 @@ function restoreCheckboxState() {
 | 
			
		|||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Because of this function, you can click anywhere on the row to select it
 | 
			
		||||
function bindRowClicks() {
 | 
			
		||||
    const rows = document.querySelectorAll('#agentList tbody tr');
 | 
			
		||||
    rows.forEach(row => {
 | 
			
		||||
| 
						 | 
				
			
			@ -101,7 +103,9 @@ function bindRowClicks() {
 | 
			
		|||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function updateAgentDropdown() {
 | 
			
		||||
 | 
			
		||||
// Colorize connection status inside agent list
 | 
			
		||||
function updateAgentStatus() {
 | 
			
		||||
    const select = document.getElementById("agentName");
 | 
			
		||||
    const optionValues = Array.from(select.options).map(opt => opt.value);
 | 
			
		||||
    const rows = document.querySelectorAll("#agentList tbody tr");
 | 
			
		||||
| 
						 | 
				
			
			@ -130,6 +134,12 @@ function updateAgentDropdown() {
 | 
			
		|||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
//
 | 
			
		||||
// Toggle them icon from sun/moon on button click
 | 
			
		||||
//
 | 
			
		||||
////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
function themeToggle() {
 | 
			
		||||
  const body = document.body;
 | 
			
		||||
  const toggleBtn = document.getElementById('themeToggleButton');
 | 
			
		||||
| 
						 | 
				
			
			@ -139,10 +149,10 @@ function themeToggle() {
 | 
			
		|||
    body.classList.remove('bg-light', 'text-dark', 'bg-dark', 'text-light');
 | 
			
		||||
    if (theme === 'dark') {
 | 
			
		||||
      body.classList.add('bg-dark', 'text-light');
 | 
			
		||||
      toggleBtn.innerHTML = '<i class="bi bi-moon"></i>';
 | 
			
		||||
      toggleBtn.innerHTML = '☽'; // Could switch to the colored version 🌙
 | 
			
		||||
    } else {
 | 
			
		||||
      body.classList.add('bg-light', 'text-dark');
 | 
			
		||||
      toggleBtn.innerHTML = '<i class="bi bi-sun"></i>';
 | 
			
		||||
      toggleBtn.innerHTML = '☼'; // Could switch to the colored version ☀
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -171,14 +181,28 @@ function styleCommandOutput() {
 | 
			
		|||
  // Map lines: if contains "Error", wrap in red span, else plain text
 | 
			
		||||
  lines = lines.map(line => {
 | 
			
		||||
    if (line.includes("ERROR")) {
 | 
			
		||||
      return `<span style="color: red;">${line}</span>`;
 | 
			
		||||
      return `<span style="color: var(--bs-danger);">${line}</span>`;
 | 
			
		||||
    } else if (/^\[\S*\]$/.test(line)) {
 | 
			
		||||
      return `<span style="color: blue;">${line}</span>`;
 | 
			
		||||
        return `<span style="color: var(--bs-primary); font-size: 16px">${line}</span>`;
 | 
			
		||||
    } else {
 | 
			
		||||
        return `<span style="font-size: 16px">${line}</span>`;
 | 
			
		||||
        return `<span style="font-size: 16px; line-height: 1em;">${line}</span>`;
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  // Replace innerHTML with the joined lines, joined by <br> for line breaks in HTML
 | 
			
		||||
  commandOutput.innerHTML = lines.join('<br>');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
//
 | 
			
		||||
// Focus on modal command inpu
 | 
			
		||||
//
 | 
			
		||||
////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
function focusCommandInput() {
 | 
			
		||||
    // const modalEl = document.getElementById('exampleModal');
 | 
			
		||||
    var modalElement = document.getElementById('exampleModal')
 | 
			
		||||
    modalElement.addEventListener('shown.bs.modal', event => {
 | 
			
		||||
      document.getElementById('modalCommand').focus();
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,11 +15,12 @@
 | 
			
		|||
    overflow-y: auto;        /* enables vertical scroll when content overflows */
 | 
			
		||||
    border: 1px solid #fff;  /* optional: for visual clarity */
 | 
			
		||||
    padding: 10px;           /* optional: spacing inside the container */
 | 
			
		||||
    line-height: 1em;
 | 
			
		||||
    /* background-color: #f8f9fa; /1* optional: subtle background for log readability *1/ */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.log-info, .log-warning, .log-error, .log-fatal, .log-debug{ font-family: "Lucida Console", Monaco, monospace;
 | 
			
		||||
      font-size: 12px;
 | 
			
		||||
      font-size: 13px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.log-info {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
		 Before Width: | Height: | Size: 655 B After Width: | Height: | Size: 655 B  | 
| 
		 Before Width: | Height: | Size: 652 B After Width: | Height: | Size: 652 B  | 
| 
		 Before Width: | Height: | Size: 674 B After Width: | Height: | Size: 674 B  | 
| 
		 Before Width: | Height: | Size: 673 B After Width: | Height: | Size: 673 B  | 
| 
						 | 
				
			
			@ -4,13 +4,11 @@
 | 
			
		|||
    <meta charset="UTF-8">
 | 
			
		||||
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
 | 
			
		||||
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
 | 
			
		||||
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
 | 
			
		||||
    <link href="static/bootstrap/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
 | 
			
		||||
    <link rel="stylesheet" type="text/css" href="static/gontrol-stylesheet.css">
 | 
			
		||||
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
 | 
			
		||||
    <link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.css" rel="stylesheet">
 | 
			
		||||
    <script src="https://unpkg.com/htmx.org@1.9.12"></script>
 | 
			
		||||
    <!-- Include Cytoscape.js -->
 | 
			
		||||
    <script src="https://cdn.jsdelivr.net/npm/cytoscape@3.23/dist/cytoscape.min.js"></script>
 | 
			
		||||
    <script type="text/javascript" src="static/bootstrap/bootstrap.bundle.min.js"></script>
 | 
			
		||||
    <script type="text/javascript" src="static/htmx/htmx.org@1.9.12.js"></script>
 | 
			
		||||
    <script type="text/javascript" src="static/cytoscape.min.js"></script>
 | 
			
		||||
    <script type="text/javascript" src="static/agents-graph.js"></script>
 | 
			
		||||
    <script type="text/javascript" src="static/gontrol-helper.js"></script>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -24,12 +22,12 @@
 | 
			
		|||
<body class="bg-light text-dark" data-bs-theme="light">
 | 
			
		||||
    <button id="themeToggleButton"
 | 
			
		||||
          class="btn btn-outline-secondary position-fixed"
 | 
			
		||||
          style="top: 1rem; right: 1rem; z-index: 1;"
 | 
			
		||||
          style="top: 1rem; right: 1.5rem; z-index: 1; border-color: var(--bs-tertiary-color);"
 | 
			
		||||
          aria-label="Toggle Theme">
 | 
			
		||||
      <i class="bi bi-sun"></i>
 | 
			
		||||
      ☀
 | 
			
		||||
    </button>
 | 
			
		||||
 | 
			
		||||
  <div class="container-fluid px-4 py-3 pb-5">
 | 
			
		||||
  <div class="container-fluid px-4 py-4 pb-5">
 | 
			
		||||
    <div class="row g-2">
 | 
			
		||||
      <!-- Agent List -->
 | 
			
		||||
      <div class="col-12 col-md-6">
 | 
			
		||||
| 
						 | 
				
			
			@ -121,7 +119,7 @@
 | 
			
		|||
            <select id="modalAgentName"
 | 
			
		||||
                    class="form-select d-none"
 | 
			
		||||
                    name="agentName"
 | 
			
		||||
                    hx-on="htmx:afterSwap:updateAgentDropdown">
 | 
			
		||||
                    hx-on="htmx:afterSwap:updateAgentStatus">
 | 
			
		||||
              <option value="" disabled selected>Select an Agent</option>
 | 
			
		||||
            </select>
 | 
			
		||||
          </form>
 | 
			
		||||
| 
						 | 
				
			
			@ -147,7 +145,7 @@
 | 
			
		|||
        <select id="agentName"
 | 
			
		||||
                class="form-select d-none"
 | 
			
		||||
                name="agentName"
 | 
			
		||||
                hx-on="htmx:afterSwap:updateAgentDropdown">
 | 
			
		||||
                hx-on="htmx:afterSwap:updateAgentStatus">
 | 
			
		||||
          <option value="" disabled selected>Select an Agent</option>
 | 
			
		||||
        </select>
 | 
			
		||||
      </form>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -228,7 +228,8 @@ func (wsh webSocketHandler) ServeHTTP(w http.ResponseWriter, r *http.Request){
 | 
			
		|||
			logger.InsertLog(logger.Error, fmt.Sprintf("Error reading from agent %s: %v", agentName, err))
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
		log.Printf("Message from agent %s: %s", agentName, message)
 | 
			
		||||
		// log.Printf("Message from agent %s: %s", agentName, message)
 | 
			
		||||
		log.Printf("Message from agent %s received", agentName)
 | 
			
		||||
		logger.InsertLog(logger.Debug, fmt.Sprintf("Message from agent %s: %s", agentName, message))
 | 
			
		||||
 | 
			
		||||
		if ch, ok := responseChannels.Load(agentName); ok {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||