hover box, network page improvements, Last Seen changed logic ⚠
Some checks are pending
Code checks / check-url-paths (push) Waiting to run
docker / docker_dev (push) Waiting to run
Deploy MkDocs / deploy (push) Waiting to run

This commit is contained in:
jokob-sk
2025-07-15 08:34:47 +10:00
parent c80e6d3474
commit e0dcc191c7
4 changed files with 62 additions and 12 deletions

View File

@@ -1716,11 +1716,34 @@ input[readonly] {
width: auto; width: auto;
} }
#hover-box #hover-box
{ {
background-color: #ffffff;; background-color: #ffffff;;
} }
#hover-box .iconPreview
{
padding: 0px;
display: flex;
}
#hover-box .devName
{
font-size: larger;
display: contents;
}
#hover-box b
{
float: left;
}
#hover-box span
{
float: right;
}
#networkTree .netCollapse #networkTree .netCollapse
{ {
position: absolute; position: absolute;

View File

@@ -418,9 +418,14 @@ function goToNetworkNode(mac)
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Go to the device // Go to the device
function goToDevice(mac) function goToDevice(mac, newtab = false) {
{ const url = './deviceDetails.php?mac=' + encodeURIComponent(mac);
window.location.href = './deviceDetails.php?mac=' + mac;
if (newtab) {
window.open(url, '_blank');
} else {
window.location.href = url;
}
} }
@@ -828,6 +833,7 @@ function initHoverNodeInfo() {
}); });
} }
// check if handlers already attached to prevent flickering
if (initHoverNodeInfo._handlersAttached) return; if (initHoverNodeInfo._handlersAttached) return;
initHoverNodeInfo._handlersAttached = true; initHoverNodeInfo._handlersAttached = true;
@@ -838,22 +844,30 @@ function initHoverNodeInfo() {
const $el = $(this); const $el = $(this);
lastTarget = this; lastTarget = this;
// use timeout to prevent a quick hover and exit toi flash a card when navigating to a target node with your mouse
clearTimeout(hoverTimeout); clearTimeout(hoverTimeout);
hoverTimeout = setTimeout(() => { hoverTimeout = setTimeout(() => {
if (lastTarget !== this) return; if (lastTarget !== this) return;
const icon = $el.data('icon');
const name = $el.data('name') || 'Unknown'; const name = $el.data('name') || 'Unknown';
const ip = $el.data('ip') || 'N/A'; const ip = $el.data('ip') || 'N/A';
const mac = $el.data('mac') || 'N/A'; const mac = $el.data('mac') || 'N/A';
const vendor = $el.data('vendor') || 'Unknown'; const vendor = $el.data('vendor') || 'Unknown';
const lastseen = $el.data('lastseen') || 'Unknown';
const relationship = $el.data('relationship') || 'Unknown'; const relationship = $el.data('relationship') || 'Unknown';
const badge = getStatusBadgeParts( $el.data('present'), $el.data('alert'), $el.data('mac'))
const status =`<span class="badge ${badge.cssClass}">${badge.iconHtml} ${badge.status}</span>`
const html = ` const html = `
<strong>${name}</strong><br> <b> <div class="iconPreview">${atob(icon)}</div> </b><b class="devName"> ${name}</b><br>
<b>IP:</b> ${ip}<br> <hr/>
<b>MAC:</b> ${mac}<br> <b>Status:</b> <span>${status}</span><br>
<b>Vendor:</b> ${vendor}<br> <b>IP:</b> <span>${ip}</span><br>
<b>MAC:</b> <span>${mac}</span><br>
<b>Vendor:</b> <span>${vendor}</span><br>
<b>Last seen:</b> <span>${lastseen}</span><br>
<b>Relationship:</b> <span class="${getRelationshipConf(relationship).cssClass}">${relationship}</span> <b>Relationship:</b> <span class="${getRelationshipConf(relationship).cssClass}">${relationship}</span>
`; `;

View File

@@ -583,8 +583,11 @@ function getChildren(node, list, path, visited = [])
icon: node.devIcon, icon: node.devIcon,
type: node.devType, type: node.devType,
vendor: node.devVendor, vendor: node.devVendor,
lastseen: node.devLastConnection,
ip: node.devLastIP, ip: node.devLastIP,
status: node.devStatus, status: node.devStatus,
presentLastScan: node.devPresentLastScan,
alertDown: node.devAlertDown,
hasChildren: children.length > 0 || hiddenMacs.includes(node.devMac), hasChildren: children.length > 0 || hiddenMacs.includes(node.devMac),
relType: node.devParentRelType, relType: node.devParentRelType,
hiddenChildren: hiddenMacs.includes(node.devMac), hiddenChildren: hiddenMacs.includes(node.devMac),
@@ -642,6 +645,7 @@ function handleNodeClick(el)
{ {
const targetTabMAC = $(el).attr("data-mytreemacmain"); const targetTabMAC = $(el).attr("data-mytreemacmain");
// handle network node
var targetTab = $(`a[data-mytabmac="${targetTabMAC}"]`); var targetTab = $(`a[data-mytabmac="${targetTabMAC}"]`);
if (targetTab.length) { if (targetTab.length) {
@@ -652,6 +656,10 @@ function handleNodeClick(el)
$('html, body').animate({ $('html, body').animate({
scrollTop: targetTab.offset().top - 50 scrollTop: targetTab.offset().top - 50
}, 500); // Adjust the duration as needed }, 500); // Adjust the duration as needed
} else
{
// handle regular device - open in new tab
goToDevice($(el).data("mac"), true)
} }
} }
@@ -684,7 +692,7 @@ function initTree(myHierarchy)
emSize = pxToEm((treeAreaHeight/(leafNodesCount)).toFixed(2)); emSize = pxToEm((treeAreaHeight/(leafNodesCount)).toFixed(2));
let screenWidthEm = pxToEm($('.networkTable').width()); let screenWidthEm = pxToEm($('.networkTable').width()-15);
// init the drawing area size // init the drawing area size
$("#networkTree").attr('style', `height:${treeAreaHeight}px; width:${emToPx(screenWidthEm)}px`) $("#networkTree").attr('style', `height:${treeAreaHeight}px; width:${emToPx(screenWidthEm)}px`)
@@ -751,7 +759,7 @@ function initTree(myHierarchy)
statusCss = ` netStatus-${nodeData.data.status}`; statusCss = ` netStatus-${nodeData.data.status}`;
return result = `<div return result = `<div
class="node-inner hover-node-info box ${nodeData.data.hasChildren ? "pointer":""} ${statusCss} ${highlightedCss}" class="node-inner hover-node-info box pointer ${statusCss} ${highlightedCss}"
data-mytreemacmain="${nodeData.data.mac}" data-mytreemacmain="${nodeData.data.mac}"
style="height:${nodeHeightPx}px;font-size:${nodeHeightPx-5}px;" style="height:${nodeHeightPx}px;font-size:${nodeHeightPx-5}px;"
onclick="handleNodeClick(this)" onclick="handleNodeClick(this)"
@@ -759,7 +767,12 @@ function initTree(myHierarchy)
data-ip="${nodeData.data.ip}" data-ip="${nodeData.data.ip}"
data-mac="${nodeData.data.mac}" data-mac="${nodeData.data.mac}"
data-vendor="${nodeData.data.vendor}" data-vendor="${nodeData.data.vendor}"
data-lastseen="${nodeData.data.lastseen}"
data-relationship="${nodeData.data.relType}" data-relationship="${nodeData.data.relType}"
data-status="${nodeData.data.status}"
data-present="${nodeData.data.presentLastScan}"
data-alert="${nodeData.data.alertDown}"
data-icon="${nodeData.data.icon}"
> >
<div class="netNodeText"> <div class="netNodeText">
<strong>${devicePort} ${deviceIcon} <strong>${devicePort} ${deviceIcon}
@@ -777,7 +790,8 @@ function initTree(myHierarchy)
isHorizontal : true, isHorizontal : true,
hasZoom: true, hasZoom: true,
hasPan: true, hasPan: true,
marginLeft: '15', marginLeft: '10',
marginRight: '10',
idKey: "mac", idKey: "mac",
hasFlatData: false, hasFlatData: false,
relationnalField: "children", relationnalField: "children",

View File

@@ -56,8 +56,7 @@ def update_devices_data_from_scan (db):
mylog('debug', '[Update Devices] 1 Last Connection') mylog('debug', '[Update Devices] 1 Last Connection')
sql.execute(f"""UPDATE Devices SET devLastConnection = '{startTime}', sql.execute(f"""UPDATE Devices SET devLastConnection = '{startTime}',
devPresentLastScan = 1 devPresentLastScan = 1
WHERE devPresentLastScan = 0 WHERE EXISTS (SELECT 1 FROM CurrentScan
AND EXISTS (SELECT 1 FROM CurrentScan
WHERE devMac = cur_MAC) """) WHERE devMac = cur_MAC) """)
# Clean no active devices # Clean no active devices