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>
|