changed layout
This commit is contained in:
parent
4fdcd049a7
commit
083567bcfc
6
.env
6
.env
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
export DB_HOST="127.0.0.1"
|
export DB_HOST="172.17.0.2"
|
||||||
export DB_PORT=3306
|
export DB_PORT=3306
|
||||||
export DB_USERNAME="mysql"
|
export DB_USERNAME="root"
|
||||||
export DB_PASSWORD="mysql"
|
export DB_PASSWORD="root"
|
||||||
export DB_NAME="gomatic"
|
export DB_NAME="gomatic"
|
||||||
|
|
|
@ -20,20 +20,65 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||||
restoreCheckboxState();
|
restoreCheckboxState();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// function prepareAgentNames(event) {
|
||||||
|
// // Determine which form was submitted
|
||||||
|
// const form = event.target;
|
||||||
|
|
||||||
|
// // Collect selected agent names
|
||||||
|
// const selected = Array.from(document.querySelectorAll('.agent-checkbox'))
|
||||||
|
// .filter(cb => cb.checked)
|
||||||
|
// .map(cb => cb.dataset.agentName);
|
||||||
|
|
||||||
|
// // Get the hidden input and select within the submitted form
|
||||||
|
// const hiddenInput = form.querySelector('[name="agentNames"]');
|
||||||
|
// const agentSelect = form.querySelector('select[name="agentName"], select#agentName, select#modalAgentName');
|
||||||
|
|
||||||
|
// if (selected.length > 0) {
|
||||||
|
// // Remove the name from the <select> so only agentNames is submitted
|
||||||
|
// if (agentSelect) {
|
||||||
|
// agentSelect.removeAttribute('name');
|
||||||
|
// }
|
||||||
|
// hiddenInput.value = selected.join(',');
|
||||||
|
// } else {
|
||||||
|
// // Re-enable <select> if no checkboxes selected
|
||||||
|
// if (agentSelect) {
|
||||||
|
// agentSelect.setAttribute('name', 'agentName');
|
||||||
|
// }
|
||||||
|
// hiddenInput.value = '';
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
let cachedAgentNames = '';
|
||||||
|
|
||||||
function prepareAgentNames(event) {
|
function prepareAgentNames(event) {
|
||||||
|
const form = event.target;
|
||||||
|
|
||||||
|
// Only set agentNames if this is the navbar form
|
||||||
|
const isNavbarForm = form.id === 'agentCommands';
|
||||||
|
|
||||||
|
// If this is the first submission (navbar), calculate agentNames
|
||||||
|
if (isNavbarForm) {
|
||||||
const selected = Array.from(document.querySelectorAll('.agent-checkbox'))
|
const selected = Array.from(document.querySelectorAll('.agent-checkbox'))
|
||||||
.filter(cb => cb.checked)
|
.filter(cb => cb.checked)
|
||||||
.map(cb => cb.dataset.agentName);
|
.map(cb => cb.dataset.agentName);
|
||||||
|
|
||||||
const hiddenInput = document.getElementById('agentNamesInput');
|
cachedAgentNames = selected.join(',');
|
||||||
|
|
||||||
|
const hiddenInput = form.querySelector('[name="agentNames"]');
|
||||||
|
const agentSelect = form.querySelector('select');
|
||||||
|
|
||||||
if (selected.length > 0) {
|
if (selected.length > 0) {
|
||||||
document.getElementById('agentName').removeAttribute('name');
|
if (agentSelect) agentSelect.removeAttribute('name');
|
||||||
hiddenInput.value = selected.join(',');
|
hiddenInput.value = cachedAgentNames;
|
||||||
} else {
|
} else {
|
||||||
document.getElementById('agentName').setAttribute('name', 'agentName');
|
if (agentSelect) agentSelect.setAttribute('name', 'agentName');
|
||||||
hiddenInput.value = '';
|
hiddenInput.value = '';
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// Use cached value for modal form
|
||||||
|
const hiddenInput = form.querySelector('[name="agentNames"]');
|
||||||
|
hiddenInput.value = cachedAgentNames;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleAllCheckboxes() {
|
function toggleAllCheckboxes() {
|
||||||
|
|
|
@ -18,8 +18,7 @@
|
||||||
/* background-color: #f8f9fa; /1* optional: subtle background for log readability *1/ */
|
/* background-color: #f8f9fa; /1* optional: subtle background for log readability *1/ */
|
||||||
}
|
}
|
||||||
|
|
||||||
.log-info, .log-warning, .log-error, .log-fatal, .log-debug{
|
.log-info, .log-warning, .log-error, .log-fatal, .log-debug{ font-family: "Lucida Console", Monaco, monospace;
|
||||||
font-family: "Lucida Console", Monaco, monospace;
|
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +39,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.execute-navbar {
|
.execute-navbar {
|
||||||
background-color: var(--bs-warning)
|
background-color: var(--bs-info-bg-subtle);
|
||||||
}
|
}
|
||||||
|
|
||||||
#graph-container {
|
#graph-container {
|
||||||
|
@ -50,3 +49,21 @@
|
||||||
tr.selected-row {
|
tr.selected-row {
|
||||||
background-color: var(--bs-table-hover-bg) !important;
|
background-color: var(--bs-table-hover-bg) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
html, body {
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* body > .container-fluid { */
|
||||||
|
/* flex: 1 0 auto; */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
table-layout: auto;
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
|
|
@ -15,120 +15,58 @@
|
||||||
<title>g2: gommand & gontrol</title>
|
<title>g2: gommand & gontrol</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="container-fluid px-4 py-3">
|
<div class="container-fluid px-4 py-3 pb-5">
|
||||||
|
<div class="row g-4">
|
||||||
<!-- Top Row: Graph + Logs (equal height) -->
|
|
||||||
<div class="row mb-3">
|
|
||||||
<!-- Graph -->
|
|
||||||
<div class="col-md-6 d-flex flex-column">
|
|
||||||
<h3>Agents</h3>
|
|
||||||
<div class="flex-grow-1 border" id="cyto-graph" style="height: 100%; min-height: 320px;"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Logs -->
|
|
||||||
<div class="col-md-6 d-flex flex-column">
|
|
||||||
<!-- <h3>Logs</h3> -->
|
|
||||||
<form id="log-filter-form"
|
|
||||||
hx-get="/logs"
|
|
||||||
hx-target="#logs-container"
|
|
||||||
hx-swap="innerHTML"
|
|
||||||
hx-trigger="change from:.log-filter, load, every 5s"
|
|
||||||
hx-include="#log-filter-form">
|
|
||||||
<div class="btn-group mb-2" role="group" aria-label="Log filter">
|
|
||||||
<input type="checkbox" class="btn-check log-filter" id="info" name="level" value="info" checked>
|
|
||||||
<label class="btn btn-outline-primary" for="info">Info</label>
|
|
||||||
|
|
||||||
<input type="checkbox" class="btn-check log-filter" id="warning" name="level" value="warning">
|
|
||||||
<label class="btn btn-outline-primary" for="warning">Warning</label>
|
|
||||||
|
|
||||||
<input type="checkbox" class="btn-check log-filter" id="error" name="level" value="error">
|
|
||||||
<label class="btn btn-outline-primary" for="error">Error</label>
|
|
||||||
|
|
||||||
<input type="checkbox" class="btn-check log-filter" id="fatal" name="level" value="fatal">
|
|
||||||
<label class="btn btn-outline-primary" for="fatal">Fatal</label>
|
|
||||||
|
|
||||||
<input type="checkbox" class="btn-check log-filter" id="debug" name="level" value="debug">
|
|
||||||
<label class="btn btn-outline-primary" for="debug">Debug</label>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="logs-container" class="flex-grow-1 border" style="overflow-y: auto; min-height: 320px;">
|
|
||||||
<!-- Logs will load here -->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Bottom Row: Agent List + Command Execution -->
|
|
||||||
<div class="row">
|
|
||||||
<!-- Agent List -->
|
<!-- Agent List -->
|
||||||
<div class="col-md-6">
|
<div class="col-12 col-md-6">
|
||||||
|
<!-- <h3>Agents</h3> -->
|
||||||
|
<div class="table-responsive">
|
||||||
<div id="agentList"
|
<div id="agentList"
|
||||||
hx-get="/agents"
|
hx-get="/agents"
|
||||||
hx-trigger="load, every 2s"
|
hx-trigger="load, every 2s"
|
||||||
hx-swap="innerHTML">
|
hx-swap="innerHTML">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Command Execution -->
|
|
||||||
<div class="col-md-6">
|
|
||||||
<!-- <div id="agentCommands"> -->
|
|
||||||
<!-- <!-1- <h5>Command Execution</h5> -1-> -->
|
|
||||||
<!-- <form hx-post="http://localhost:5555/executeCommand" -->
|
|
||||||
<!-- hx-target="#commandOutput" -->
|
|
||||||
<!-- hx-encoding="application/x-www-form-urlencoded" -->
|
|
||||||
<!-- hx-swap="innerHTML" -->
|
|
||||||
<!-- onsubmit="prepareAgentNames(event)"> -->
|
|
||||||
<!-- <!-1- <div style="visibility: collapse" class="mb-3"> -1-> -->
|
|
||||||
<!-- <div class="mb-3"> -->
|
|
||||||
<!-- <label for="agentName" class="form-label">Agent Name</label> -->
|
|
||||||
<!-- <select id="agentName" class="form-select" name="agentName" -->
|
|
||||||
<!-- hx-on="htmx:afterSwap:updateAgentDropdown"> -->
|
|
||||||
<!-- <option value="" disabled selected>Select an Agent</option> -->
|
|
||||||
<!-- </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> -->
|
|
||||||
<!-- <input type="hidden" name="agentNames" id="agentNamesInput"> -->
|
|
||||||
<!-- </form> -->
|
|
||||||
<pre id="commandOutput"></pre>
|
|
||||||
<!-- </div> -->
|
|
||||||
<!-- </div> -->
|
|
||||||
</div>
|
</div>
|
||||||
<!-- <div id="agentConnect">Future Agent Tabs</div> -->
|
|
||||||
|
|
||||||
<nav class="navbar fixed-bottom bg-body-tertiary">
|
<!-- Right Column: Logs and Graph -->
|
||||||
<div class="container-fluid navbar execute-navbar">
|
<div class="col-12 col-md-6 d-flex flex-column">
|
||||||
<form id="agentCommands"
|
<!-- Logs -->
|
||||||
hx-post="http://localhost:5555/executeCommand"
|
<div class="mb-3">
|
||||||
hx-target="#commandOutput"
|
<!-- <h3>Logs</h3> -->
|
||||||
hx-encoding="application/x-www-form-urlencoded"
|
<form id="log-filter-form"
|
||||||
|
hx-get="/logs"
|
||||||
|
hx-target="#logs-container"
|
||||||
hx-swap="innerHTML"
|
hx-swap="innerHTML"
|
||||||
onsubmit="prepareAgentNames(event)"
|
hx-trigger="change from:.log-filter, load, every 5s"
|
||||||
class="d-flex w-100">
|
hx-include="#log-filter-form"
|
||||||
|
class="mb-2">
|
||||||
<!-- Submit button on the left -->
|
<div class="btn-group flex-wrap" role="group" aria-label="Log filter">
|
||||||
<button type="submit" class="btn btn-primary me-2">Execute</button>
|
<input type="checkbox" class="btn-check log-filter" id="info" name="level" value="info" checked>
|
||||||
|
<label class="btn btn-outline-primary" for="info">Info</label>
|
||||||
<!-- Command input fills the rest of the space -->
|
<input type="checkbox" class="btn-check log-filter" id="warning" name="level" value="warning">
|
||||||
<input type="text" class="form-control" id="command" name="command" placeholder="Enter command" required>
|
<label class="btn btn-outline-primary" for="warning">Warning</label>
|
||||||
|
<input type="checkbox" class="btn-check log-filter" id="error" name="level" value="error">
|
||||||
<!-- Hidden agentNames input -->
|
<label class="btn btn-outline-primary" for="error">Error</label>
|
||||||
<input type="hidden" name="agentNames" id="agentNamesInput">
|
<input type="checkbox" class="btn-check log-filter" id="fatal" name="level" value="fatal">
|
||||||
|
<label class="btn btn-outline-primary" for="fatal">Fatal</label>
|
||||||
<!-- Fully hidden dropdown (not visible but present in DOM) -->
|
<input type="checkbox" class="btn-check log-filter" id="debug" name="level" value="debug">
|
||||||
<select id="agentName"
|
<label class="btn btn-outline-primary" for="debug">Debug</label>
|
||||||
class="form-select d-none"
|
</div>
|
||||||
name="agentName"
|
</form>
|
||||||
hx-on="htmx:afterSwap:updateAgentDropdown">
|
<div id="logs-container" class="border" style="overflow-y: auto; min-height: 240px; max-height: 320px;">
|
||||||
<option value="" disabled selected>Select an Agent</option>
|
<!-- Logs will load here -->
|
||||||
</select>
|
</div>
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Graph -->
|
||||||
|
<div>
|
||||||
|
<h3>Graph</h3>
|
||||||
|
<div class="border" id="cyto-graph" style="min-height: 320px;"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Offcanvas for Agent Details -->
|
<!-- Offcanvas for Agent Details -->
|
||||||
<div class="offcanvas offcanvas-end" tabindex="-1" id="offcanvasRight" aria-labelledby="offcanvasRightLabel" data-bs-scroll="true">
|
<div class="offcanvas offcanvas-end" tabindex="-1" id="offcanvasRight" aria-labelledby="offcanvasRightLabel" data-bs-scroll="true">
|
||||||
|
@ -140,6 +78,63 @@
|
||||||
...
|
...
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Modal -->
|
||||||
|
<div class="modal fade modal-dialog-scrollable modal-xl" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog modal-dialog-scrollable modal-fullscreen">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h1 class="modal-title" id="exampleModalLabel">Modal title</h1>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<pre id="commandOutput">...</pre>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer d-flex justify-content-between align-items-center">
|
||||||
|
<form id="modalAgentCommands"
|
||||||
|
hx-post="http://localhost:5555/executeCommand"
|
||||||
|
hx-target="#commandOutput"
|
||||||
|
hx-encoding="application/x-www-form-urlencoded"
|
||||||
|
hx-swap="innerHTML"
|
||||||
|
onsubmit="prepareAgentNames(event)"
|
||||||
|
class="d-flex flex-grow-1 me-3">
|
||||||
|
<input type="text" class="form-control me-2" id="modalCommand" name="command" placeholder="Enter command" required>
|
||||||
|
<input type="hidden" name="agentNames" id="modalAgentNamesInput">
|
||||||
|
<select id="modalAgentName"
|
||||||
|
class="form-select d-none"
|
||||||
|
name="agentName"
|
||||||
|
hx-on="htmx:afterSwap:updateAgentDropdown">
|
||||||
|
<option value="" disabled selected>Select an Agent</option>
|
||||||
|
</select>
|
||||||
|
<button type="submit" class="btn btn-primary">Execute</button>
|
||||||
|
</form>
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Sticky Footer Navbar -->
|
||||||
|
<nav class="navbar bg-body-tertiary fixed-bottom">
|
||||||
|
<div class="px-4 container-fluid navbar text-primary-emphasis bg-primary-subtle border-top border-primary-subtle">
|
||||||
|
<form id="agentCommands"
|
||||||
|
hx-post="http://localhost:5555/executeCommand"
|
||||||
|
hx-target="#commandOutput"
|
||||||
|
hx-encoding="application/x-www-form-urlencoded"
|
||||||
|
hx-swap="innerHTML"
|
||||||
|
onsubmit="prepareAgentNames(event)"
|
||||||
|
class="d-flex w-100">
|
||||||
|
<button type="submit" class="btn btn-primary me-2" data-bs-toggle="modal" data-bs-target="#exampleModal">Execute</button>
|
||||||
|
<input type="text" class="form-control" id="command" name="command" placeholder="Enter command" required>
|
||||||
|
<input type="hidden" name="agentNames" id="agentNamesInput">
|
||||||
|
<select id="agentName"
|
||||||
|
class="form-select d-none"
|
||||||
|
name="agentName"
|
||||||
|
hx-on="htmx:afterSwap:updateAgentDropdown">
|
||||||
|
<option value="" disabled selected>Select an Agent</option>
|
||||||
|
</select>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
<!-- <th>Last Contact</th> -->
|
<!-- <th>Last Contact</th> -->
|
||||||
<th>Status</th>
|
<th>Status</th>
|
||||||
<!-- <th>Actions <input type="checkbox" class="select-agent-checkbox" onClick="toggleAllCheckboxes(this)"></th> -->
|
<!-- <th>Actions <input type="checkbox" class="select-agent-checkbox" onClick="toggleAllCheckboxes(this)"></th> -->
|
||||||
<th><button type="button" class="btn btn-primary btn-sm" onClick="toggleAllCheckboxes()">Toggle Agents</button></th>
|
<th><button type="button" class="btn btn-outline-primary btn-sm" onClick="toggleAllCheckboxes()">Toggle Agents</button></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
|
Loading…
Reference in New Issue