-
diff --git a/front/css/app.css b/front/css/app.css
index 888bfac4..a49896bd 100755
--- a/front/css/app.css
+++ b/front/css/app.css
@@ -2090,36 +2090,45 @@ input[readonly] {
/* -----------------------------------------------------------------------------
Spin
----------------------------------------------------------------------------- */
+#loadingSpinner {
+ position: fixed;
+ z-index: 1000;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ opacity: 0;
+ transition: opacity 0.3s ease-in-out;
+ pointer-events: none;
+ display: block;
+ z-index: 999;
+}
+
+#loadingSpinner.visible {
+ opacity: 1;
+ pointer-events: auto;
+}
+
.pa_semitransparent-panel {
position: absolute;
- width: 100%; /*calc (100% -40px);*/
+ width: 100%;
height: 100%;
- left: 0;
- top: 0;
- display: block;
-
- opacity: 0.8;
background-color: #fff;
- z-index: 800;
+ opacity: 0.8;
+ z-index: 99;
}
.pa_spinner {
- position: fixed;
- left: 0;
- right: 0;
+ position: absolute;
top: 100px;
- margin-left: auto;
- margin-right: auto;
+ left: 50%;
+ transform: translateX(-50%);
padding: 15px;
width: 200px;
background-color: #fff;
- z-index: 801;
+ z-index: 1000;
}
-#loadingSpinner
-{
- z-index: 100;
-}
/* Multi-edit adjustements */
.box-header
diff --git a/front/css/dark-patch.css b/front/css/dark-patch.css
index 3929bf9a..9fea6749 100755
--- a/front/css/dark-patch.css
+++ b/front/css/dark-patch.css
@@ -10,6 +10,16 @@
*
* Additional fixes For Pi.Alert UI by leiweibau */
+:root {
+ --color-aqua: #00c0ef;
+ --color-lightblue: #3c8dbc;
+ --color-blue: #0060df;
+ --color-green: #00a65a;
+ --color-yellow: #f39c12;
+ --color-red: #dd4b39;
+ --color-gray: #8c8c8c;
+}
+
:root {
--datatable-bgcolor: rgba(64, 76, 88, 0.8);
}
@@ -770,4 +780,9 @@ input[type="password"]::-webkit-caps-lock-indicator {
.thresholdFormControl
{
color:#000;
+}
+
+.btn:hover
+{
+ color: var(--color-gray);
}
\ No newline at end of file
diff --git a/front/css/system-dark-patch.css b/front/css/system-dark-patch.css
index 50088f78..43706116 100755
--- a/front/css/system-dark-patch.css
+++ b/front/css/system-dark-patch.css
@@ -11,6 +11,16 @@
* Additional fixes For Pi.Alert UI by leiweibau */
@media (prefers-color-scheme: dark) {
+
+ :root {
+ --color-aqua: #00c0ef;
+ --color-lightblue: #3c8dbc;
+ --color-blue: #0060df;
+ --color-green: #00a65a;
+ --color-yellow: #f39c12;
+ --color-red: #dd4b39;
+ --color-gray: #8c8c8c;
+}
:root {
--datatable-bgcolor: rgba(64, 76, 88, 0.8);
@@ -781,3 +791,7 @@
color:#000;
}
+.btn:hover
+{
+ color: var(--color-gray);
+}
\ No newline at end of file
diff --git a/front/deviceDetails.php b/front/deviceDetails.php
index 8411e69c..c6f76a2d 100755
--- a/front/deviceDetails.php
+++ b/front/deviceDetails.php
@@ -16,8 +16,9 @@
require 'php/templates/header.php';
?>
-
-
+
-
-
- ${getString(`${prefix}_icon`)} ${getString(`${prefix}_display_name`)}
-
-
- ${stats.objectDataCount > 0 ? `${stats.objectDataCount}` : ""} -
- `);
- }
+ // Append the tab header to the tabs location
+ $('#tabs-location').append(`
+
-
+
+ ${getString(`${prefix}_icon`)} ${getString(`${prefix}_display_name`)}
+
+
+ ${stats.objectDataCount > 0 ? `${stats.objectDataCount}` : ""} +
+ `);
+
}
-function createTabContent(pluginObj) {
+// ---------------------------------------------------------------
+// Content of selected plugin (header)
+function createTabContent(pluginObj, assignActive) {
const prefix = pluginObj.unique_prefix; // Get the unique prefix for the plugin
const colDefinitions = getColumnDefinitions(pluginObj); // Get column definitions for DataTables
@@ -349,7 +359,7 @@ function createTabContent(pluginObj) {
// Append the content structure for the plugin's tab to the content location
$('#tabs-content-location').append(`
-
@@ -125,15 +126,11 @@
-
-
+
-
-
@@ -141,51 +138,38 @@
-
-
-
-
+ ?>
-
-
+
@@ -273,7 +257,7 @@ function main () {
period = '1 day';
sessionsRows = 50;
eventsRows = 50;
- $('#chkHideConnectionEvents')[0].checked = eval(eventsHide == 'true');
+ // $('#chkHideConnectionEvents')[0].checked = eval(eventsHide == 'true');
// Initialize components with parameters
@@ -282,26 +266,7 @@ function main () {
$( document ).ready(function() {
initializeTabs();
});
-
-
-
-
- // // Events tab toggle conenction events
- // $('input').on('ifToggled', function(event){
- // // Hide / Show Events
- // if (event.currentTarget.id == 'chkHideConnectionEvents') {
- // getDeviceEvents();
- // } else {
- // // Activate save & restore
- // // activateSaveRestoreData();
-
- // // Ask skip notifications
- // // if (event.currentTarget.id == 'chkArchived' ) {
- // // askSkipNotifications();
- // // }
- // }
- // });
-
+
}
@@ -328,6 +293,48 @@ function recordSwitch(direction) {
}
}
+
+// ----------------------------------------
+// Handle previous/next arrows/chevrons
+function updateChevrons(currentMac) {
+ const devicesList = getDevicesList();
+
+ // Find the index of the device by MAC
+ pos = devicesList.findIndex(item => item.devMac == currentMac);
+
+ // If device not found, optionally add it or handle error
+ if (pos === -1) {
+ // If you want to add a placeholder or handle missing device:
+ // devicesList.push({ mac: currentMac, name: 'Unknown', type: 'Unknown' });
+ // pos = devicesList.length - 1;
+
+ // Or just return early if device not found
+ console.warn('Device with MAC not found:', currentMac);
+ return;
+ }
+
+ // Update the record number display
+ $('#txtRecord').html((pos + 1) + ' / ' + devicesList.length);
+
+ // Enable/disable previous button
+ if (pos <= 0) {
+ $('#btnPrevious').attr('disabled', '');
+ $('#btnPrevious').addClass('text-gray50');
+ } else {
+ $('#btnPrevious').removeAttr('disabled');
+ $('#btnPrevious').removeClass('text-gray50');
+ }
+
+ // Enable/disable next button
+ if (pos >= devicesList.length - 1) {
+ $('#btnNext').attr('disabled', '');
+ $('#btnNext').addClass('text-gray50');
+ } else {
+ $('#btnNext').removeAttr('disabled');
+ $('#btnNext').removeClass('text-gray50');
+ }
+}
+
// -----------------------------------------------------------------------------
function performSwitch(direction)
@@ -338,7 +345,9 @@ function performSwitch(direction)
// Update the global position in the devices list variable 'pos'
if (direction === "next") {
- if (pos < devicesList.length - 1) {
+ console.log("direction" + direction);
+
+ if (pos < devicesList.length) {
pos++;
}
} else if (direction === "prev") {
@@ -358,15 +367,12 @@ function performSwitch(direction)
}
-
// -----------------------------------------------------------------------------
// Activate save & restore on any value change
$(document).on('input', 'input:text', function() {
settingsChanged();
});
-
-
// -----------------------------------------------------------------------------
function initializeTabs () {
@@ -380,8 +386,6 @@ function initializeTabs () {
}
$('.nav-tabs a[id='+ selectedTab +']').tab('show');
- // $('.nav-tabs a[id='+ selectedTab +']').parent().click();
- // $('.nav-tabs a[id="tabPlugins"]').tab('show');
// When changed save new current tab
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
@@ -391,11 +395,6 @@ function initializeTabs () {
// events on tab change
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
var target = $(e.target).attr("href") // activated tab
-
- // if(target == "#panTools")
- // {
- // // loadTools();
- // }
});
}
@@ -482,22 +481,41 @@ async function renderSmallBoxes() {
console.error('Error in renderSmallBoxes:', error);
} finally {
// Hide loading dialog
- hideSpinner();
+ // hideSpinner();
}
}
+function updateDevicePageName(mac) {
+
+ name = getDevDataByMac(mac, "devName")
+ owner = getDevDataByMac(mac, "devOwner")
+
+ // Page title - Name
+ if (mac == "new") {
+ $('#pageTitle').html(` ` + getString("Gen_create_new_device"));
+ $('#devicePageInfoPlc .inner').html(` ` + getString("Gen_create_new_device_info"));
+ $('#devicePageInfoPlc').show();
+ } else if (owner == null || owner == '' ||
+ (name.toString()).indexOf(owner) != -1) {
+ $('#pageTitle').html(name);
+ $('#devicePageInfoPlc').hide();
+ } else {
+ $('#pageTitle').html(name + ' (' + owner + ')');
+ $('#devicePageInfoPlc').hide();
+ }
+
+}
//-----------------------------------------------------------------------------------
+
window.onload = function async()
{
initializeTabs();
-
+ updateChevrons(mac);
+ updateDevicePageName(mac);
}
-
-
-
diff --git a/front/deviceDetailsEdit.php b/front/deviceDetailsEdit.php
index 150d787d..5ae68e4d 100755
--- a/front/deviceDetailsEdit.php
+++ b/front/deviceDetailsEdit.php
@@ -39,7 +39,7 @@
// -------------------------------------------------------------------
// Get plugin and settings data from API endpoints
- function getDeviceData(readAllData){
+ function getDeviceData(){
mac = getMac()
@@ -53,13 +53,13 @@
var deviceData = JSON.parse(data);
- // Deactivate next previous buttons
- if (readAllData) {
- $('#btnPrevious').attr ('disabled','');
- $('#btnPrevious').addClass ('text-gray50');
- $('#btnNext').attr ('disabled','');
- $('#btnNext').addClass ('text-gray50');
- }
+ // // Deactivate next previous buttons
+ // if (readAllData) {
+ // $('#btnPrevious').attr ('disabled','');
+ // $('#btnPrevious').addClass ('text-gray50');
+ // $('#btnNext').attr ('disabled','');
+ // $('#btnNext').addClass ('text-gray50');
+ // }
// some race condition, need to implement delay
setTimeout(() => {
@@ -255,30 +255,13 @@
updateAllIconPreviews();
// update readonly fields
- handleReadOnly(settingsData, disabledFields);
-
- // Page title - Name
- if (mac == "new") {
- $('#pageTitle').html(` ` + getString("Gen_create_new_device"));
- $('#devicePageInfoPlc .inner').html(` ` + getString("Gen_create_new_device_info"));
- $('#devicePageInfoPlc').show();
- } else if (deviceData['devOwner'] == null || deviceData['devOwner'] == '' ||
- (deviceData['devName'].toString()).indexOf(deviceData['devOwner']) != -1) {
- $('#pageTitle').html(deviceData['devName']);
- $('#devicePageInfoPlc').hide();
- } else {
- $('#pageTitle').html(deviceData['devName'] + ' (' + deviceData['devOwner'] + ')');
- $('#devicePageInfoPlc').hide();
- }
+ handleReadOnly(settingsData, disabledFields);
};
// console.log(relevantSettings)
generateSimpleForm(relevantSettings);
- // <> chevrons
- updateChevrons(deviceData)
-
toggleNetworkConfiguration(mac == 'Internet')
initSelect2();
@@ -294,46 +277,6 @@
}
- // ----------------------------------------
- // Handle previous/next arrows/chevrons
- function updateChevrons(deviceData) {
-
- devicesList = getDevicesList();
-
- // console.log(devicesList);
-
- // Check if device is part of the devicesList
- pos = devicesList.findIndex(item => item.rowid == deviceData['rowid']);
-
- // console.log(pos);
-
- if (pos == -1) {
- devicesList.push({"rowid" : deviceData['rowid'], "mac" : deviceData['devMac'], "name": deviceData['devName'], "type": deviceData['devType']});
- pos=0;
- }
-
- // Record number
- $('#txtRecord').html (pos+1 +' / '+ devicesList.length);
-
- // Deactivate previous button
- if (pos <= 0) {
- $('#btnPrevious').attr ('disabled','');
- $('#btnPrevious').addClass ('text-gray50');
- } else {
- $('#btnPrevious').removeAttr ('disabled');
- $('#btnPrevious').removeClass ('text-gray50');
- }
-
- // Deactivate next button
- if (pos >= (devicesList.length-1)) {
- $('#btnNext').attr ('disabled','');
- $('#btnNext').addClass ('text-gray50');
- } else {
- $('#btnNext').removeAttr ('disabled');
- $('#btnNext').removeClass ('text-gray50');
- }
- }
-
// ----------------------------------------
// Handle the read-only fields
function handleReadOnly(settingsData, disabledFields) {
@@ -451,9 +394,47 @@
}
}
+// -----------------------------------------------
+// INIT with polling for panel element visibility
+// -----------------------------------------------
+
+var deviceDetailsPageInitialized = false;
+
+function initdeviceDetailsPage()
+{
+ // Only proceed if .plugin-content is visible
+ if (!$('#panDetails:visible').length) {
+ return; // exit early if nothing is visible
+ }
+
+ // init page once
+ if (deviceDetailsPageInitialized) return; // ENSURE ONCE
+ deviceDetailsPageInitialized = true;
+
+ showSpinner();
+
+ getDeviceData();
+
+}
+
+// -----------------------------------------------------------------------------
+// Recurring function to monitor the URL and reinitialize if needed
+function deviceDetailsPageUpdater() {
+ initdeviceDetailsPage();
+
+ // Run updater again after delay
+ setTimeout(deviceDetailsPageUpdater, 200);
+}
+
+// if visible, load immediately, if not start updater
+if (!$('#panDetails:visible').length) {
+ deviceDetailsPageUpdater();
+}
+else
+{
+ getDeviceData();
+}
- // -------------------- INIT ------------------------
- getDeviceData(true);
\ No newline at end of file
diff --git a/front/deviceDetailsEvents.php b/front/deviceDetailsEvents.php
index 6e6d7f82..98ffa53b 100755
--- a/front/deviceDetailsEvents.php
+++ b/front/deviceDetailsEvents.php
@@ -29,10 +29,7 @@
\ No newline at end of file
diff --git a/front/deviceDetailsPresence.php b/front/deviceDetailsPresence.php
index 7aa781a0..04dd6ac9 100755
--- a/front/deviceDetailsPresence.php
+++ b/front/deviceDetailsPresence.php
@@ -23,8 +23,6 @@
\ No newline at end of file
diff --git a/front/deviceDetailsSessions.php b/front/deviceDetailsSessions.php
index 23e27732..9498be33 100755
--- a/front/deviceDetailsSessions.php
+++ b/front/deviceDetailsSessions.php
@@ -24,77 +24,126 @@
\ No newline at end of file
diff --git a/front/devices.php b/front/devices.php
index 01e76953..5fd88e9d 100755
--- a/front/devices.php
+++ b/front/devices.php
@@ -1047,40 +1047,24 @@ function multiEditDevices()
// -----------------------------------------------------------------------------
// Function collects shown devices from the DataTable
function getMacsOfShownDevices() {
- rows = $('#tableDevices')[0].rows;
- macs = [];
+ var table = $('#tableDevices').DataTable();
- // var devicesDataTableData = $('#tableDevices').dataTable().fnGetData();
- var devicesDataTableData = $('#tableDevices').DataTable().rows({ selected: false, page: 'current' }).data().toArray();
+ var macs = [];
- console.log(devicesDataTableData);
+ // Get all row indexes on current page, in display order
+ var allIndexes = table.rows({ page: 'current' }).indexes();
- var selectedDevices = [];
-
- // first row is the heading, skip
- for (var i = 1; i < rows.length; i++) {
- var rowIndex = rows[i]._DT_RowIndex;
-
- // Ensure the rowIndex is valid and within bounds of devicesDataTableData
- if (rowIndex >= 0 && rowIndex < devicesDataTableData.length) {
- selectedDevices.push(devicesDataTableData[rowIndex]);
- } else {
- console.log(`Invalid rowIndex: ${rowIndex} at row ${i}`);
+ allIndexes.each(function(idx) {
+ var rowData = table.row(idx).data();
+ if (rowData) {
+ macs.push(rowData[mapIndx(11)]); // mapIndx(11) == MAC column
}
- }
-
- for (var j = 0; j < selectedDevices.length; j++) {
- // Ensure that selectedDevices[j] is not undefined
- if (selectedDevices[j]) {
- macs.push(selectedDevices[j][mapIndx(11)]); // mapIndx(11) == MAC
- } else {
- console.log(`selectedDevices[${j}] is undefined`);
- }
- }
+ });
return macs;
}
+
// -----------------------------------------------------------------------------
// Handle custom actions/properties on a device
function renderCustomProps(custProps, mac) {
diff --git a/front/js/common.js b/front/js/common.js
index 685b9e8a..72e261d1 100755
--- a/front/js/common.js
+++ b/front/js/common.js
@@ -1109,46 +1109,52 @@ function getGuid() {
// -----------------------------------------------------------------------------
// Loading Spinner overlay
// -----------------------------------------------------------------------------
-spinnerHtml = `
-
-
-
-
-
-
+ ?>
-
-
-
-
-
- `
-function showSpinner(stringKey='Loading')
-{
+let spinnerTimeout = null;
+let animationTime = 300
- if(stringKey == "")
- {
- text = ''
- } else
- {
- text = getString(stringKey)
- }
+function showSpinner(stringKey = 'Loading') {
+ const text = isEmpty(stringKey) ? "Loading" : getString(stringKey || "Loading");
+ const spinner = $("#loadingSpinner");
+
+ if (spinner.length && spinner.is(':visible')) {
+ clearTimeout(spinnerTimeout);
+
+ console.log(spinner);
- text = isEmpty(text) ? "Loading" : text;
+ $("#loadingSpinnerText").text(text);
+ spinner.addClass("visible");
- if($("#loadingSpinner").length)
- {
- $("#loadingSpinner").show();
- }
- else{
- $(".wrapper").append(spinnerHtml.replace('_text_',text))
+ spinner.fadeIn(animationTime);
+ } else {
+ $("#loadingSpinnerText").text(text);
+
+ requestAnimationFrame(() => {
+ spinner.addClass("visible");
+ spinner.fadeIn(animationTime);
+ });
}
}
-// -----------------------------------------------------------------------------
-function hideSpinner()
-{
- $("#loadingSpinner").hide()
+
+function hideSpinner() {
+ clearTimeout(spinnerTimeout);
+
+ const spinner = $("#loadingSpinner");
+
+ if (spinner.length) {
+ spinner.removeClass("visible");
+ spinner.fadeOut(animationTime);
+
+ spinnerTimeout = setTimeout(() => {
+ spinner.removeClass("visible");
+ spinner.fadeOut(animationTime); // optional remove or hide again
+ }, 300);
+ }
}
+
+
+
// --------------------------------------------------------
// Calls a backend function to add a front-end event to an execution queue
diff --git a/front/php/templates/header.php b/front/php/templates/header.php
index cf8f48b2..7a3fa581 100755
--- a/front/php/templates/header.php
+++ b/front/php/templates/header.php
@@ -136,7 +136,21 @@
+
+
+
+
+
-
-
-
- | _text_ | -- |
+
+
+
+
+
+
+| + | + |
diff --git a/front/php/templates/language/en_us.json b/front/php/templates/language/en_us.json
index 50b2f765..0d73003a 100755
--- a/front/php/templates/language/en_us.json
+++ b/front/php/templates/language/en_us.json
@@ -9,7 +9,7 @@
"About_Exit": "Sign out",
"About_Title": "Network security scanner & notification framework",
"AppEvents_AppEventProcessed": "Processed",
- "AppEvents_DateTimeCreated": "Discovered On",
+ "AppEvents_DateTimeCreated": "Logged",
"AppEvents_Extra": "Extra",
"AppEvents_GUID": "Application Event GUID",
"AppEvents_Helper1": "Helper 1",
diff --git a/front/pluginsCore.php b/front/pluginsCore.php
index 98d7da06..8211dd94 100755
--- a/front/pluginsCore.php
+++ b/front/pluginsCore.php
@@ -49,10 +49,19 @@ function initMacFilter() {
return mac;
}
+// -----------------------------------------------
+// INIT with polling for panel element visibility
+// -----------------------------------------------
+
// -----------------------------------------------------------------------------
// Initializes the fields if the MAC in the URL is different or not yet set
function initFields() {
+ // Only proceed if .plugin-content is visible
+ if (!$('.plugin-content:visible').length) {
+ return; // exit early if nothing is visible
+ }
+
// Get current value from the readonly text field
const currentVal = initMacFilter();
@@ -74,15 +83,6 @@ function initFields() {
}
}
-// -----------------------------------------------------------------------------
-// Recurring function to monitor the URL and reinitialize if needed
-function updater() {
- initFields();
-
- // Run updater again after 500 milliseconds
- setTimeout(updater, 500);
-}
-
// -----------------------------------------------------------------------------
// Get form control according to the column definition from config.json > database_column_definitions
function getFormControl(dbColumnDef, value, index) {
@@ -285,11 +285,9 @@ function getData(){
pluginHistory = res["data"];
generateTabs()
-
});
});
});
-
});
}
@@ -301,15 +299,24 @@ function generateTabs() {
// Sort pluginDefinitions by unique_prefix alphabetically
pluginDefinitions.sort((a, b) => a.unique_prefix.localeCompare(b.unique_prefix));
+ assignActive = true;
+
// Iterate over the sorted pluginDefinitions to create tab headers and content
pluginDefinitions.forEach(pluginObj => {
if (pluginObj.show_ui) {
- stats = createTabContent(pluginObj); // Create the content for each tab
- createTabHeader(pluginObj, stats); // Create the header for each tab
- }
- });
+ stats = createTabContent(pluginObj, assignActive); // Create the content for each tab
- hideSpinner()
+ if(stats.objectDataCount > 0)
+ {
+ createTabHeader(pluginObj, stats, assignActive); // Create the header for each tab
+ assignActive = false; // only mark first with content active
+ }
+ }
+ });
+
+
+
+ hideSpinner()
}
function resetTabs() {
@@ -318,27 +325,30 @@ function resetTabs() {
$('#tabs-content-location').empty();
}
-function createTabHeader(pluginObj, stats) {
+// ---------------------------------------------------------------
+// left headers
+function createTabHeader(pluginObj, stats, assignActive) {
const prefix = pluginObj.unique_prefix; // Get the unique prefix for the plugin
+
// Determine the active class for the first tab
- const activeClass = pluginDefinitions.indexOf(pluginObj) === 0 ? 'active' : '';
+ assignActive ? activeClass = "active" : activeClass = "";
- if(stats.objectDataCount > 0)
- {
- // Append the tab header to the tabs location
- $('#tabs-location').append(`
-
+
${generateTabNavigation(prefix, objectData.length, eventData.length, historyData.length)}
${generateDataTable(prefix, 'Objects', objectData, colDefinitions)}
@@ -435,7 +445,7 @@ function generateDataTable(prefix, tableType, data, colDefinitions) {
`;
@@ -583,14 +593,22 @@ function deleteListedExecute() {
// -----------------------------------------------------------------------------
// Main sequence
-// show spinning icon
-showSpinner()
-// Start updater on page load
-$(document).ready(function () {
- setTimeout(() => {
- updater();
- }, 100);
-
-});
+// -----------------------------------------------------------------------------
+// Recurring function to monitor the URL and reinitialize if needed
+function updater() {
+ initFields();
+
+ // Run updater again after delay
+ setTimeout(updater, 200);
+}
+
+// if visible, load immediately, if not start updater
+if (!$('.plugin-content:visible').length) {
+ updater();
+}
+else
+{
+ initFields();
+}
- ${tableType !== 'Events' ? `` : ''}
+ ${tableType !== 'Events' ? `` : ''}