190 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			HTML
		
	
	
	
			
		
		
	
	
			190 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			HTML
		
	
	
	
<!DOCTYPE html>
 | 
						|
<html lang="en">
 | 
						|
<head>
 | 
						|
    <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">
 | 
						|
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
 | 
						|
    <script src="https://unpkg.com/htmx.org@1.9.12"></script>
 | 
						|
    <!-- <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script> -->
 | 
						|
    <title>g2: gommand & gontrol</title>
 | 
						|
    <script>
 | 
						|
    const checkboxState = new Map();
 | 
						|
 | 
						|
    document.addEventListener('DOMContentLoaded', () => {
 | 
						|
 | 
						|
        document.body.addEventListener('htmx:beforeSwap', function(event) {
 | 
						|
            if (event.target.id === "agentList") {
 | 
						|
                saveCheckboxState();
 | 
						|
            }
 | 
						|
        });
 | 
						|
 | 
						|
        document.body.addEventListener('htmx:afterSwap', function(event) {
 | 
						|
            if (event.target.id === "agentList") {
 | 
						|
                restoreCheckboxState();
 | 
						|
                updateAgentDropdown();
 | 
						|
            }
 | 
						|
        });
 | 
						|
    });
 | 
						|
 | 
						|
    function prepareAgentNames(event) {
 | 
						|
        const selected = Array.from(document.querySelectorAll('.agent-checkbox'))
 | 
						|
            .filter(cb => cb.checked)
 | 
						|
            .map(cb => cb.dataset.agentName);
 | 
						|
 | 
						|
        const hiddenInput = document.getElementById('agentNamesInput');
 | 
						|
 | 
						|
        if (selected.length > 0) {
 | 
						|
            document.getElementById('agentName').removeAttribute('name');
 | 
						|
            hiddenInput.value = selected.join(',');
 | 
						|
        } else {
 | 
						|
            document.getElementById('agentName').setAttribute('name', 'agentName');
 | 
						|
            hiddenInput.value = '';
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    function saveCheckboxState() {
 | 
						|
        document.querySelectorAll('.agent-checkbox').forEach((checkbox) => {
 | 
						|
            checkboxState.set(checkbox.dataset.agentName, checkbox.checked);
 | 
						|
        });
 | 
						|
    }
 | 
						|
 | 
						|
    function restoreCheckboxState() {
 | 
						|
        document.querySelectorAll('.agent-checkbox').forEach((checkbox) => {
 | 
						|
            const state = checkboxState.get(checkbox.dataset.agentName);
 | 
						|
            if (state !== undefined) {
 | 
						|
                checkbox.checked = state;
 | 
						|
            }
 | 
						|
        });
 | 
						|
    }
 | 
						|
 | 
						|
    function updateAgentDropdown() {
 | 
						|
        const select = document.getElementById("agentName");
 | 
						|
        const optionValues = Array.from(select.options).map(opt => opt.value);
 | 
						|
        const rows = document.querySelectorAll("#agentList tbody tr");
 | 
						|
 | 
						|
        rows.forEach(row => {
 | 
						|
            const status = row.cells[4].textContent.trim();
 | 
						|
            const name = row.cells[1].textContent.trim();
 | 
						|
 | 
						|
            if (status === "Connected") {
 | 
						|
                row.cells[4].innerHTML = '<span class="badge bg-success">Connected</span>';
 | 
						|
                const option = document.createElement("option");
 | 
						|
                if (!(optionValues.includes(name))) {
 | 
						|
                    option.value = name;
 | 
						|
                    option.textContent = name;
 | 
						|
                    select.appendChild(option);
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            if (status === "Disconnected") {
 | 
						|
                row.cells[4].innerHTML = '<span class="badge bg-danger">Disconnected</span>';
 | 
						|
                const option = Array.from(select.options).find(opt => opt.value === name);
 | 
						|
                if(option) {
 | 
						|
                    select.removeChild(option);
 | 
						|
                }
 | 
						|
            }
 | 
						|
        });
 | 
						|
    }
 | 
						|
 | 
						|
    </script>
 | 
						|
    <style>
 | 
						|
        :root{
 | 
						|
          --grey-color: #1B2B34;
 | 
						|
          --error-color: #EC5f67;
 | 
						|
          --warning-color: #F99157;
 | 
						|
          --yellow-color: #FAC863;
 | 
						|
          --info-color: #99C794;
 | 
						|
          --teal-color: #5FB3B3;
 | 
						|
          --blue-color: #6699CC;
 | 
						|
          --debug-color: #C594C5;
 | 
						|
          --fatal-color: #AB7967;
 | 
						|
        }
 | 
						|
 | 
						|
        .log-info, .log-warning, .log-error, .log-fatal, .log-debug{
 | 
						|
              font-family: "Lucida Console", Monaco, monospace;
 | 
						|
        }
 | 
						|
 | 
						|
        .log-info {
 | 
						|
            color: var(--info-color);
 | 
						|
        }
 | 
						|
        .log-warning {
 | 
						|
            color: var(--warning-color);
 | 
						|
        }
 | 
						|
        .log-error {
 | 
						|
            color: var(--error-color);
 | 
						|
        }
 | 
						|
        .log-fatal {
 | 
						|
            color: var(--fatal-color);
 | 
						|
        }
 | 
						|
        .log-debug {
 | 
						|
            color: var(--debug-color);
 | 
						|
        }
 | 
						|
    </style>
 | 
						|
 | 
						|
</head>
 | 
						|
<body>
 | 
						|
    <div class="container">
 | 
						|
        <div class="row">
 | 
						|
            <div class="col">
 | 
						|
                <h2>Agents</h2>
 | 
						|
 | 
						|
                <!-- Agent List -->
 | 
						|
                <div id="agentList" hx-get="/agents" hx-trigger="load, every 2s" hx-swap="innerHTML"></div>
 | 
						|
                <!-- <div id="agentList" hx-get="/agents" hx-trigger="load" hx-swap="innerHTML"></div> -->
 | 
						|
                <!-- Agent Commands -->
 | 
						|
                <div id="agentCommands">
 | 
						|
                    <h3>Command Execution</h3>
 | 
						|
                    <form hx-post="http://localhost:5555/executeCommand" hx-target="#commandOutput" hx-encoding="application/x-www-form-urlencoded"  hx-swap="innerHTML" onsubmit="prepareAgentNames(event)">
 | 
						|
                        <div class="mb-3">
 | 
						|
                            <label for="agentName" class="form-label">Agent Name</label>
 | 
						|
                            <!-- <select class="form-select" id="agentName" name="agentName" required> -->
 | 
						|
                            <select id="agentName" class="form-select" name="agentName" hx-on="htmx:afterSwap:updateAgentDropdown">
 | 
						|
                                <option value="" disabled selected>Select an Agent</option>
 | 
						|
                                <!-- Dynamically populated with agent names -->
 | 
						|
                            </select>
 | 
						|
                        </div>
 | 
						|
                        <div class="mb-3">
 | 
						|
                            <label for="command" class="form-label">Command</label>
 | 
						|
                            <input type="text" class="form-control" id="command" name="command" placeholder="Enter command" required>
 | 
						|
                        </div>
 | 
						|
                        <button type="submit" class="btn btn-primary">Execute</button>
 | 
						|
                    <!-- Hidden checkbox form !-->
 | 
						|
                    <input type="hidden" name="agentNames" id="agentNamesInput">
 | 
						|
                    </form>
 | 
						|
                    <pre id="commandOutput"></pre>
 | 
						|
                </div>
 | 
						|
 | 
						|
        <!-- Agent Details -->
 | 
						|
        <div class="col" id="agentDetails">
 | 
						|
            <h3>Details</h3>
 | 
						|
            <p>Select an agent to view details.</p>
 | 
						|
        </div>
 | 
						|
 | 
						|
        <!-- Logs Section -->
 | 
						|
        <h3>Logs</h3>
 | 
						|
 | 
						|
            <form id="log-filter-form"
 | 
						|
              hx-get="/logs"
 | 
						|
              hx-target="#logs-container"
 | 
						|
              hx-swap="innerHTML"
 | 
						|
              hx-trigger="change from:.log-filter, every 3s"
 | 
						|
              hx-include="#log-filter-form">
 | 
						|
 | 
						|
              <label><input type="checkbox" class="log-filter" name="level" value="info" checked> Info</label>
 | 
						|
              <label><input type="checkbox" class="log-filter" name="level" value="warning"> Warning</label>
 | 
						|
              <label><input type="checkbox" class="log-filter" name="level" value="error"> Error</label>
 | 
						|
              <label><input type="checkbox" class="log-filter" name="level" value="debug"> Debug</label>
 | 
						|
              <label><input type="checkbox" class="log-filter" name="level" value="fatal"> Fatal</label>
 | 
						|
 | 
						|
            </form>
 | 
						|
 | 
						|
            <div id="logs-container">
 | 
						|
                <!-- Logs will load here -->
 | 
						|
            </div>
 | 
						|
        </div>
 | 
						|
    </div>
 | 
						|
</body>
 | 
						|
</html>
 |