diff --git a/docs/DEVICE_CHANGE_LOG.md b/docs/DEVICE_CHANGE_LOG.md new file mode 100644 index 00000000..c2f3b25f --- /dev/null +++ b/docs/DEVICE_CHANGE_LOG.md @@ -0,0 +1,73 @@ +# Change log + +The **_Change log_** provides a historical record of changes made to your devices. It allows you to see **what changed, when it changed, and what caused the change**, making it easier to troubleshoot unexpected updates, audit configuration changes, and understand how device information evolves over time. + +![Device Change log](./img/DEVICE_MANAGEMENT/device_change_log.png) + +## What is recorded? + +Whenever a tracked device property changes, NetAlertX records: + +* **Time** the change occurred +* **Source** that made the change +* **Device** that was updated +* **Field** that changed +* **Previous value** +* **New value** + +Related changes that occur at the same time are grouped together into a single event, making it easy to see all updates from one scan or user action. + +## Understanding the Source column + +The **Source** column identifies what caused the change. + +Depending on the field, the source may be: + +* A discovery plugin such as **ARPSCAN**, **NSLOOKUP**, **UNIFIAPI**, or another plugin that supplied the information. +* **user:api** for changes made manually through the NetAlertX interface or API. +* **system** for values calculated or maintained internally by NetAlertX. + +This helps distinguish between information discovered automatically and changes made by users. + +## Filtering the history + +The _Change log_ includes filters to help locate specific events. + +You can filter by: + +* **Source** to view changes made by a specific plugin or user. +* **Changed Field** to display changes to a particular device property, such as IP address or hostname. + +You can also use the search box to quickly find matching devices by GUID, values, or fields. + +## Viewing grouped changes + +A single action often updates multiple properties on a device. + +Instead of showing each field as a separate record, the _Change log_ groups related updates together. For example, a network scan might update both a device's IP address and hostname at the same time. These changes appear together in one entry with each modified field listed underneath. + +## Retention + +The amount of history retained is controlled by the **Device History Days (`DEV_HIST_DAYS`)** setting. + +Older history entries are automatically removed once they exceed the configured retention period. this is maintained by the `DBCLNP` plugin. + +Setting this value to **0** disables _Change log_ recording entirely. + +## Choosing what to track + +Not every device property needs to be recorded. + +The **Tracked Device History Fields (`DEV_HIST_TRACKED`)** setting lets you choose exactly which device fields should be monitored. Tracking only the fields that are important for your environment can significantly reduce database growth while keeping the most useful audit information. + +## Performance considerations + +Recording history introduces additional database writes whenever tracked fields change. For most installations the overhead is minimal, but on larger networks it can generate a substantial amount of historical data. + +If you want to reduce storage usage or improve performance, consider: + +* Tracking only the device fields that matter to you. +* Reducing the history retention period. +* Disabling the _Change log_ entirely by setting **`DEV_HIST_DAYS`** to **0**. + +These settings allow you to balance historical visibility with database size and performance. For more tips on how to optimize system resource use check the [performance guide](./PERFORMANCE.md). diff --git a/docs/DEVICE_PRESENCE.md b/docs/DEVICE_PRESENCE.md new file mode 100644 index 00000000..89133678 --- /dev/null +++ b/docs/DEVICE_PRESENCE.md @@ -0,0 +1,45 @@ +## Presence View + +![Device presence](./img/DEVICE_MANAGEMENT/device_presence.png) + +The **Presence View** provides a visual timeline of when each device was detected on your network, making it easy to understand activity over time instead of relying only on the current status. + +Use this view to answer questions such as: + +* When was this device first discovered? +* When was it last seen online? +* How often does this device connect to the network? +* Has the device been continuously online or only appearing intermittently? +* When did the device disappear or return? + +The timeline makes it easy to identify recurring activity patterns, unexpected outages, or devices that only appear at certain times of the day or week. + +### Timeline Views + +The timeline can be displayed at different time scales depending on the level of detail you need: + +* **Week** – View recent activity with the highest level of detail. +* **Month** – Review activity across the past month. +* **Year** – Get a long-term overview of device presence and seasonal patterns. + +Switch between these views using the **Week**, **Month**, and **Year** buttons above the timeline. + +### Timeline Legend + +The timeline uses color coding to indicate device presence: + +*
**Now online** – The device was detected during the most recent scan and is currently online. +*
**Past online** – The device was online previously but is currently offline. +*
**Past online (mismatch)** – Historical activity was detected, but the beginning of the session could not be determined or conflicting data was encountered. + +### Typical Uses + +The Presence View is especially useful for: + +* Troubleshooting intermittent connectivity issues. +* Identifying devices that frequently disconnect and reconnect. +* Understanding occupancy or usage patterns for phones, laptops, IoT devices, and other network equipment. +* Verifying when visitors' devices or temporary equipment were present on the network. +* Reviewing historical presence without searching through individual events or logs. + +Unlike the Device Details page, which shows the current state of a device, the Presence View focuses on **when** devices were active, providing valuable historical context at a glance. To investigate exactly **what** changed during a device's lifetime, see the [Change Log](./DEVICE_CHANGE_LOG.md). diff --git a/docs/WHERE_NETALERTX_FITS.md b/docs/WHERE_NETALERTX_FITS.md index 0b56bd63..5f3dd715 100644 --- a/docs/WHERE_NETALERTX_FITS.md +++ b/docs/WHERE_NETALERTX_FITS.md @@ -122,13 +122,43 @@ NetAlertX supports [device relationships](./NETWORK_TREE.md) to better represent Many monitoring systems focus only on the current state. -NetAlertX also records historical information so you can answer questions like: +NetAlertX also records historical information, helping you understand how devices behave over time. + +You can answer questions like: * When was this device first discovered? * When was it last online? -* Which ports have changed over time? +* How does its network presence change over time? +* Which configuration attributes have changed? + +Historical data provides operational context without requiring a separate logging platform. + +Two key views help explore this history: + +* **Presence View** – when a device was active on the network +* **Change log** – what changed in the device’s configuration over time + +--- + +## Change log + +![Device change log](./img/DEVICE_MANAGEMENT/device_change_log.png) + +The **Change log** records all tracked changes to device attributes, showing what changed and when it happened. + +Each entry includes: + +* Timestamp of the change +* Previous and new values +* Source of the change (plugin, workflow, or user action) + +You can filter, search, and sort changes to quickly investigate events such as IP changes, hostname updates, VLAN changes, or device classification updates. + +| View | Answers | +| ----------------- | ------------------- | +| **Presence View** | When was it active? | +| **Change log** | What changed? | -Historical information provides valuable operational context without requiring a separate logging platform. --- diff --git a/docs/img/DEVICE_MANAGEMENT/device_change_log.png b/docs/img/DEVICE_MANAGEMENT/device_change_log.png new file mode 100644 index 00000000..7166d7d9 Binary files /dev/null and b/docs/img/DEVICE_MANAGEMENT/device_change_log.png differ diff --git a/docs/stylesheets/custom.css b/docs/stylesheets/custom.css index a8585d21..f7105106 100644 --- a/docs/stylesheets/custom.css +++ b/docs/stylesheets/custom.css @@ -14,6 +14,19 @@ * limitations under the License. */ + :root { + --color-white: #fff; + --color-aqua: #00c0ef; + --color-lightblue: #3c8dbc; + --color-blue: #0060df; + --color-green: #00a65a; + --color-yellow: #f39c12; + --color-red: #dd4b39; + --color-gray: #8c8c8c; + --color-darkgray: #3f3e3e; + --color-lightgray: #bec5cb; + --color-black: #000; +} /* --- HERO SECTION --- */ .hero-wrapper { @@ -143,3 +156,25 @@ p.hero-description { .learn-more-btn:hover { opacity: 0.8; } + +/* key presence styles */ +.presenceOnlineNow{ + background-color: var(--color-green); +} + +.presenceOnlinePast{ + background-color: var(--color-blue); +} + +.presenceOnlinePastMiss{ + background-color: var(--color-yellow); +} + +.presenceKeyBoxes +{ + width: 10px; + height: 10px; + display: inline-block; + /* background: #fff; */ + opacity: .75; +} diff --git a/front/changeLog.php b/front/changeLog.php index c5003212..92aa7582 100644 --- a/front/changeLog.php +++ b/front/changeLog.php @@ -2,12 +2,6 @@ require 'php/templates/header.php'; ?>
-
-

