sleeping devices status #1519

This commit is contained in:
Jokob @NetAlertX
2026-03-02 04:35:07 +00:00
parent deb0d16c3d
commit 8e6efc3008
22 changed files with 211 additions and 55 deletions

View File

@@ -138,7 +138,7 @@ function getDeviceData() {
},
// Group for event and alert settings
DevDetail_EveandAl_Title: {
data: ["devAlertEvents", "devAlertDown", "devSkipRepeated", "devReqNicsOnline", "devChildrenNicsDynamic", "devForceStatus"],
data: ["devAlertEvents", "devAlertDown", "devCanSleep", "devSkipRepeated", "devReqNicsOnline", "devChildrenNicsDynamic", "devForceStatus"],
docs: "https://docs.netalertx.com/NOTIFICATIONS",
iconClass: "fa fa-bell",
inputGroupClasses: "field-group alert-group col-lg-4 col-sm-6 col-xs-12",
@@ -447,6 +447,7 @@ function setDeviceData(direction = '', refreshCallback = '') {
devAlertEvents: ($('#NEWDEV_devAlertEvents')[0].checked * 1),
devAlertDown: ($('#NEWDEV_devAlertDown')[0].checked * 1),
devCanSleep: ($('#NEWDEV_devCanSleep')[0].checked * 1),
devSkipRepeated: $('#NEWDEV_devSkipRepeated').val().split(' ')[0],
devForceStatus: $('#NEWDEV_devForceStatus').val().replace(/'/g, ""),

View File

@@ -24,6 +24,7 @@ function loadNetworkNodes() {
parent.devIcon AS node_icon,
parent.devAlertDown AS node_alert,
parent.devFlapping AS node_flapping,
parent.devIsSleeping AS node_sleeping,
COUNT(child.devMac) AS node_ports_count
FROM DevicesView AS parent
LEFT JOIN DevicesView AS child
@@ -34,7 +35,7 @@ function loadNetworkNodes() {
WHERE parent.devType IN (${networkDeviceTypes})
AND parent.devIsArchived = 0
GROUP BY parent.devMac, parent.devName, parent.devPresentLastScan,
parent.devType, parent.devParentMAC, parent.devIcon, parent.devAlertDown, parent.devFlapping
parent.devType, parent.devParentMAC, parent.devIcon, parent.devAlertDown, parent.devFlapping, parent.devIsSleeping
ORDER BY parent.devName;
`;
@@ -146,7 +147,8 @@ function loadDeviceTable({ sql, containerSelector, tableId, wrapperHtml = null,
device.devAlertDown,
device.devFlapping,
device.devMac,
device.devStatus
device.devStatus,
device.devIsSleeping || 0
);
return `<a href="${badge.url}" class="badge ${badge.cssClass}">${badge.iconHtml} ${badge.text}</a>`;
}
@@ -204,7 +206,7 @@ function loadDeviceTable({ sql, containerSelector, tableId, wrapperHtml = null,
*/
function loadUnassignedDevices() {
const sql = `
SELECT devMac, devPresentLastScan, devName, devLastIP, devVendor, devAlertDown, devParentPort, devFlapping, devStatus
SELECT devMac, devPresentLastScan, devName, devLastIP, devVendor, devAlertDown, devParentPort, devFlapping, devIsSleeping, devStatus
FROM DevicesView
WHERE (devParentMAC IS NULL OR devParentMAC IN ("", " ", "undefined", "null"))
AND LOWER(devMac) NOT LIKE "%internet%"
@@ -239,10 +241,11 @@ function loadConnectedDevices(node_mac) {
const normalized_mac = node_mac.toLowerCase();
const sql = `
SELECT devName, devMac, devLastIP, devVendor, devPresentLastScan, devAlertDown, devParentPort, devVlan, devFlapping,
SELECT devName, devMac, devLastIP, devVendor, devPresentLastScan, devAlertDown, devParentPort, devVlan, devFlapping, devIsSleeping,
CASE
WHEN devIsNew = 1 THEN 'New'
WHEN devPresentLastScan = 1 THEN 'On-line'
WHEN devIsSleeping = 1 THEN 'Sleeping'
WHEN devPresentLastScan = 0 AND devAlertDown != 0 THEN 'Down'
WHEN devIsArchived = 1 THEN 'Archived'
WHEN devPresentLastScan = 0 THEN 'Off-line'

View File

@@ -24,8 +24,9 @@ function initNetworkTopology() {
LOWER(devMac) AS devMac,
LOWER(devParentMAC) AS devParentMAC,
CASE
WHEN devAlertDown != 0 AND devPresentLastScan = 0 THEN 'Down'
WHEN devPresentLastScan = 1 THEN 'On-line'
WHEN devIsSleeping = 1 THEN 'Sleeping'
WHEN devAlertDown != 0 AND devPresentLastScan = 0 THEN 'Down'
ELSE 'Off-line'
END AS devStatus,
CASE

View File

@@ -9,7 +9,8 @@ function renderNetworkTabs(nodes) {
let html = '';
nodes.forEach((node, i) => {
const iconClass = node.online == 1 ? "text-green" :
(node.node_alert == 1 ? "text-red" : "text-gray50");
(node.node_sleeping == 1 ? "text-aqua" :
(node.node_alert == 1 ? "text-red" : "text-gray50"));
const portLabel = node.node_ports_count ? ` (${node.node_ports_count})` : '';
const icon = atob(node.node_icon);
@@ -55,7 +56,9 @@ function renderNetworkTabContent(nodes) {
node.online,
node.node_alert,
node.node_flapping,
node.node_mac
node.node_mac,
'',
node.node_sleeping || 0
);
const badgeHtml = `<a href="${badge.url}" class="badge ${badge.cssClass}">${badge.iconHtml} ${badge.status}</a>`;

View File

@@ -74,6 +74,7 @@ function getChildren(node, list, path, visited = [])
presentLastScan: node.devPresentLastScan,
flapping: node.devFlapping,
alertDown: node.devAlertDown,
sleeping: node.devIsSleeping || 0,
hasChildren: children.length > 0 || hiddenMacs.includes(node.devMac),
relType: node.devParentRelType,
devVlan: node.devVlan,
@@ -272,7 +273,8 @@ function initTree(myHierarchy)
nodeData.data.alertDown,
nodeData.data.flapping,
nodeData.data.mac,
statusText = ''
'',
nodeData.data.sleeping || 0
);
return result = `<div
@@ -291,6 +293,7 @@ function initTree(myHierarchy)
data-firstseen="${nodeData.data.firstseen}"
data-relationship="${nodeData.data.relType}"
data-flapping="${nodeData.data.flapping}"
data-sleeping="${nodeData.data.sleeping || 0}"
data-status="${nodeData.data.status}"
data-present="${nodeData.data.presentLastScan}"
data-alert="${nodeData.data.alertDown}"

View File

@@ -738,7 +738,7 @@ function getColumnNameFromLangString(headStringKey) {
//--------------------------------------------------------------
// Generating the device status chip
function getStatusBadgeParts(devPresentLastScan, devAlertDown, devFlapping, devMac, statusText = '') {
function getStatusBadgeParts(devPresentLastScan, devAlertDown, devFlapping, devMac, statusText = '', devIsSleeping = 0) {
let css = 'bg-gray text-white statusUnknown';
let icon = '<i class="fa-solid fa-question"></i>';
let status = 'unknown';
@@ -754,6 +754,11 @@ function getStatusBadgeParts(devPresentLastScan, devAlertDown, devFlapping, devM
cssText = 'text-yellow';
icon = '<i class="fa-solid fa-plug-circle-exclamation"></i>';
status = 'online';
} else if (devIsSleeping == 1) {
css = 'bg-aqua text-white statusSleeping';
cssText = 'text-aqua';
icon = '<i class="fa-solid fa-moon"></i>';
status = 'sleeping';
} else if (devAlertDown == 1) {
css = 'bg-red text-white statusDown';
cssText = 'text-red';
@@ -929,7 +934,9 @@ function renderDeviceLink(data, container, useName = false) {
device.devPresentLastScan,
device.devAlertDown,
device.devFlapping,
device.devMac
device.devMac,
'',
device.devIsSleeping || 0
);
// badge class and hover-info class to container
@@ -948,6 +955,7 @@ function renderDeviceLink(data, container, useName = false) {
'data-flapping': device.devFlapping,
'data-present': device.devPresentLastScan,
'data-alert': device.devAlertDown,
'data-sleeping': device.devIsSleeping || 0,
'data-icon': device.devIcon
});
@@ -1017,7 +1025,8 @@ function initHoverNodeInfo() {
const firstseen = $el.data('firstseen') || 'Unknown';
const relationship = $el.data('relationship') || 'Unknown';
const flapping = $el.data('flapping') || 0;
const badge = getStatusBadgeParts( $el.data('present'), $el.data('alert'), flapping, $el.data('mac'))
const sleeping = $el.data('sleeping') || 0;
const badge = getStatusBadgeParts( $el.data('present'), $el.data('alert'), flapping, $el.data('mac'), '', sleeping)
const status =`<span class="badge ${badge.cssClass}">${badge.iconHtml} ${badge.status}</span>`
const html = `

View File

@@ -1191,6 +1191,41 @@
}
]
},
{
"function": "devCanSleep",
"type": {
"dataType": "integer",
"elements": [
{
"elementType": "input",
"elementOptions": [
{
"type": "checkbox"
}
],
"transformers": []
}
]
},
"default_value": 0,
"options": [],
"localized": [
"name",
"description"
],
"name": [
{
"language_code": "en_us",
"string": "Can Sleep"
}
],
"description": [
{
"language_code": "en_us",
"string": "When enabled, the device will appear as <em>Sleeping</em> instead of <em>Down</em> or <em>Off-line</em> while it has been absent for less than the <b>Sleep Window</b> (<code>NTFPRCS_sleep_time</code>). Once the sleep window expires the device becomes subject to the normal <code>Alert Down</code> condition. Database column name: <code>devCanSleep</code>."
}
]
},
{
"function": "devSkipRepeated",
"type": {

View File

@@ -105,6 +105,34 @@
}
]
},
{
"function": "sleep_time",
"type": {
"dataType": "integer",
"elements": [
{
"elementType": "input",
"elementOptions": [{ "type": "number" }],
"transformers": []
}
]
},
"default_value": 30,
"options": [],
"localized": ["name", "description"],
"name": [
{
"language_code": "en_us",
"string": "Sleep Window"
}
],
"description": [
{
"language_code": "en_us",
"string": "How many minutes a device with <code>Can Sleep</code> enabled is shown as <em>Sleeping</em> before it becomes subject to the <code>Alert Down</code> condition. Changes take effect after saving settings."
}
]
},
{
"function": "new_dev_condition",
"type": {

View File

@@ -46,7 +46,7 @@ let fieldOptions = [
"devName", "devMac", "devOwner", "devType", "devVendor", "devVlan", "devFavorite",
"devGroup", "devComments", "devFirstConnection", "devLastConnection",
"devLastIP", "devStaticIP", "devScan", "devLogEvents", "devAlertEvents",
"devAlertDown", "devSkipRepeated", "devLastNotification", "devPresentLastScan",
"devAlertDown", "devCanSleep", "devSkipRepeated", "devLastNotification", "devPresentLastScan",
"devIsNew", "devLocation", "devIsArchived", "devParentMAC", "devParentPort",
"devIcon", "devSite", "devSSID", "devSyncHubNode", "devSourcePlugin", "devFQDN",
"devParentRelType", "devReqNicsOnline", "devNameSource", "devVendorSource" ,