FE+BE: use of new sessions endpoint

Signed-off-by: jokob-sk <jokob.sk@gmail.com>
This commit is contained in:
jokob-sk
2026-01-03 10:54:10 +11:00
parent 44c2297c25
commit 039189ff4b
8 changed files with 263 additions and 198 deletions

View File

@@ -664,7 +664,9 @@ body
border-right: 5px solid #606060;
}
.fc-ltr .fc-time-grid .fc-event-container {
margin: 0 2.5% 0 0px !important;
}
/* -----------------------------------------------------------------------------
Notification float banner

View File

@@ -210,14 +210,14 @@ function getDeviceData() {
groupSettings.forEach(setting => {
const column = $('<div>'); // Create a column for each setting (Bootstrap column)
console.log(setting);
// console.log(setting);
// Get the field data (replace 'NEWDEV_' prefix from the key)
fieldData = deviceData[setting.setKey.replace('NEWDEV_', '')]
fieldData = fieldData == null ? "" : fieldData;
fieldOptionsOverride = null;
console.log(setting.setKey);
// console.log(setting.setKey);
// console.log(fieldData);
// Additional form elements like the random MAC address button for devMac

View File

@@ -30,51 +30,72 @@
<script>
// -----------------------------------------------------------------------------
function loadEventsData() {
const hideConnections = $('#chkHideConnectionEvents')[0].checked;
const hideConnectionsStr = hideConnections ? 'true' : 'false';
mac = getMac()
let period = $("#period").val();
let { start, end } = getPeriodStartEnd(period);
const rawSql = `
SELECT eve_DateTime, eve_DateTime, eve_EventType, eve_IP, eve_AdditionalInfo
SELECT eve_DateTime, eve_EventType, eve_IP, eve_AdditionalInfo
FROM Events
WHERE eve_MAC = "${mac}"
AND eve_DateTime BETWEEN "${start}" AND "${end}"
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))}`;
const protocol = window.location.protocol.replace(':', '');
const host = window.location.hostname;
const port = getSetting("GRAPHQL_PORT");
const apiToken = getSetting("API_TOKEN");
// Manually load the data first
$.get(apiUrl, function (data) {
const parsed = JSON.parse(data);
const apiBase = `${protocol}://${host}:${port}`;
const url = `${apiBase}/dbquery/read`;
const rows = parsed.map(row => {
const rawDate = row.eve_DateTime;
const formattedDate = rawDate ? localizeTimestamp(rawDate) : '-';
return [
formattedDate,
row.eve_DateTime,
row.eve_EventType,
row.eve_IP,
row.eve_AdditionalInfo
];
});
$.ajax({
url: url,
method: "POST",
contentType: "application/json",
headers: {
"Authorization": `Bearer ${apiToken}`
},
data: JSON.stringify({
rawSql: btoa(rawSql)
}),
success: function (data) {
// assuming read_query returns rows directly
const rows = data["results"].map(row => {
const rawDate = row.eve_DateTime;
const formattedDate = rawDate ? localizeTimestamp(rawDate) : '-';
// Fill the table manually
const table = $('#tableEvents').DataTable();
table.clear();
table.rows.add(rows); // assuming each row is an array
table.draw();
return [
formattedDate,
row.eve_DateTime,
row.eve_EventType,
row.eve_IP,
row.eve_AdditionalInfo
];
});
hideSpinner();
const table = $('#tableEvents').DataTable();
table.clear();
table.rows.add(rows);
table.draw();
hideSpinner();
},
error: function (xhr) {
console.error("Failed to load events", xhr.responseText);
hideSpinner();
}
});
}
function initializeEventsDatatable (eventsRows) {
if ($.fn.dataTable.isDataTable('#tableEvents')) {

View File

@@ -35,95 +35,49 @@
// ---------------------------------------
// query data
function loadPresenceData()
{
// Define Presence datasource and query data
function loadPresenceData() {
const protocol = window.location.protocol.replace(":", "");
const host = window.location.hostname;
const port = getSetting("GRAPHQL_PORT");
const apiToken = getSetting("API_TOKEN");
const apiBase = `${protocol}://${host}:${port}`;
const url = `${apiBase}/sessions/calendar`;
$('#calendar').fullCalendar('removeEventSources');
$('#calendar').fullCalendar('addEventSource',
{ url: 'php/server/events.php?action=getDevicePresence&mac=' + mac});
}
// ---------------------------------------
function initializeCalendar_() {
var calendarEl = document.getElementById('calendar');
var calendar = new FullCalendar.Calendar(calendarEl, {
headerToolbar: {
left: 'prev,next today',
center: 'title',
right: 'dayGridYear,dayGridMonth,timeGridWeek'
},
initialView: 'dayGridYear',
initialDate: '2023-01-12',
editable: true,
selectable: true,
dayMaxEvents: true, // allow "more" link when too many events
// businessHours: true,
// weekends: false,
events: [
{
title: 'All Day Event',
start: '2023-01-01'
$('#calendar').fullCalendar('addEventSource', function(start, end, timezone, callback) {
$.ajax({
url: url,
method: "GET",
dataType: "json",
headers: {
"Authorization": `Bearer ${apiToken}`
},
{
title: 'Long Event',
start: '2023-01-07',
end: '2023-01-10'
data: {
start: start.format('YYYY-MM-DD'),
end: end.format('YYYY-MM-DD'),
mac: mac
},
{
groupId: 999,
title: 'Repeating Event',
start: '2023-01-09T16:00:00'
success: function(response) {
if (response && response.success) {
callback(response.sessions || []);
} else {
console.warn("Presence calendar API error:", response);
callback([]);
}
},
{
groupId: 999,
title: 'Repeating Event',
start: '2023-01-16T16:00:00'
},
{
title: 'Conference',
start: '2023-01-11',
end: '2023-01-13'
},
{
title: 'Meeting',
start: '2023-01-12T10:30:00',
end: '2023-01-12T12:30:00'
},
{
title: 'Lunch',
start: '2023-01-12T12:00:00'
},
{
title: 'Meeting',
start: '2023-01-12T14:30:00'
},
{
title: 'Happy Hour',
start: '2023-01-12T17:30:00'
},
{
title: 'Dinner',
start: '2023-01-12T20:00:00'
},
{
title: 'Birthday Party',
start: '2023-01-13T07:00:00'
},
{
title: 'Click for Google',
url: 'http://google.com/',
start: '2023-01-28'
error: function(xhr) {
console.error(
"Presence calendar request failed:",
xhr.status,
xhr.responseText
);
callback([]);
}
]
});
});
calendar.render();
}
}
// -----------------------------------------------------------------------------
function initializeCalendar() {
@@ -138,7 +92,7 @@ function initializeCalendar() {
slotDuration : '02:00:00',
slotLabelInterval : '04:00:00',
slotLabelFormat : 'H:mm',
timeFormat : 'H:mm',
timeFormat : 'H:mm',
locale : '<?= lang('Presence_CalHead_lang');?>',
header: {
left : 'prev,next today',
@@ -146,7 +100,7 @@ function initializeCalendar() {
right : 'agendaYear,agendaMonth,agendaWeek'
},
views: {
views: {
agendaYear: {
type : 'agenda',
duration : { year: 1 },
@@ -162,16 +116,7 @@ function initializeCalendar() {
},
agendaWeek: {
buttonText : '<?= lang('Presence_CalHead_week');?>',
},
agendaDay: {
type : 'agenda',
duration : { day: 1 },
buttonText : '<?= lang('Presence_CalHead_day');?>',
slotLabelFormat : 'H',
slotDuration : '01:00:00'
}
},
viewRender: function(view) {
@@ -191,40 +136,40 @@ function initializeCalendar() {
listContent[i+1].style.borderRightColor = '#808080';
}
listHeader[i].style.paddingLeft = '10px';
}
};
}
};
}
},
columnHeaderText: function(mom) {
switch ($('#calendar').fullCalendar('getView').name) {
case 'agendaYear':
if (mom.date() == 1) {
return mom.format('MMM');
} else {
return '';
case 'agendaYear':
if (mom.date() == 1) {
return mom.format('MMM');
} else {
return '';
}
break;
case 'agendaMonth':
return mom.date();
break;
case 'agendaWeek':
return mom.format ('ddd D');
break;
default:
return mom.date();
}
break;
case 'agendaMonth':
return mom.date();
break;
case 'agendaWeek':
return mom.format ('ddd D');
break;
default:
return mom.date();
}
},
eventRender: function (event, element) {
// $(element).tooltip({container: 'body', placement: 'bottom', title: event.tooltip});
element.attr ('title', event.tooltip); // Alternative tooltip
},
loading: function( isLoading, view ) {
if (isLoading) {
showSpinner()
} else {
} else {
hideSpinner()
}
}
@@ -250,7 +195,7 @@ function initDevicePresencePage() {
showSpinner();
initializeCalendar();
initializeCalendar();
loadPresenceData();
}

View File

@@ -5,7 +5,7 @@
?>
<!-- ----------------------------------------------------------------------- -->
<!-- Datatable Session -->
<table id="tableSessions" class="table table-bordered table-hover table-striped ">
@@ -53,20 +53,20 @@ function initializeSessionsDatatable (sessionsRows) {
{targets: [1,2],
"createdCell": function (td, cellData, rowData, row, col) {
// console.log(cellData);
if (!cellData.includes("missing event") && !cellData.includes("..."))
{
{
if (cellData.includes("+")) { // Check if timezone offset is present
cellData = cellData.split('+')[0]; // Remove timezone offset
}
}
// console.log(cellData);
result = localizeTimestamp(cellData);
} else
{
result = translateHTMLcodes(cellData)
}
$(td).html (result);
$(td).html (result);
} }
],
@@ -94,22 +94,57 @@ function initializeSessionsDatatable (sessionsRows) {
// INIT with polling for panel element visibility
// -----------------------------------------------
// -----------------------------------------------------------
// -----------------------------------------------------------
// Init datatable
function loadSessionsData(period){
function loadSessionsData() {
const table = $('#tableSessions').DataTable();
let period = $("#period").val()
showSpinner();
// table.clear().draw(); // Clear existing data before reloading
// Build API base
const protocol = window.location.protocol.replace(':', '');
const host = window.location.hostname;
const port = getSetting("GRAPHQL_PORT"); // or whatever port your Flask API runs on
const apiToken = getSetting("API_TOKEN");
table.ajax
.url('php/server/events.php?action=getDeviceSessions&mac=' + getMac() + '&period=' + period)
.load(function () {
const apiBase = `${protocol}://${host}:${port}`;
const url = `${apiBase}/sessions/${getMac()}?period=${encodeURIComponent(period)}`;
// Call API with Authorization header
$.ajax({
url: url,
method: "GET",
headers: {
"Authorization": `Bearer ${apiToken}`
},
success: function (data) {
table.clear();
if (data.success && data.sessions.length) {
data.sessions.forEach(session => {
table.row.add([
session.ses_DateTimeOrder,
session.ses_Connection,
session.ses_Disconnection,
session.ses_Duration,
session.ses_IP,
session.ses_Info
]);
});
}
table.draw();
hideSpinner();
});
},
error: function (xhr, status, err) {
console.error("Failed to load sessions:", err, xhr.responseText);
hideSpinner();
}
});
}
var sessionsPageInitialized = false;
// -----------------------------------------------------------
@@ -128,10 +163,9 @@ function initDeviceSessionsPage()
showSpinner();
var sessionsRows = 10;
var period = '1 month';
initializeSessionsDatatable(sessionsRows);
loadSessionsData(period);
loadSessionsData();
}
// -----------------------------------------------------------------------------
@@ -144,6 +178,6 @@ function deviceSessionsPageUpdater() {
}
// start updater
deviceSessionsPageUpdater();
deviceSessionsPageUpdater();
</script>

View File

@@ -373,7 +373,7 @@ function getLangCode() {
const LOCALE = getSetting('UI_LOCALE') || 'en-GB';
// -----------------------------------------------------------------------------
// String utilities
// DateTime utilities
// -----------------------------------------------------------------------------
function localizeTimestamp(input) {
@@ -462,6 +462,54 @@ function localizeTimestamp(input) {
}
/**
* Returns start and end date for a given period.
* @param {string} period - "1 day", "7 days", "1 month", "1 year", "100 years"
* @returns {{start: string, end: string}} - Dates in "YYYY-MM-DD HH:MM:SS" format
*/
function getPeriodStartEnd(period) {
const now = new Date();
let start = new Date(now); // default start = now
let end = new Date(now); // default end = now
switch (period) {
case "1 day":
start.setDate(now.getDate() - 1);
break;
case "7 days":
start.setDate(now.getDate() - 7);
break;
case "1 month":
start.setMonth(now.getMonth() - 1);
break;
case "1 year":
start.setFullYear(now.getFullYear() - 1);
break;
case "100 years":
start = new Date(0); // very old date for "all"
break;
default:
console.warn("Unknown period, using 1 month as default");
start.setMonth(now.getMonth() - 1);
}
// Helper function to format date as "YYYY-MM-DD HH:MM:SS"
const formatDate = (date) => {
const pad = (n) => String(n).padStart(2, "0");
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ` +
`${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`;
};
return {
start: formatDate(start),
end: formatDate(end)
};
}
// -----------------------------------------------------------------------------
// String utilities
// -----------------------------------------------------------------------------
// ----------------------------------------------------
/**