- - -

-
diff --git a/front/changeLogCore.php b/front/changeLogCore.php index 0d320f69..0b01c473 100644 --- a/front/changeLogCore.php +++ b/front/changeLogCore.php @@ -1,311 +1,413 @@ - -
-
-
-
- -
- - -
+ - -
- - - - - - - - - - - - -
- -
-
+
+ + + + + + + +
+
+
+ + + + +
+ + + + +
+ + + + +
+ + + + + + + + + + + + + + + +
+ +
+
+
-
- +
+
\ No newline at end of file diff --git a/front/css/app.css b/front/css/app.css index 5824f4b5..751be365 100755 --- a/front/css/app.css +++ b/front/css/app.css @@ -1001,6 +1001,19 @@ height: 50px; opacity: .75; } +#presencePage .helpIcon{ + top: 2px; + display: initial; + font-size: x-small; +} + +.calendarHelpIcon{ + display: block; + position: absolute; + font-size: x-small; + top: -5px; +} + /* --------------------------------------------------------- */ /* report */ /* --------------------------------------------------------- */ @@ -2636,7 +2649,18 @@ table.dataTable tbody > tr.selected background-color: rgba(140, 140, 140, 0.05); } -/* ===== Loading Skeleton ===== */ +/* ----------------------------------------------------------------------------- + Change log +----------------------------------------------------------------------------- */ + +.change-log .helpIcon{ + left: 15px; + font-size: x-small; +} + +/* ----------------------------------------------------------------------------- + Loading Skeletons +----------------------------------------------------------------------------- */ /* Custom properties (overridden in dark-patch.css for Dark/System themes) */ :root { diff --git a/front/deviceDetailsEvents.php b/front/deviceDetailsEvents.php index 34980b80..27247c9d 100755 --- a/front/deviceDetailsEvents.php +++ b/front/deviceDetailsEvents.php @@ -196,12 +196,7 @@ function initDeviceEventsPage() // ----------------------------------------------------------------------------- // Recurring function to monitor the URL and reinitialize if needed -function deviceEventsPageUpdater() { - initDeviceEventsPage(); - - // Run updater again after delay - setTimeout(deviceEventsPageUpdater, 200); -} +initLazyTab('#panEvents', initDeviceEventsPage); deviceEventsPageUpdater(); diff --git a/front/deviceDetailsPresence.php b/front/deviceDetailsPresence.php index 31d4741f..36d5915c 100755 --- a/front/deviceDetailsPresence.php +++ b/front/deviceDetailsPresence.php @@ -21,6 +21,11 @@ + + + + +
diff --git a/front/js/common.js b/front/js/common.js index 006bad8f..765d3438 100755 --- a/front/js/common.js +++ b/front/js/common.js @@ -1175,6 +1175,82 @@ function isSQLQuery(query) { return sqlRegex.test(query); } +/** + * Lazy tab initializer + * - Ensures a tab is only initialized once + * - Waits until tab is visible in DOM + * - Uses polling (compatible with your existing architecture) + */ + +function waitForAppReady(cb) { + + if (window.__appReady) { + cb(); + return; + } + + const t = setInterval(() => { + + if (window.__appReady) { + clearInterval(t); + cb(); + } + + }, 50); +} + +function initLazyTab(selector, initFn, intervalMs = 200) { + + const stateKey = `__lazy_init_${selector}`; + let initialized = false; + + function runner() { + + // prevent duplicate execution + if (initialized || window[stateKey]) return; + + const $el = $(selector); + + // --------------------------------------------------------- + // CASE 1: element does not exist → standalone page variant + // run immediately (no DOM dependency) + // --------------------------------------------------------- + if (!$el.length) { + initialized = true; + window[stateKey] = true; + + try { + initFn(); + } catch (e) { + console.error("Lazy init (no-element) failed:", selector, e); + } + return; + } + + // --------------------------------------------------------- + // CASE 2: element exists AND is visible → run immediately + // --------------------------------------------------------- + if ($el.is(':visible')) { + initialized = true; + window[stateKey] = true; + + try { + initFn(); + } catch (e) { + console.error("Lazy init (visible) failed:", selector, e); + } + return; + } + + // --------------------------------------------------------- + // CASE 3: element exists but hidden → wait for visibility + // (tab mode) + // --------------------------------------------------------- + setTimeout(runner, intervalMs); + } + + runner(); +} // ------------------------------------------------------------------- // Get corresponding plugin setting object diff --git a/front/js/ui_components.js b/front/js/ui_components.js index 917ff860..8d3bdc1c 100755 --- a/front/js/ui_components.js +++ b/front/js/ui_components.js @@ -1164,5 +1164,5 @@ function getLengthMenu(newEntry) { return [values, labels]; } - +window.__appReady = true; console.log("init ui_components.js") \ No newline at end of file diff --git a/front/php/templates/language/en_us.json b/front/php/templates/language/en_us.json index 8d304290..bc4c54fc 100755 --- a/front/php/templates/language/en_us.json +++ b/front/php/templates/language/en_us.json @@ -777,7 +777,7 @@ "add_icon_event_tooltip": "Add new icon", "add_option_event_tooltip": "Add new value", "copy_icons_event_tooltip": "Overwrite icons of all devices with the same device type", - "device_history_col_changes": "Select which columns are tracked via the DEV_HIST_TRACKED setting.", + "device_history_col_changes": "Select which columns are tracked via the DEV_HIST_TRACKED setting.", "device_history_col_dropdown": "Columns", "device_history_col_source": "Modified By", "device_history_col_time": "Timestamp", diff --git a/front/presence.php b/front/presence.php index 2dc2da99..4a074e12 100755 --- a/front/presence.php +++ b/front/presence.php @@ -22,6 +22,7 @@
+ @@ -128,9 +129,11 @@
+
+
- +

Devices

@@ -145,6 +148,11 @@
+ + + + +
@@ -456,7 +464,7 @@ function getDevicesPresence (status) { // Set title and color $('#tableDevicesTitle')[0].className = 'box-title text-'+ color; $('#tableDevicesBox')[0].className = 'box box-'+ color; - $('#tableDevicesTitle').html (tableTitle); + $('#tableDevicesTitle').html (`${tableTitle} ${getString("Device_TableHead_PresentLastScan")}`); const apiToken = getSetting("API_TOKEN"); diff --git a/mkdocs.yml b/mkdocs.yml index 2d1ebc1c..2a16e508 100755 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -74,7 +74,10 @@ nav: - Device display settings: DEVICE_DISPLAY_SETTINGS.md - Device views filtering: DEVICE_FILTERS.md - Session info: SESSION_INFO.md - - Field Lock/Unlock: DEVICE_FIELD_LOCK.md + - Field Lock/Unlock: DEVICE_FIELD_LOCK.md + - Device auditing: + - Change log: DEVICE_CHANGE_LOG.md + - Presence: DEVICE_PRESENCE.md - Device source fields: DEVICE_SOURCE_FIELDS.md - Icons and network topology: - Icons: ICONS.md