diff --git a/front/css/app.css b/front/css/app.css
index c8601286..ccc10a14 100755
--- a/front/css/app.css
+++ b/front/css/app.css
@@ -147,11 +147,16 @@
.unread-notifications-bell
{
- opacity: 70%;
- color: red;
position: absolute;
top: 3px;
- /* display: none; */
+ margin-left: 15px;
+ display: none;
+
+}
+
+.navbar-custom-menu .bg-yellow
+{
+ color: white !important;
}
.header-status-locked-db
@@ -706,6 +711,11 @@ height: 50px;
/* report */
/* --------------------------------------------------------- */
+#notificationData
+{
+ margin-bottom: 10px;
+}
+
#notificationData textarea{
width: 100%;
}
diff --git a/front/img/NetAlertX_logo_notification.png b/front/img/NetAlertX_logo_notification.png
new file mode 100755
index 00000000..1032b889
Binary files /dev/null and b/front/img/NetAlertX_logo_notification.png differ
diff --git a/front/img/NetAlertX_logo_notification_white.png b/front/img/NetAlertX_logo_notification_white.png
new file mode 100755
index 00000000..a3bfaec7
Binary files /dev/null and b/front/img/NetAlertX_logo_notification_white.png differ
diff --git a/front/img/NetAlertX_logo_notification_yellow.png b/front/img/NetAlertX_logo_notification_yellow.png
new file mode 100755
index 00000000..1032b889
Binary files /dev/null and b/front/img/NetAlertX_logo_notification_yellow.png differ
diff --git a/front/js/modal.js b/front/js/modal.js
index 5892a7fa..cc4af4bd 100755
--- a/front/js/modal.js
+++ b/front/js/modal.js
@@ -261,7 +261,7 @@ function checkNotification() {
// Find the oldest unread notification with level "interrupt"
const oldestInterruptNotification = response.find(notification => notification.read === 0 && notification.level === "interrupt");
- const allUnreadNotification = response.filter(notification => notification.read === 0);
+ const allUnreadNotification = response.filter(notification => notification.read === 0 && notification.level === "alert");
if (oldestInterruptNotification) {
// Show modal dialog with the oldest unread notification
@@ -292,7 +292,8 @@ function checkNotification() {
});
}
- $('#unread-notifications-bell-count').html(allUnreadNotification.length);
+ handleUnreadNotifications(allUnreadNotification.length)
+
}
},
@@ -303,7 +304,106 @@ function checkNotification() {
});
}
+// Handling unread notifications favicon + bell floating number bublbe
+function handleUnreadNotifications(count) {
+ $('#unread-notifications-bell-count').html(count);
+ if (count > 0) {
+ $('#unread-notifications-bell-count').show();
+ // Change the favicon to show there are notifications
+ $('#favicon').attr('href', 'img/NetAlertX_logo_notification.png');
+ // Update the title to include the count
+ document.title = `(${count}) ` + originalTitle;
+ } else {
+ $('#unread-notifications-bell-count').hide();
+ // Change the favicon back to the original
+ $('#favicon').attr('href', 'img/NetAlertX_logo.png');
+ // Revert the title to the original title
+ document.title = originalTitle;
+ }
+}
+
+// Store the original title of the document
+var originalTitle = document.title;
+
+
// Start checking for notifications periodically
setInterval(checkNotification, 3000);
+// --------------------------------------------------
+// User notification handling methods
+// --------------------------------------------------
+
+const phpEndpoint = 'php/server/utilNotification.php';
+
+// --------------------------------------------------
+// Write a notification
+function writeNotification(content, level) {
+
+ $.ajax({
+ url: phpEndpoint, // Change this to the path of your PHP script
+ type: 'GET',
+ data: {
+ action: 'write_notification',
+ content: content,
+ level: level
+ },
+ success: function(response) {
+ console.log('Notification written successfully.');
+ },
+ error: function(xhr, status, error) {
+ console.error('Error writing notification:', error);
+ }
+ });
+}
+
+// --------------------------------------------------
+// Write a notification
+function markNotificationAsRead(guid) {
+
+ $.ajax({
+ url: phpEndpoint,
+ type: 'GET',
+ data: {
+ action: 'mark_notification_as_read',
+ guid: guid
+ },
+ success: function(response) {
+ console.log(response);
+ // Perform any further actions after marking the notification as read here
+ showMessage(getString("Gen_Okay"))
+ },
+ error: function(xhr, status, error) {
+ console.error("Error marking notification as read:", status, error);
+ },
+ complete: function() {
+ // Perform any cleanup tasks here
+ }
+ });
+ }
+
+// --------------------------------------------------
+// Remove a notification
+function removeNotification(guid) {
+
+ $.ajax({
+ url: phpEndpoint,
+ type: 'GET',
+ data: {
+ action: 'remove_notification',
+ guid: guid
+ },
+ success: function(response) {
+ console.log(response);
+ // Perform any further actions after marking the notification as read here
+ showMessage(getString("Gen_Okay"))
+ },
+ error: function(xhr, status, error) {
+ console.error("Error removing notification:", status, error);
+ },
+ complete: function() {
+ // Perform any cleanup tasks here
+ }
+ });
+ }
+
diff --git a/front/js/tests.js b/front/js/tests.js
index 996c5e80..375031fe 100755
--- a/front/js/tests.js
+++ b/front/js/tests.js
@@ -26,26 +26,7 @@ function lockDatabase(delay=20) {
}
-function writeNotification(content, level) {
-
- const phpEndpoint = 'php/server/utilNotification.php';
-
- $.ajax({
- url: phpEndpoint, // Change this to the path of your PHP script
- type: 'GET',
- data: {
- action: 'write_notification',
- content: content,
- level: level
- },
- success: function(response) {
- alert('Notification written successfully.');
- },
- error: function(xhr, status, error) {
- console.error('Error writing notification:', error);
- }
- });
-}
+
diff --git a/front/js/ui_components.js b/front/js/ui_components.js
index 536389da..f78b4aeb 100755
--- a/front/js/ui_components.js
+++ b/front/js/ui_components.js
@@ -250,6 +250,33 @@ function updateIconPreview (inputId) {
}
+
+// -----------------------------------------------------------------------------
+// Generic function to copy text to clipboard
+function copyToClipboard(buttonElement) {
+ const text = $(buttonElement).data('text');
+ if (navigator.clipboard && navigator.clipboard.writeText) {
+ navigator.clipboard.writeText(text).then(() => {
+ showMessage('Copied to clipboard: ' + text, 1500);
+ }).catch(err => {
+ console.error('Failed to copy: ', err);
+ });
+ } else {
+ // Fallback to execCommand if Clipboard API is not available
+ const tempInput = document.createElement('input');
+ tempInput.value = text;
+ document.body.appendChild(tempInput);
+ tempInput.select();
+ try {
+ document.execCommand('copy');
+ showMessage('Copied to clipboard: ' + text, 1500);
+ } catch (err) {
+ console.error('Failed to copy: ', err);
+ }
+ document.body.removeChild(tempInput);
+ }
+}
+
// -----------------------------------------------------------------------------
// initialize
// -----------------------------------------------------------------------------
diff --git a/front/multiEditCore.php b/front/multiEditCore.php
index 3d104403..c3cc93a4 100755
--- a/front/multiEditCore.php
+++ b/front/multiEditCore.php
@@ -290,6 +290,8 @@ function executeAction(action, whereColumnName, key, targetColumns, newTargetCol
// update API endpoints to refresh the UI
updateApi()
+ writeNotification(`[Multi edit] Executed "${action}" on Columns "${targetColumns}" matching "${key}"`, 'info')
+
} else {
showMessage(getString('Gen_LockedDB'));
}
@@ -313,9 +315,9 @@ function askDeleteSelectedDevices () {
// Delete selected devices
function deleteSelectedDevices()
{
-
- executeAction('delete', 'dev_MAC', selectorMacs() )
-
+ macs_tmp = selectorMacs()
+ executeAction('delete', 'dev_MAC', macs_tmp )
+ writeNotification('[Multi edit] Manually deleted devices with MACs:' + macs_tmp, 'info')
}
diff --git a/front/php/server/utilNotification.php b/front/php/server/utilNotification.php
index 02c674ec..69a63ece 100755
--- a/front/php/server/utilNotification.php
+++ b/front/php/server/utilNotification.php
@@ -1,5 +1,9 @@
format('Y-m-d H:i:s');
// Escape content to prevent breaking JSON
$escaped_content = json_encode($content);
diff --git a/front/php/templates/header.php b/front/php/templates/header.php
index f5a90c84..33c446b8 100755
--- a/front/php/templates/header.php
+++ b/front/php/templates/header.php
@@ -62,7 +62,7 @@ require dirname(__FILE__).'/security.php';
-
+
@@ -165,7 +165,7 @@ if ($ENABLED_DARKMODE === True) {
- 0
+ 0
diff --git a/front/php/templates/language/de_de.json b/front/php/templates/language/de_de.json
index 0b4942d8..2524ab01 100755
--- a/front/php/templates/language/de_de.json
+++ b/front/php/templates/language/de_de.json
@@ -540,6 +540,8 @@
"Network_Table_State": "Status",
"Network_Title": "Netzwerk\u00fcbersicht",
"Network_UnassignedDevices": "Nicht zugewiesene Ger\u00e4te",
+ "Notifications_All": "",
+ "Notifications_Mark_All_Read": "",
"PIALERT_WEB_PASSWORD_description": "Das Standardpasswort ist 123456. Um das Passwort zu \u00e4ndern, entweder /app/back/pialert-cli im Container starten oder SETPWD_RUN Set password plugin nutzen.",
"PIALERT_WEB_PASSWORD_name": "Login-Passwort",
"PIALERT_WEB_PROTECTION_description": "Ein Loginfenster wird angezeigt wenn aktiviert. Untere Beschreibung genau durchlesen falls Sie sich aus Ihrer Instanz aussperren.",
@@ -594,6 +596,7 @@
"REPORT_WEBHOOK_description": "Enable webhooks for notifications. Webhooks help you to connect to a lot of 3rd party tools, such as IFTTT, Zapier or n8n to name a few. Check out this simple n8n guide here to get started. If enabled, configure related settings below.",
"REPORT_WEBHOOK_name": "Enable Webhooks",
"RandomMAC_hover": "Autodetected - indicates if the device randomizes it's MAC address.",
+ "Reports_Sent_Log": "",
"SCAN_SUBNETS_description": "Arp-scan is a command-line tool that uses the ARP protocol to discover and fingerprint IP hosts on the local network. An alternative to ARP scan is to enable the PIHOLE_RUNPiHole integration settings. The arp-scan time itself depends on the number of IP addresses to check so set this up carefully with the appropriate network mask and interface. Check the subnets documentation for help on setting up VLANs, what VLANs are supported, or how to figure out the network mask and your interface.",
"SMTP_FORCE_SSL_description": "Force SSL when connecting to your SMTP server.",
"SMTP_FORCE_SSL_name": "Force SSL",
@@ -745,7 +748,7 @@
"settings_other_scanners_icon": "fa-solid fa-recycle",
"settings_other_scanners_label": "Andere Scanner",
"settings_publishers": "",
- "settings_publishers_icon": "fa-solid fa-comment-dots",
+ "settings_publishers_icon": "fa-solid fa-paper-plane",
"settings_publishers_label": "Ver\u00f6ffentlicher",
"settings_saved": " Settings saved to the app.conf file.
A time-stamped backup of the previous file created.
Reloading... ",
"settings_system_icon": "fa-solid fa-gear",
diff --git a/front/php/templates/language/en_us.json b/front/php/templates/language/en_us.json
index 63ed3bba..29f4aad4 100755
--- a/front/php/templates/language/en_us.json
+++ b/front/php/templates/language/en_us.json
@@ -503,6 +503,8 @@
"Network_Table_State": "State",
"Network_Title": "Network overview",
"Network_UnassignedDevices": "Unassigned devices",
+ "Notifications_All": "All Notifications",
+ "Notifications_Mark_All_Read": "Mark All Read",
"PIALERT_WEB_PASSWORD_description": "The default password is 123456. To change the password run /app/back/pialert-cli in the container or use the SETPWD_RUN Set password plugin.",
"PIALERT_WEB_PASSWORD_name": "Login password",
"PIALERT_WEB_PROTECTION_description": "When enabled a login dialog is displayed. Read below carefully if you get locked out of your instance.",
@@ -539,6 +541,7 @@
"REPORT_MAIL_name": "Enable email",
"REPORT_TITLE": "Report",
"RandomMAC_hover": "Autodetected - indicates if the device randomizes it's MAC address.",
+ "Reports_Sent_Log": "Sent Reports Log",
"SCAN_SUBNETS_description": "Most on-network scanners (ARP-SCAN, NMAP, NSLOOKUP, DIG, PHOLUS) rely on scanning specific network interfaces and subnets. Check the subnets documentation for help on this setting, especially VLANs, what VLANs are supported, or how to figure out the network mask and your interface.
An alternative to on-network scanners is to enable some other Device scanners/importers that don't rely on NetAlertX having access to the network (UNIFI, dhcp.leases, PiHole, etc.).
Note: The scan time itself depends on the number of IP addresses to check, so set this up carefully with the appropriate network mask and interface.",
"SYSTEM_TITLE": "System Information",
"Setting_Override": "Override value",
@@ -642,7 +645,7 @@
"general_event_description": "The event you have triggered might take a while until background processes finish. The execution ended once the below execution queue empties (Check the error log if you encounter issues).
Execution queue:",
"general_event_title": "Executing an ad-hoc event",
"report_guid": "Notification guid:",
- "report_guid_missing": "Linked notification not found. The selected notification might have been deleted during maintenance as specified in the DBCLNP_NOTIFI_HIST setting. The latest notification is displayed instead. The missing notification has the following GUID:",
+ "report_guid_missing": "Linked notification not found. There is a small delay between recently sent notifications and them being available. Referesh your page and cache after a few seconds. It's also possible the selected notification have been deleted during maintenance as specified in the DBCLNP_NOTIFI_HIST setting.
The latest notification is displayed instead. The missing notification has the following GUID:",
"report_select_format": "Select Format:",
"report_time": "Notification time:",
"run_event_icon": "fa-play",
@@ -664,7 +667,7 @@
"settings_other_scanners_icon": "fa-solid fa-recycle",
"settings_other_scanners_label": "Other scanners",
"settings_publishers": "Enabled notification gateways - publishers, that will send a notification depending on your settings.",
- "settings_publishers_icon": "fa-solid fa-comment-dots",
+ "settings_publishers_icon": "fa-solid fa-paper-plane",
"settings_publishers_label": "Publishers",
"settings_saved": " Settings saved.
Reloading...
",
"settings_system_icon": "fa-solid fa-gear",
diff --git a/front/php/templates/language/es_es.json b/front/php/templates/language/es_es.json
index 018de6c6..477c4d70 100755
--- a/front/php/templates/language/es_es.json
+++ b/front/php/templates/language/es_es.json
@@ -538,6 +538,8 @@
"Network_Table_State": "Estado",
"Network_Title": "Descripci\u00f3n general de la red",
"Network_UnassignedDevices": "Dispositivos sin asignar",
+ "Notifications_All": "",
+ "Notifications_Mark_All_Read": "",
"PIALERT_WEB_PASSWORD_description": "Por defecto, la contrase\u00f1a es 123456.Para cambiar la contrase\u00f1a ejecute /app/back/pialert-cli en el contenedor o utilice el SETPWD_RUN Establecer contrase\u00f1a plugin.",
"PIALERT_WEB_PASSWORD_name": "Contrase\u00f1a de inicio de sesi\u00f3n",
"PIALERT_WEB_PROTECTION_description": "Cuando est\u00e1 habilitado, se muestra un cuadro de di\u00e1logo de inicio de sesi\u00f3n. Lea detenidamente a continuaci\u00f3n si se le bloquea el acceso a su instancia.",
@@ -592,6 +594,7 @@
"REPORT_WEBHOOK_description": "Habilite webhooks para notificaciones. Los webhooks lo ayudan a conectarse a muchas herramientas de terceros, como IFTTT, Zapier o n8n, por nombrar algunas. Consulte esta sencilla gu\u00eda de n8n aqu\u00ed para obtener comenz\u00f3. Si est\u00e1 habilitado, configure los ajustes relacionados a continuaci\u00f3n.",
"REPORT_WEBHOOK_name": "Habilitar webhooks",
"RandomMAC_hover": "Autodetectado - indica si el dispositivo aleatoriza su direcci\u00f3n MAC.",
+ "Reports_Sent_Log": "",
"SCAN_SUBNETS_description": "La mayor\u00eda de los esc\u00e1neres en red (ARP-SCAN, NMAP, NSLOOKUP, DIG, PHOLUS) se basan en el escaneo de interfaces de red y subredes espec\u00edficas. Consulte la documentaci\u00f3n sobre subredes para obtener ayuda sobre esta configuraci\u00f3n, especialmente VLANs, qu\u00e9 VLANs son compatibles, o c\u00f3mo averiguar la m\u00e1scara de red y su interfaz.
Una alternativa a los esc\u00e1neres en red es habilitar algunos otros esc\u00e1neres/importadores de dispositivos que no dependen de que NetAlertX tenga acceso a la red (UNIFI, dhcp.leases, PiHole, etc.).
Nota: El tiempo de escaneo en s\u00ed depende del n\u00famero de direcciones IP a comprobar, as\u00ed que configure esto cuidadosamente con la m\u00e1scara de red y la interfaz adecuadas.",
"SCAN_SUBNETS_name": "Subredes para escanear",
"SMTP_FORCE_SSL_description": "Forzar SSL al conectarse a su servidor SMTP",
@@ -744,7 +747,7 @@
"settings_other_scanners_icon": "fa-solid fa-recycle",
"settings_other_scanners_label": "Otros esc\u00e1neres",
"settings_publishers": "Puertas de enlace para las notificaci\u00f3n habilitadas: editores, que enviar\u00e1n una notificaci\u00f3n seg\u00fan su configuraci\u00f3n.",
- "settings_publishers_icon": "fa-solid fa-comment-dots",
+ "settings_publishers_icon": "fa-solid fa-paper-plane",
"settings_publishers_label": "Editores",
"settings_saved": " Ajustes guardados.
Recargando...
",
"settings_system_icon": "fa-solid fa-gear",
diff --git a/front/php/templates/language/fr_fr.json b/front/php/templates/language/fr_fr.json
index fc9be8b7..58033929 100755
--- a/front/php/templates/language/fr_fr.json
+++ b/front/php/templates/language/fr_fr.json
@@ -503,6 +503,8 @@
"Network_Table_State": "\u00c9tat",
"Network_Title": "",
"Network_UnassignedDevices": "",
+ "Notifications_All": "",
+ "Notifications_Mark_All_Read": "",
"PIALERT_WEB_PASSWORD_description": "",
"PIALERT_WEB_PASSWORD_name": "",
"PIALERT_WEB_PROTECTION_description": "",
@@ -539,6 +541,7 @@
"REPORT_MAIL_name": "",
"REPORT_TITLE": "",
"RandomMAC_hover": "",
+ "Reports_Sent_Log": "",
"SCAN_SUBNETS_description": "",
"SYSTEM_TITLE": "Informations syst\u00e8me",
"Setting_Override": "",
diff --git a/front/php/templates/language/it_it.json b/front/php/templates/language/it_it.json
index 0fbed9b6..2fdc64fa 100755
--- a/front/php/templates/language/it_it.json
+++ b/front/php/templates/language/it_it.json
@@ -503,6 +503,8 @@
"Network_Table_State": "Stato",
"Network_Title": "Panoramica di Rete",
"Network_UnassignedDevices": "Dispositivi non assegnati",
+ "Notifications_All": "",
+ "Notifications_Mark_All_Read": "",
"PIALERT_WEB_PASSWORD_description": "La password predefinita \u00e8 123456. Per cambiare la password esegui /app/back/pialert-cli nel container o usa il plugin per impostare la password SETPWD_RUN.",
"PIALERT_WEB_PASSWORD_name": "Password login",
"PIALERT_WEB_PROTECTION_description": "Se abilitato, una finestra di login viene mostrata. Leggi attentamente qui sotto nel caso in cui si rimanga bloccati fuori dalla propria istanza.",
@@ -539,6 +541,7 @@
"REPORT_MAIL_name": "Abilita email",
"REPORT_TITLE": "Report",
"RandomMAC_hover": "Autorilevato - indica se l'indirizzo MAC del dispositivo \u00e8 casuale.",
+ "Reports_Sent_Log": "",
"SCAN_SUBNETS_description": "La maggior parte degli scanner di rete (ARP-SCAN, NMAP, NSLOOKUP, DIG, PHOLUS) si basano sulla scansione di interfacce di rete e sottoreti specifiche. Consulta la documentazione sulle sottoreti per assistenza su questa impostazione, in particolare VLAN, quali VLAN sono supportate o come individuare la maschera di rete e l'interfaccia.
Un'alternativa agli scanner in rete \u00e8 abilitare altri scanner/importatori di dispositivi che non si affidano a NetAlertX che hanno accesso alla rete (UNIFI, dhcp.leases , PiHole, ecc.).
Nota: il tempo di scansione stesso dipende dal numero di indirizzi IP da controllare, quindi impostarlo attentamente con la maschera di rete e l'interfaccia appropriate.",
"SYSTEM_TITLE": "Informazioni di Sistema",
"Setting_Override": "Sovrascrivi valore",
@@ -664,7 +667,7 @@
"settings_other_scanners_icon": "fa-solid fa-recycle",
"settings_other_scanners_label": "Altri scanner",
"settings_publishers": "Gateway-Publishers di notifica abilitati, che inviano notifiche in base alle tue impostazioni.",
- "settings_publishers_icon": "fa-solid fa-comment-dots",
+ "settings_publishers_icon": "fa-solid fa-paper-plane",
"settings_publishers_label": "Publisher",
"settings_saved": " Impostazioni salvate.