presence rework #1119, plugin history filter

This commit is contained in:
jokob-sk
2025-07-26 08:45:07 +10:00
parent 0265c41612
commit 170a3c0ae1
7 changed files with 186 additions and 196 deletions

View File

@@ -286,21 +286,21 @@ function main () {
// Events tab toggle conenction events
$('input').on('ifToggled', function(event){
// Hide / Show Events
if (event.currentTarget.id == 'chkHideConnectionEvents') {
getDeviceEvents();
} else {
// Activate save & restore
// activateSaveRestoreData();
// // 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();
// }
}
});
// // Ask skip notifications
// // if (event.currentTarget.id == 'chkArchived' ) {
// // askSkipNotifications();
// // }
// }
// });
}

View File

@@ -7,11 +7,11 @@
<!-- Hide Connections -->
<div class="text-center">
<label>
<input class="checkbox blue hidden" id="chkHideConnectionEvents" type="checkbox" checked>
<?= lang('DevDetail_Events_CheckBox');?>
<div class="col-sm-12 col-xs-12">
<label class="col-sm-3 col-xs-10">
<?= lang('DevDetail_Events_CheckBox');?>
</label>
<input class="checkbox blue col-sm-1 col-xs-2" id="chkHideConnectionEvents" type="checkbox" onChange="loadEventsData()">
</div>
<!-- Datatable Events -->
@@ -29,21 +29,58 @@
<script>
var eventsRows = 10;
var eventsHide = true;
var parEventsRows = 'Front_Details_Events_Rows';
var parEventsHide = 'Front_Details_Events_Hide';
var eventsRows = 10;
var eventsHide = true;
var parEventsRows = 'Front_Details_Events_Rows';
var parEventsHide = 'Front_Details_Events_Hide';
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
function loadEventsData() {
const hideConnections = $('#chkHideConnectionEvents')[0].checked;
const hideConnectionsStr = hideConnections ? 'true' : 'false';
const rawSql = `
SELECT eve_DateTime, eve_EventType, eve_IP, eve_AdditionalInfo
FROM Events
WHERE eve_MAC = "${mac}"
AND (
(eve_EventType NOT IN ("Connected", "Disconnected", "VOIDED - Connected", "VOIDED - Disconnected"))
OR "${hideConnectionsStr}" = "false"
)
`;
const apiUrl = `php/server/dbHelper.php?action=read&rawSql=${btoa(encodeURIComponent(rawSql))}`;
// Manually load the data first
$.get(apiUrl, function (data) {
const parsed = JSON.parse(data);
console.log(parsed);
const rows = parsed.map(row => {
const rawDate = row.eve_DateTime;
const formattedDate = rawDate ? localizeTimestamp(rawDate) : '-';
return [
formattedDate,
row.eve_EventType,
row.eve_IP,
row.eve_AdditionalInfo
];
});
console.log(rows);
function loadEventsData() {
// Define Events datasource and query dada
hideConnections = $('#chkHideConnectionEvents')[0].checked;
$('#tableEvents').DataTable().ajax.url('php/server/events.php?action=getDeviceEvents&mac=' + mac +'&period='+ period +'&hideConnections='+ hideConnections).load();
}
// Fill the table manually
const table = $('#tableEvents').DataTable();
table.clear();
table.rows.add(rows); // assuming each row is an array
table.draw();
});
}
function initializeSessionsDatatable () {

View File

@@ -362,18 +362,64 @@ function getLangCode() {
// -----------------------------------------------------------------------------
// String utilities
// -----------------------------------------------------------------------------
function localizeTimestamp(input) {
let tz = getSetting("TIMEZONE") || 'Europe/Berlin';
// Convert to string and trim
input = String(input || '').trim();
function localizeTimestamp(result)
{
// contains TZ in format Europe/Berlin
tz = getSetting("TIMEZONE")
// Normalize multiple spaces and remove commas
const cleaned = input.replace(',', ' ').replace(/\s+/g, ' ');
// set default if not available or app still loading
tz == "" ? tz = 'Europe/Berlin' : tz = tz;
const date = new Date(result); // Assumes result is a timestamp or ISO string
const formatter = new Intl.DateTimeFormat('default', {
// DD/MM/YYYY format check
const dateTimeParts = cleaned.split(' ');
if (dateTimeParts.length >= 2 && dateTimeParts[0].includes('/')) {
const [day, month, year] = dateTimeParts[0].split('/');
const timePart = dateTimeParts[1];
if (day && month && year && timePart) {
const isoString = `${year}-${month}-${day}T${timePart.length === 5 ? timePart + ':00' : timePart}`;
const date = new Date(isoString);
if (!isFinite(date)) return 'b-';
return new Intl.DateTimeFormat('default', {
timeZone: tz,
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: false
}).format(date);
}
}
// ISO style YYYY-MM-DD HH:mm(:ss)?
const match = cleaned.match(/^(\d{4}-\d{2}-\d{2}) (\d{2}:\d{2})(:\d{2})?$/);
if (match) {
let iso = `${match[1]}T${match[2]}${match[3] || ':00'}`;
const date = new Date(iso);
if (!isFinite(date)) return 'c-';
return new Intl.DateTimeFormat('default', {
timeZone: tz,
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: false
}).format(date);
}
// Fallback: try to parse any other string input
const date = new Date(input);
if (!isFinite(date)) return 'Failed conversion: ' + input;
return new Intl.DateTimeFormat('default', {
timeZone: tz,
year: 'numeric',
month: '2-digit',
@@ -381,12 +427,12 @@ function localizeTimestamp(result)
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: false // change to true if you want AM/PM format
});
return formatter.format(date);
hour12: false
}).format(date);
}
// ----------------------------------------------------
/**
* Replaces double quotes within single-quoted strings, then converts all single quotes to double quotes,

View File

@@ -29,7 +29,6 @@ require_once $_SERVER['DOCUMENT_ROOT'] . '/php/templates/security.php';
case 'getEvents': getEvents(); break;
case 'getDeviceSessions': getDeviceSessions(); break;
case 'getDevicePresence': getDevicePresence(); break;
case 'getDeviceEvents': getDeviceEvents(); break;
case 'getEventsCalendar': getEventsCalendar(); break;
default: logServerConsole ('Action: '. $action); break;
}
@@ -410,41 +409,4 @@ function getEventsCalendar() {
echo (json_encode($tableData));
}
//------------------------------------------------------------------------------
// Query Device events
//------------------------------------------------------------------------------
function getDeviceEvents() {
global $db;
// Request Parameters
$mac = $_REQUEST['mac'];
$periodDate = getDateFromPeriod();
$hideConnections = $_REQUEST ['hideConnections'];
// SQL
$SQL = 'SELECT eve_DateTime, eve_EventType, eve_IP, eve_AdditionalInfo
FROM Events
WHERE eve_MAC="'. $mac .'" AND eve_DateTime >= '. $periodDate .'
AND ( (eve_EventType <> "Connected" AND eve_EventType <> "Disconnected" AND
eve_EventType <> "VOIDED - Connected" AND eve_EventType <> "VOIDED - Disconnected")
OR "'. $hideConnections .'" = "false" ) ';
$result = $db->query($SQL);
// arrays of rows
$tableData = array();
while ($row = $result -> fetchArray (SQLITE3_NUM)) {
$row[0] = formatDate ($row[0]);
$tableData['data'][] = $row;
}
// Control no rows
if (empty($tableData['data'])) {
$tableData['data'] = '';
}
// Return json
echo (json_encode ($tableData));
}
?>

View File

@@ -344,7 +344,7 @@ function createTabContent(pluginObj) {
// Get data for events, objects, and history related to the plugin
const objectData = getObjectData(prefix, colDefinitions, pluginObj);
const eventData = getEventData(prefix, colDefinitions);
const eventData = getEventData(prefix, colDefinitions, pluginObj);
const historyData = getHistoryData(prefix, colDefinitions, pluginObj);
// Append the content structure for the plugin's tab to the content location
@@ -378,10 +378,10 @@ function getColumnDefinitions(pluginObj) {
return pluginObj["database_column_definitions"].filter(colDef => colDef.show);
}
function getEventData(prefix, colDefinitions) {
function getEventData(prefix, colDefinitions, pluginObj) {
// Extract event data specific to the plugin and format it for DataTables
return pluginUnprocessedEvents
.filter(event => event.Plugin === prefix) // Filter events for the specific plugin
.filter(event => event.Plugin === prefix && shouldBeShown(event, pluginObj)) // Filter events for the specific plugin
.map(event => colDefinitions.map(colDef => event[colDef.column] || '')); // Map to the defined columns
}
@@ -395,7 +395,7 @@ function getObjectData(prefix, colDefinitions, pluginObj) {
function getHistoryData(prefix, colDefinitions, pluginObj) {
return pluginHistory
.filter(history => history.Plugin === prefix) // First, filter based on the plugin prefix
.filter(history => history.Plugin === prefix && shouldBeShown(history, pluginObj)) // First, filter based on the plugin prefix
.sort((a, b) => b.Index - a.Index) // Then, sort by the Index field in descending order
.slice(0, 50) // Limit the result to the first 50 entries
.map(object =>