mirror of
https://github.com/jokob-sk/NetAlertX.git
synced 2026-04-08 03:01:29 -07:00
GraphQl 0.121 - Pagination working
This commit is contained in:
@@ -364,174 +364,25 @@ function getDeviceStatus(item)
|
|||||||
return "Unknown status"
|
return "Unknown status"
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// Map column index to column name for GraphQL query
|
||||||
function initializeDatatable_n (status) {
|
function mapColumnIndexToFieldName(index) {
|
||||||
|
const columnNames = [
|
||||||
console.log(tableColumnVisible);
|
"rowid", "devMac", "devName", "devOwner", "devType", "devVendor",
|
||||||
|
"devFavorite", "devGroup", "devComments", "devFirstConnection",
|
||||||
|
"devLastConnection", "devLastIP", "devStaticIP", "devScan", "devLogEvents",
|
||||||
// Build GraphQL query dynamically based on tableColumnVisible
|
"devAlertEvents", "devAlertDown", "devSkipRepeated", "devLastNotification",
|
||||||
let requiredColumns = ['devMac', 'devName', 'devIsNew', 'devPresentLastScan', 'devAlertDown', 'devIsArchived']
|
"devPresentLastScan", "devIsNew", "devLocation", "devIsArchived",
|
||||||
let columnsToFetch = [
|
"devParentMAC", "devParentPort", "devIcon", "devGUID", "devSite", "devSSID",
|
||||||
'devMac', 'devName', 'devLastConnection', 'devIsArchived', 'devOwner', 'devType',
|
"devSyncHubNode", "devSourcePlugin"
|
||||||
'devIcon', 'devFavorite', 'devGroup', 'devFirstConnection', 'devLastIP', 'devNetworkNodeMAC',
|
];
|
||||||
'devLocation', 'devVendor', 'devNetworkNodePort', 'devGUID', 'devSyncHubNodeName',
|
|
||||||
'devNetworkSite', 'devSSID', 'devSourcePlugin'
|
|
||||||
];
|
|
||||||
|
|
||||||
let selectedColumns = columnsToFetch.filter(col => tableColumnVisible.includes(col));
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Construct the GraphQL query
|
|
||||||
let graphqlQuery = `
|
|
||||||
query {
|
|
||||||
devices {
|
|
||||||
${selectedColumns.join('\n')}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
console.log(graphqlQuery);
|
|
||||||
|
|
||||||
|
|
||||||
$.ajax({
|
|
||||||
url: 'php/server/query_graphql.php', // PHP endpoint that proxies to the GraphQL server
|
|
||||||
type: 'POST',
|
|
||||||
contentType: 'application/json',
|
|
||||||
data: JSON.stringify({
|
|
||||||
query: graphqlQuery,
|
|
||||||
variables: {} // Optional: pass variables if needed
|
|
||||||
}),
|
|
||||||
success: function(response) {
|
|
||||||
console.log('GraphQL Response:', response);
|
|
||||||
|
|
||||||
// Handle the GraphQL response
|
|
||||||
let devicesListAll_JSON = response.data.devices;
|
|
||||||
let devicesListAll_JSON_str = JSON.stringify(devicesListAll_JSON);
|
|
||||||
setCache('devicesListAll_JSON', devicesListAll_JSON_str);
|
|
||||||
|
|
||||||
// Query data
|
|
||||||
getDevicesTotals(devicesListAll_JSON);
|
|
||||||
|
|
||||||
// Filter the data based on deviceStatus
|
|
||||||
var filteredData = filterDataByStatus(devicesListAll_JSON, deviceStatus);
|
|
||||||
|
|
||||||
// Convert JSON data into the desired format
|
|
||||||
var dataArray = {
|
|
||||||
data: filteredData.map(function(item) {
|
|
||||||
var originalRow = selectedColumns.map(function(column) {
|
|
||||||
return item[column] || "";
|
|
||||||
});
|
|
||||||
|
|
||||||
var newRow = [];
|
|
||||||
|
|
||||||
// Reorder data based on user-defined columns order
|
|
||||||
for (index = 0; index < tableColumnOrder.length; index++) {
|
|
||||||
newRow.push(originalRow[tableColumnOrder[index]]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return newRow;
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
// Initialize DataTable
|
|
||||||
if ($.fn.dataTable.isDataTable('#tableDevices')) {
|
|
||||||
var table = $('#tableDevices').DataTable();
|
|
||||||
table.clear().destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
var table = $('#tableDevices').DataTable({
|
|
||||||
'data': dataArray["data"],
|
|
||||||
'paging': true,
|
|
||||||
'lengthChange': true,
|
|
||||||
'lengthMenu': [[10, 25, 50, 100, 500, 100000], [10, 25, 50, 100, 500, getString('Device_Tablelenght_all')]],
|
|
||||||
'searching': true,
|
|
||||||
'ordering': true,
|
|
||||||
'info': true,
|
|
||||||
'autoWidth': false,
|
|
||||||
'pageLength': tableRows,
|
|
||||||
'order': tableOrder,
|
|
||||||
'select': true,
|
|
||||||
'columnDefs': [
|
|
||||||
{ visible: false, targets: tableColumnHide },
|
|
||||||
{ className: 'text-center', targets: [mapIndx(3), mapIndx(4), mapIndx(9), mapIndx(10), mapIndx(15), mapIndx(18)] },
|
|
||||||
{ width: '80px', targets: [mapIndx(6), mapIndx(7), mapIndx(15)] },
|
|
||||||
{ width: '30px', targets: [mapIndx(10), mapIndx(13), mapIndx(18)] },
|
|
||||||
{ orderData: [mapIndx(12)], targets: mapIndx(8) },
|
|
||||||
|
|
||||||
// Device Name
|
|
||||||
{ targets: [mapIndx(0)], 'createdCell': function (td, cellData, rowData) {
|
|
||||||
$(td).html ('<b class="anonymizeDev"><a href="deviceDetails.php?mac='+ rowData[mapIndx(11)] +'" class="">'+ cellData +'</a></b>');
|
|
||||||
}},
|
|
||||||
|
|
||||||
// Handle other column customizations (similar to the original code)
|
|
||||||
// Example for IP address formatting:
|
|
||||||
{ targets: [mapIndx(8)], 'createdCell': function (td, cellData) {
|
|
||||||
if (!emptyArr.includes(cellData)) {
|
|
||||||
$(td).html (`<span class="anonymizeIp">
|
|
||||||
<a href="http://${cellData}" class="pointer" target="_blank">${cellData}</a>
|
|
||||||
<a href="https://${cellData}" class="pointer" target="_blank"><i class="fa fa-lock "></i></a>
|
|
||||||
</span>`);
|
|
||||||
} else {
|
|
||||||
$(td).html('');
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
|
|
||||||
// Other columns (Status, MAC, Date, etc.) can be similarly customized.
|
|
||||||
],
|
|
||||||
'processing': true,
|
|
||||||
'language': {
|
|
||||||
processing: '<table><td width="130px" align="middle">Loading...</td><td><i class="ion ion-ios-loop-strong fa-spin fa-2x fa-fw"></td></table>',
|
|
||||||
emptyTable: 'No data',
|
|
||||||
"lengthMenu": "<?= lang('Device_Tablelenght');?>",
|
|
||||||
"search": "<?= lang('Device_Searchbox');?>: ",
|
|
||||||
"paginate": {
|
|
||||||
"next": "<?= lang('Device_Table_nav_next');?>",
|
|
||||||
"previous": "<?= lang('Device_Table_nav_prev');?>"
|
|
||||||
},
|
|
||||||
"info": "<?= lang('Device_Table_info');?>",
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Event listeners for row selection and saving parameters (same as the original code)
|
|
||||||
$('#tableDevices').on('length.dt', function (e, settings, len) {
|
|
||||||
setCookie ("nax_parTableRows", len, 129600); // save for 90 days
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#tableDevices').on('order.dt', function () {
|
|
||||||
setCookie ("nax_parTableOrder", JSON.stringify(table.order()), 129600); // save for 90 days
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add multi-edit button and row selection functionality
|
|
||||||
$('#multiEditPlc').append(
|
|
||||||
`<button type="submit" id="multiEdit" class="btn btn-primary" style="display:none" onclick="multiEditDevices();">
|
|
||||||
<i class="fa fa-pencil pointer"></i> ${getString("Device_MultiEdit")}
|
|
||||||
</button>`
|
|
||||||
);
|
|
||||||
|
|
||||||
$('#tableDevices').on('click', 'tr', function () {
|
|
||||||
setTimeout(function(){
|
|
||||||
var anyRowSelected = $('#tableDevices tr.selected').length > 0;
|
|
||||||
$('#multiEdit').toggle(anyRowSelected);
|
|
||||||
}, 200);
|
|
||||||
});
|
|
||||||
|
|
||||||
hideSpinner(); // Hide the loading spinner
|
|
||||||
},
|
|
||||||
error: function(xhr, status, error) {
|
|
||||||
console.error('AJAX Error:', error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
return columnNames[index] || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ---------------------------------------------------------
|
// ---------------------------------------------------------
|
||||||
function initializeDatatable (status) {
|
function initializeDatatable (status) {
|
||||||
|
|
||||||
|
|
||||||
if(!status)
|
if(!status)
|
||||||
{
|
{
|
||||||
status = 'my_devices'
|
status = 'my_devices'
|
||||||
@@ -579,323 +430,328 @@ function initializeDatatable (status) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct the GraphQL query
|
|
||||||
let graphqlQuery = `
|
var table = $('#tableDevices').DataTable({
|
||||||
query {
|
"serverSide": true,
|
||||||
devices {
|
"processing": true,
|
||||||
rowid
|
"ajax": {
|
||||||
devMac
|
"url": 'php/server/query_graphql.php', // PHP endpoint that proxies to the GraphQL server
|
||||||
devName
|
"type": "POST",
|
||||||
devOwner
|
"contentType": "application/json",
|
||||||
devType
|
"data": function (d) {
|
||||||
devVendor
|
// Construct GraphQL query with pagination and sorting options
|
||||||
devFavorite
|
let graphqlQuery = `
|
||||||
devGroup
|
query devices($options: PageQueryOptionsInput) {
|
||||||
devComments
|
devices(options: $options) {
|
||||||
devFirstConnection
|
devices {
|
||||||
devLastConnection
|
rowid
|
||||||
devLastIP
|
devMac
|
||||||
devStaticIP
|
devName
|
||||||
devScan
|
devOwner
|
||||||
devLogEvents
|
devType
|
||||||
devAlertEvents
|
devVendor
|
||||||
devAlertDown
|
devFavorite
|
||||||
devSkipRepeated
|
devGroup
|
||||||
devLastNotification
|
devComments
|
||||||
devPresentLastScan
|
devFirstConnection
|
||||||
devIsNew
|
devLastConnection
|
||||||
devLocation
|
devLastIP
|
||||||
devIsArchived
|
devStaticIP
|
||||||
devParentMAC
|
devScan
|
||||||
devParentPort
|
devLogEvents
|
||||||
devIcon
|
devAlertEvents
|
||||||
devGUID
|
devAlertDown
|
||||||
devSite
|
devSkipRepeated
|
||||||
devSSID
|
devLastNotification
|
||||||
devSyncHubNode
|
devPresentLastScan
|
||||||
devSourcePlugin
|
devIsNew
|
||||||
|
devLocation
|
||||||
|
devIsArchived
|
||||||
|
devParentMAC
|
||||||
|
devParentPort
|
||||||
|
devIcon
|
||||||
|
devGUID
|
||||||
|
devSite
|
||||||
|
devSSID
|
||||||
|
devSyncHubNode
|
||||||
|
devSourcePlugin
|
||||||
|
}
|
||||||
|
count
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
console.log(d);
|
||||||
|
|
||||||
|
|
||||||
|
// Prepare query variables for pagination, sorting, and search
|
||||||
|
let query = {
|
||||||
|
"operationName": null,
|
||||||
|
"query": graphqlQuery,
|
||||||
|
"variables": {
|
||||||
|
"options": {
|
||||||
|
"page": Math.floor(d.start / d.length) + 1, // Page number (1-based)
|
||||||
|
"limit": parseInt(d.length, 10), // Page size (ensure it's an integer)
|
||||||
|
"sort": d.order && d.order[0] ? [{
|
||||||
|
"field": mapColumnIndexToFieldName(d.order[0].column), // Sort field from DataTable column
|
||||||
|
"order": d.order[0].dir.toUpperCase() // Sort direction (ASC/DESC)
|
||||||
|
}] : [], // Default to an empty array if no sorting is defined
|
||||||
|
"search": d.search.value // Search query
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return JSON.stringify(query); // Send the JSON request
|
||||||
|
},
|
||||||
|
"dataSrc": function (json) {
|
||||||
|
console.log(json);
|
||||||
|
|
||||||
|
return json.devices.devices.map(device => {
|
||||||
|
// Convert each device record into the required DataTable row format
|
||||||
|
const originalRow = [
|
||||||
|
device.devName || "",
|
||||||
|
device.devOwner || "",
|
||||||
|
device.devType || "",
|
||||||
|
device.devIcon || "",
|
||||||
|
device.devFavorite || "",
|
||||||
|
device.devGroup || "",
|
||||||
|
device.devFirstConnection || "",
|
||||||
|
device.devLastConnection || "",
|
||||||
|
device.devLastIP || "",
|
||||||
|
(isRandomMAC(device.devMac)) || "", // Custom logic for randomized MAC
|
||||||
|
getDeviceStatus(device) || "",
|
||||||
|
device.devMac || "", // hidden
|
||||||
|
formatIPlong(device.devLastIP) || "", // IP orderable
|
||||||
|
device.rowid || "",
|
||||||
|
device.devParentMAC || "",
|
||||||
|
getNumberOfChildren(device.devMac, json.devices.devices) || 0,
|
||||||
|
device.devLocation || "",
|
||||||
|
device.devVendor || "",
|
||||||
|
device.devParentPort || 0,
|
||||||
|
device.devGUID || "",
|
||||||
|
device.devSyncHubNode || "",
|
||||||
|
device.devSite || "",
|
||||||
|
device.devSSID || "",
|
||||||
|
device.devSourcePlugin || ""
|
||||||
|
];
|
||||||
|
|
||||||
|
const newRow = [];
|
||||||
|
// Reorder data based on user-defined columns order
|
||||||
|
for (let index = 0; index < tableColumnOrder.length; index++) {
|
||||||
|
newRow.push(originalRow[tableColumnOrder[index]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return newRow;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
`;
|
},
|
||||||
|
'paging' : true,
|
||||||
|
'lengthChange' : true,
|
||||||
|
'lengthMenu' : [[10, 25, 50, 100, 500, 100000], [10, 25, 50, 100, 500, getString('Device_Tablelenght_all')]],
|
||||||
|
'searching' : true,
|
||||||
|
|
||||||
console.log(graphqlQuery);
|
'ordering' : true,
|
||||||
|
'info' : true,
|
||||||
|
'autoWidth' : false,
|
||||||
|
|
||||||
|
// Parameters
|
||||||
|
'pageLength' : tableRows,
|
||||||
|
'order' : tableOrder,
|
||||||
|
'select' : true, // Enable selection
|
||||||
|
|
||||||
$.ajax({
|
'columnDefs' : [
|
||||||
url: 'php/server/query_graphql.php', // PHP endpoint that proxies to the GraphQL server
|
{visible: false, targets: tableColumnHide },
|
||||||
type: 'POST',
|
{className: 'text-center', targets: [mapIndx(3), mapIndx(4), mapIndx(9), mapIndx(10), mapIndx(15), mapIndx(18)] },
|
||||||
contentType: 'application/json',
|
{width: '80px', targets: [mapIndx(6), mapIndx(7), mapIndx(15)] },
|
||||||
data: JSON.stringify({
|
{width: '30px', targets: [mapIndx(10), mapIndx(13), mapIndx(18)] },
|
||||||
query: graphqlQuery,
|
{orderData: [mapIndx(12)], targets: mapIndx(8) },
|
||||||
variables: {} // Optional: pass variables if needed
|
|
||||||
}),
|
|
||||||
success: function(result) {
|
|
||||||
|
|
||||||
// refresh devices cache
|
// Device Name
|
||||||
devicesListAll_JSON = result["devices"];
|
{targets: [mapIndx(0)],
|
||||||
console.log(devicesListAll_JSON);
|
'createdCell': function (td, cellData, rowData, row, col) {
|
||||||
|
|
||||||
devicesListAll_JSON_str = JSON.stringify(devicesListAll_JSON)
|
|
||||||
setCache('devicesListAll_JSON', devicesListAll_JSON_str)
|
|
||||||
|
|
||||||
// query data
|
|
||||||
getDevicesTotals(result.devices);
|
|
||||||
|
|
||||||
// Filter the data based on deviceStatus
|
|
||||||
var filteredData = filterDataByStatus(result.devices, deviceStatus);
|
|
||||||
|
|
||||||
// Convert JSON data into the desired format
|
|
||||||
var dataArray = {
|
|
||||||
data: filteredData.map(function(item) {
|
|
||||||
var originalRow = [
|
|
||||||
item.devName || "",
|
|
||||||
item.devOwner || "",
|
|
||||||
item.devType || "",
|
|
||||||
item.devIcon || "",
|
|
||||||
item.devFavorite || "",
|
|
||||||
item.devGroup || "",
|
|
||||||
item.devFirstConnection || "",
|
|
||||||
item.devLastConnection || "",
|
|
||||||
item.devLastIP || "",
|
|
||||||
(isRandomMAC(item.devMac)) || "", // Check if randomized MAC
|
|
||||||
getDeviceStatus(item) || "",
|
|
||||||
item.devMac || "", // hidden
|
|
||||||
formatIPlong(item.devLastIP) || "", // IP orderable
|
|
||||||
item.rowid || "",
|
|
||||||
item.devParentMAC || "",
|
|
||||||
getNumberOfChildren(item.devMac, result.devices) || 0,
|
|
||||||
item.devLocation || "",
|
|
||||||
item.devVendor || "",
|
|
||||||
item.devParentPort || 0,
|
|
||||||
item.devGUID || "",
|
|
||||||
item.devSyncHubNode || "",
|
|
||||||
item.devSite || "",
|
|
||||||
item.devSSID || "",
|
|
||||||
item.devSourcePlugin || ""
|
|
||||||
];
|
|
||||||
|
|
||||||
var newRow = [];
|
|
||||||
|
|
||||||
// reorder data based on user-defined columns order
|
|
||||||
for (index = 0; index < tableColumnOrder.length; index++) {
|
|
||||||
newRow.push(originalRow[tableColumnOrder[index]]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return newRow;
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
// Check if the DataTable already exists
|
|
||||||
if ($.fn.dataTable.isDataTable('#tableDevices')) {
|
|
||||||
// The DataTable exists, so destroy it
|
|
||||||
var table = $('#tableDevices').DataTable();
|
|
||||||
table.clear().destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
var table =
|
|
||||||
$('#tableDevices').DataTable({
|
|
||||||
'data' : dataArray["data"],
|
|
||||||
'paging' : true,
|
|
||||||
'lengthChange' : true,
|
|
||||||
'lengthMenu' : [[10, 25, 50, 100, 500, 100000], [10, 25, 50, 100, 500, getString('Device_Tablelenght_all')]],
|
|
||||||
'searching' : true,
|
|
||||||
|
|
||||||
'ordering' : true,
|
|
||||||
'info' : true,
|
|
||||||
'autoWidth' : false,
|
|
||||||
|
|
||||||
// Parameters
|
|
||||||
'pageLength' : tableRows,
|
|
||||||
'order' : tableOrder,
|
|
||||||
'select' : true, // Enable selection
|
|
||||||
|
|
||||||
'columnDefs' : [
|
|
||||||
{visible: false, targets: tableColumnHide },
|
|
||||||
{className: 'text-center', targets: [mapIndx(3), mapIndx(4), mapIndx(9), mapIndx(10), mapIndx(15), mapIndx(18)] },
|
|
||||||
{width: '80px', targets: [mapIndx(6), mapIndx(7), mapIndx(15)] },
|
|
||||||
{width: '30px', targets: [mapIndx(10), mapIndx(13), mapIndx(18)] },
|
|
||||||
{orderData: [mapIndx(12)], targets: mapIndx(8) },
|
|
||||||
|
|
||||||
// Device Name
|
|
||||||
{targets: [mapIndx(0)],
|
|
||||||
'createdCell': function (td, cellData, rowData, row, col) {
|
|
||||||
|
|
||||||
// console.log(cellData)
|
|
||||||
$(td).html ('<b class="anonymizeDev"><a href="deviceDetails.php?mac='+ rowData[mapIndx(11)] +'" class="">'+ cellData +'</a></b>');
|
|
||||||
} },
|
|
||||||
|
|
||||||
// Connected Devices
|
|
||||||
{targets: [mapIndx(15)],
|
|
||||||
'createdCell': function (td, cellData, rowData, row, col) {
|
|
||||||
// check if this is a network device
|
|
||||||
if(getSetting("NETWORK_DEVICE_TYPES").includes(`'${rowData[mapIndx(2)]}'`) )
|
|
||||||
{
|
|
||||||
$(td).html ('<b><a href="./network.php?mac='+ rowData[mapIndx(11)] +'" class="">'+ cellData +'</a></b>');
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$(td).html (`<i class="fa-solid fa-xmark" title="${getString("Device_Table_Not_Network_Device")}"></i>`)
|
|
||||||
}
|
|
||||||
|
|
||||||
} },
|
|
||||||
|
|
||||||
// Icon
|
|
||||||
{targets: [mapIndx(3)],
|
|
||||||
'createdCell': function (td, cellData, rowData, row, col) {
|
|
||||||
if (!emptyArr.includes(cellData)){
|
|
||||||
$(td).html (atob(cellData));
|
|
||||||
} else {
|
|
||||||
$(td).html ('');
|
|
||||||
}
|
|
||||||
} },
|
|
||||||
|
|
||||||
// Full MAC
|
|
||||||
{targets: [mapIndx(11)],
|
|
||||||
'createdCell': function (td, cellData, rowData, row, col) {
|
|
||||||
if (!emptyArr.includes(cellData)){
|
|
||||||
$(td).html ('<span class="anonymizeMac">'+cellData+'</span>');
|
|
||||||
} else {
|
|
||||||
$(td).html ('');
|
|
||||||
}
|
|
||||||
} },
|
|
||||||
|
|
||||||
// IP address
|
|
||||||
{targets: [mapIndx(8)],
|
|
||||||
'createdCell': function (td, cellData, rowData, row, col) {
|
|
||||||
if (!emptyArr.includes(cellData)){
|
|
||||||
$(td).html (`<span class="anonymizeIp">
|
|
||||||
<a href="http://${cellData}" class="pointer" target="_blank">
|
|
||||||
${cellData}
|
|
||||||
</a>
|
|
||||||
<a href="https://${cellData}" class="pointer" target="_blank">
|
|
||||||
<i class="fa fa-lock "></i>
|
|
||||||
</a>
|
|
||||||
<span>`);
|
|
||||||
} else {
|
|
||||||
$(td).html ('');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// IP address (ordeable)
|
|
||||||
{targets: [mapIndx(12)],
|
|
||||||
'createdCell': function (td, cellData, rowData, row, col) {
|
|
||||||
if (!emptyArr.includes(cellData)){
|
|
||||||
$(td).html (`<span class="anonymizeIp">${cellData}<span>`);
|
|
||||||
} else {
|
|
||||||
$(td).html ('');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// Favorite
|
|
||||||
{targets: [mapIndx(4)],
|
|
||||||
'createdCell': function (td, cellData, rowData, row, col) {
|
|
||||||
if (cellData == 1){
|
|
||||||
$(td).html ('<i class="fa fa-star text-yellow" style="font-size:16px"></i>');
|
|
||||||
} else {
|
|
||||||
$(td).html ('');
|
|
||||||
}
|
|
||||||
} },
|
|
||||||
|
|
||||||
// Dates
|
// console.log(cellData)
|
||||||
{targets: [mapIndx(6), mapIndx(7)],
|
$(td).html ('<b class="anonymizeDev"><a href="deviceDetails.php?mac='+ rowData[mapIndx(11)] +'" class="">'+ cellData +'</a></b>');
|
||||||
'createdCell': function (td, cellData, rowData, row, col) {
|
} },
|
||||||
var result = cellData.toString(); // Convert to string
|
|
||||||
if (result.includes("+")) { // Check if timezone offset is present
|
|
||||||
result = result.split('+')[0]; // Remove timezone offset
|
|
||||||
}
|
|
||||||
$(td).html (translateHTMLcodes (result));
|
|
||||||
} },
|
|
||||||
|
|
||||||
// Random MAC
|
// Connected Devices
|
||||||
{targets: [mapIndx(9)],
|
{targets: [mapIndx(15)],
|
||||||
'createdCell': function (td, cellData, rowData, row, col) {
|
'createdCell': function (td, cellData, rowData, row, col) {
|
||||||
// console.log(cellData)
|
|
||||||
if (cellData == 1){
|
|
||||||
$(td).html ('<i data-toggle="tooltip" data-placement="right" title="Random MAC" style="font-size: 16px;" class="text-yellow glyphicon glyphicon-random"></i>');
|
|
||||||
} else {
|
|
||||||
$(td).html ('');
|
|
||||||
}
|
|
||||||
} },
|
|
||||||
|
|
||||||
// Status color
|
|
||||||
{targets: [mapIndx(10)],
|
// check if this is a network device
|
||||||
'createdCell': function (td, cellData, rowData, row, col) {
|
if(getSetting("NETWORK_DEVICE_TYPES").includes(`'${rowData[mapIndx(2)]}'`) )
|
||||||
|
{
|
||||||
|
$(td).html ('<b><a href="./network.php?mac='+ rowData[mapIndx(11)] +'" class="">'+ cellData +'</a></b>');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$(td).html (`<i class="fa-solid fa-xmark" title="${getString("Device_Table_Not_Network_Device")}"></i>`)
|
||||||
|
}
|
||||||
|
|
||||||
|
} },
|
||||||
|
|
||||||
devData = getDeviceDataByMac(rowData[mapIndx(11)])
|
// Icon
|
||||||
|
{targets: [mapIndx(3)],
|
||||||
|
'createdCell': function (td, cellData, rowData, row, col) {
|
||||||
|
|
||||||
|
if (!emptyArr.includes(cellData)){
|
||||||
|
$(td).html (atob(cellData));
|
||||||
|
} else {
|
||||||
|
$(td).html ('');
|
||||||
|
}
|
||||||
|
} },
|
||||||
|
|
||||||
if (devData.devPresentLastScan == 1)
|
// Full MAC
|
||||||
{
|
{targets: [mapIndx(11)],
|
||||||
css = "green text-white statusOnline"
|
'createdCell': function (td, cellData, rowData, row, col) {
|
||||||
icon = '<i class="fa-solid fa-plug"></i>'
|
if (!emptyArr.includes(cellData)){
|
||||||
} else if (devData.devPresentLastScan != 1 && devData.devAlertDown == 1)
|
$(td).html ('<span class="anonymizeMac">'+cellData+'</span>');
|
||||||
{
|
} else {
|
||||||
css = "red text-white statusDown"
|
$(td).html ('');
|
||||||
icon = '<i class="fa-solid fa-triangle-exclamation"></i>'
|
}
|
||||||
} else if(devData.devPresentLastScan != 1)
|
} },
|
||||||
{
|
|
||||||
css = "gray text-white statusOffline"
|
// IP address
|
||||||
icon = '<i class="fa-solid fa-xmark"></i>'
|
{targets: [mapIndx(8)],
|
||||||
} else
|
'createdCell': function (td, cellData, rowData, row, col) {
|
||||||
{
|
if (!emptyArr.includes(cellData)){
|
||||||
css = "gray text-white statusUnknown"
|
$(td).html (`<span class="anonymizeIp">
|
||||||
icon = '<i class="fa-solid fa-question"></i>'
|
<a href="http://${cellData}" class="pointer" target="_blank">
|
||||||
}
|
${cellData}
|
||||||
|
</a>
|
||||||
$(td).html (`<a href="deviceDetails.php?mac=${rowData[mapIndx(11)]}" class="badge bg-${css}">${icon} ${cellData.replace('-', '')}</a>`);
|
<a href="https://${cellData}" class="pointer" target="_blank">
|
||||||
} },
|
<i class="fa fa-lock "></i>
|
||||||
],
|
</a>
|
||||||
|
<span>`);
|
||||||
|
} else {
|
||||||
|
$(td).html ('');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// IP address (ordeable)
|
||||||
|
{targets: [mapIndx(12)],
|
||||||
|
'createdCell': function (td, cellData, rowData, row, col) {
|
||||||
|
if (!emptyArr.includes(cellData)){
|
||||||
|
$(td).html (`<span class="anonymizeIp">${cellData}<span>`);
|
||||||
|
} else {
|
||||||
|
$(td).html ('');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Favorite
|
||||||
|
{targets: [mapIndx(4)],
|
||||||
|
'createdCell': function (td, cellData, rowData, row, col) {
|
||||||
|
if (cellData == 1){
|
||||||
|
$(td).html ('<i class="fa fa-star text-yellow" style="font-size:16px"></i>');
|
||||||
|
} else {
|
||||||
|
$(td).html ('');
|
||||||
|
}
|
||||||
|
} },
|
||||||
|
|
||||||
// Processing
|
// Dates
|
||||||
'processing' : true,
|
{targets: [mapIndx(6), mapIndx(7)],
|
||||||
'language' : {
|
'createdCell': function (td, cellData, rowData, row, col) {
|
||||||
processing: '<table> <td width="130px" align="middle">Loading...</td><td><i class="ion ion-ios-loop-strong fa-spin fa-2x fa-fw"></td> </table>',
|
var result = cellData.toString(); // Convert to string
|
||||||
emptyTable: 'No data',
|
if (result.includes("+")) { // Check if timezone offset is present
|
||||||
"lengthMenu": "<?= lang('Device_Tablelenght');?>",
|
result = result.split('+')[0]; // Remove timezone offset
|
||||||
"search": "<?= lang('Device_Searchbox');?>: ",
|
}
|
||||||
"paginate": {
|
$(td).html (translateHTMLcodes (result));
|
||||||
"next": "<?= lang('Device_Table_nav_next');?>",
|
} },
|
||||||
"previous": "<?= lang('Device_Table_nav_prev');?>"
|
|
||||||
},
|
|
||||||
"info": "<?= lang('Device_Table_info');?>",
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
// Random MAC
|
||||||
|
{targets: [mapIndx(9)],
|
||||||
|
'createdCell': function (td, cellData, rowData, row, col) {
|
||||||
|
// console.log(cellData)
|
||||||
|
if (cellData == 1){
|
||||||
|
$(td).html ('<i data-toggle="tooltip" data-placement="right" title="Random MAC" style="font-size: 16px;" class="text-yellow glyphicon glyphicon-random"></i>');
|
||||||
|
} else {
|
||||||
|
$(td).html ('');
|
||||||
|
}
|
||||||
|
} },
|
||||||
|
|
||||||
|
// Status color
|
||||||
|
{targets: [mapIndx(10)],
|
||||||
|
'createdCell': function (td, cellData, rowData, row, col) {
|
||||||
|
|
||||||
|
devData = getDeviceDataByMac(rowData[mapIndx(11)])
|
||||||
|
|
||||||
|
if (devData.devPresentLastScan == 1)
|
||||||
|
{
|
||||||
|
css = "green text-white statusOnline"
|
||||||
|
icon = '<i class="fa-solid fa-plug"></i>'
|
||||||
|
} else if (devData.devPresentLastScan != 1 && devData.devAlertDown == 1)
|
||||||
|
{
|
||||||
|
css = "red text-white statusDown"
|
||||||
|
icon = '<i class="fa-solid fa-triangle-exclamation"></i>'
|
||||||
|
} else if(devData.devPresentLastScan != 1)
|
||||||
|
{
|
||||||
|
css = "gray text-white statusOffline"
|
||||||
|
icon = '<i class="fa-solid fa-xmark"></i>'
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
css = "gray text-white statusUnknown"
|
||||||
|
icon = '<i class="fa-solid fa-question"></i>'
|
||||||
|
}
|
||||||
|
|
||||||
|
$(td).html (`<a href="deviceDetails.php?mac=${rowData[mapIndx(11)]}" class="badge bg-${css}">${icon} ${cellData.replace('-', '')}</a>`);
|
||||||
|
} },
|
||||||
|
],
|
||||||
|
|
||||||
|
// Processing
|
||||||
|
'processing' : true,
|
||||||
|
'language' : {
|
||||||
|
emptyTable: 'No data',
|
||||||
|
"lengthMenu": "<?= lang('Device_Tablelenght');?>",
|
||||||
|
"search": "<?= lang('Device_Searchbox');?>: ",
|
||||||
|
"paginate": {
|
||||||
|
"next": "<?= lang('Device_Table_nav_next');?>",
|
||||||
|
"previous": "<?= lang('Device_Table_nav_prev');?>"
|
||||||
|
},
|
||||||
|
"info": "<?= lang('Device_Table_info');?>",
|
||||||
|
},
|
||||||
|
initComplete: function (settings, JSON) {
|
||||||
|
// Handle any additional interactions or event listeners as required
|
||||||
// Save cookie Rows displayed, and Parameters rows & order
|
// Save cookie Rows displayed, and Parameters rows & order
|
||||||
$('#tableDevices').on( 'length.dt', function ( e, settings, len ) {
|
$('#tableDevices').on( 'length.dt', function ( e, settings, len ) {
|
||||||
setCookie ("nax_parTableRows", len, 129600); // save for 90 days
|
setCookie ("nax_parTableRows", len, 129600); // save for 90 days
|
||||||
} );
|
} );
|
||||||
|
|
||||||
$('#tableDevices').on( 'order.dt', function () {
|
$('#tableDevices').on( 'order.dt', function () {
|
||||||
setCookie ("nax_parTableOrder", JSON.stringify (table.order()), 129600); // save for 90 days
|
setCookie ("nax_parTableOrder", JSON.stringify (table.order()), 129600); // save for 90 days
|
||||||
} );
|
} );
|
||||||
|
|
||||||
// add multi-edit button
|
// add multi-edit button
|
||||||
$('#multiEditPlc').append(
|
$('#multiEditPlc').append(
|
||||||
`<button type="submit" id="multiEdit" class="btn btn-primary" style="display:none" onclick="multiEditDevices();">
|
`<button type="submit" id="multiEdit" class="btn btn-primary" style="display:none" onclick="multiEditDevices();">
|
||||||
<i class="fa fa-pencil pointer" ></i> ${getString("Device_MultiEdit")}
|
<i class="fa fa-pencil pointer" ></i> ${getString("Device_MultiEdit")}
|
||||||
</button>`)
|
</button>`)
|
||||||
|
|
||||||
// Event listener for row selection in DataTable
|
// Event listener for row selection in DataTable
|
||||||
$('#tableDevices').on('click', 'tr', function (e) {
|
$('#tableDevices').on('click', 'tr', function (e) {
|
||||||
setTimeout(function(){
|
setTimeout(function(){
|
||||||
// Check if any row is selected
|
// Check if any row is selected
|
||||||
var anyRowSelected = $('#tableDevices tr.selected').length > 0;
|
var anyRowSelected = $('#tableDevices tr.selected').length > 0;
|
||||||
|
|
||||||
// Toggle visibility of element with ID 'multiEdit'
|
// Toggle visibility of element with ID 'multiEdit'
|
||||||
$('#multiEdit').toggle(anyRowSelected);
|
$('#multiEdit').toggle(anyRowSelected);
|
||||||
}, 200);
|
}, 100);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
});
|
hideSpinner();
|
||||||
|
|
||||||
hideSpinner();
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
|
||||||
};
|
});
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -970,6 +970,19 @@ function getGuid() {
|
|||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// Loading Spinner overlay
|
// Loading Spinner overlay
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
spinnerHtml = `
|
||||||
|
<!-- spinner -->
|
||||||
|
<div id="loadingSpinner" style="display: block">
|
||||||
|
<div class="pa_semitransparent-panel"></div>
|
||||||
|
<div class="panel panel-default pa_spinner">
|
||||||
|
<table>
|
||||||
|
<td width="130px" align="middle">_text_</td>
|
||||||
|
<td><i class="ion ion-ios-loop-strong fa-spin fa-2x fa-fw"></td>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
|
||||||
function showSpinner(stringKey='Loading')
|
function showSpinner(stringKey='Loading')
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -988,20 +1001,7 @@ function showSpinner(stringKey='Loading')
|
|||||||
$("#loadingSpinner").show();
|
$("#loadingSpinner").show();
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
html = `
|
$(".wrapper").append(spinnerHtml.replace('_text_',text))
|
||||||
<!-- spinner -->
|
|
||||||
<div id="loadingSpinner" style="display: block">
|
|
||||||
<div class="pa_semitransparent-panel"></div>
|
|
||||||
<div class="panel panel-default pa_spinner">
|
|
||||||
<table>
|
|
||||||
<td width="130px" align="middle">${text}</td>
|
|
||||||
<td><i class="ion ion-ios-loop-strong fa-spin fa-2x fa-fw"></td>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
|
|
||||||
$(".wrapper").append(html)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import graphene
|
import graphene
|
||||||
from graphene import ObjectType, String, Int, Boolean, Field, List
|
from graphene import ObjectType, String, Int, Boolean, List, Field, InputObjectType
|
||||||
import json
|
import json
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
|
||||||
# Register NetAlertX directories
|
# Register NetAlertX directories
|
||||||
INSTALL_PATH="/app"
|
INSTALL_PATH="/app"
|
||||||
sys.path.extend([f"{INSTALL_PATH}/server"])
|
sys.path.extend([f"{INSTALL_PATH}/server"])
|
||||||
@@ -14,6 +13,17 @@ from const import apiPath
|
|||||||
# Define a base URL with the user's home directory
|
# Define a base URL with the user's home directory
|
||||||
folder = apiPath
|
folder = apiPath
|
||||||
|
|
||||||
|
# Pagination and Sorting Input Types
|
||||||
|
class SortOptionsInput(InputObjectType):
|
||||||
|
field = String()
|
||||||
|
order = String()
|
||||||
|
|
||||||
|
class PageQueryOptionsInput(InputObjectType):
|
||||||
|
page = Int()
|
||||||
|
limit = Int()
|
||||||
|
sort = List(SortOptionsInput)
|
||||||
|
search = String()
|
||||||
|
|
||||||
# Device ObjectType
|
# Device ObjectType
|
||||||
class Device(ObjectType):
|
class Device(ObjectType):
|
||||||
rowid = Int()
|
rowid = Int()
|
||||||
@@ -48,50 +58,49 @@ class Device(ObjectType):
|
|||||||
devSyncHubNode = String()
|
devSyncHubNode = String()
|
||||||
devSourcePlugin = String()
|
devSourcePlugin = String()
|
||||||
|
|
||||||
|
class DeviceResult(ObjectType):
|
||||||
class Query(ObjectType):
|
|
||||||
devices = List(Device)
|
devices = List(Device)
|
||||||
|
count = Int()
|
||||||
|
|
||||||
def resolve_devices(self, info):
|
# Define Query Type with Pagination Support
|
||||||
# Load JSON data only when the query executes
|
class Query(ObjectType):
|
||||||
|
devices = Field(DeviceResult, options=PageQueryOptionsInput())
|
||||||
|
|
||||||
|
def resolve_devices(self, info, options=None):
|
||||||
try:
|
try:
|
||||||
with open(folder + 'table_devices.json', 'r') as f:
|
with open(folder + 'table_devices.json', 'r') as f:
|
||||||
devices_data = json.load(f)["data"]
|
devices_data = json.load(f)["data"]
|
||||||
except (FileNotFoundError, json.JSONDecodeError) as e:
|
except (FileNotFoundError, json.JSONDecodeError) as e:
|
||||||
mylog('error', f'[graphql_schema] Error loading devices data: {e}')
|
mylog('none', f'[graphql_schema] Error loading devices data: {e}')
|
||||||
return []
|
return DeviceResult(devices=[], count=0)
|
||||||
|
|
||||||
return devices_data # Directly return the data without mapping
|
total_count = len(devices_data)
|
||||||
|
|
||||||
|
# Apply pagination and sorting if options are provided
|
||||||
|
if options:
|
||||||
|
# Implement pagination and sorting here
|
||||||
|
if options.page and options.limit:
|
||||||
|
start = (options.page - 1) * options.limit
|
||||||
|
end = start + options.limit
|
||||||
|
devices_data = devices_data[start:end]
|
||||||
|
|
||||||
|
if options.sort:
|
||||||
|
for sort_option in options.sort:
|
||||||
|
devices_data = sorted(
|
||||||
|
devices_data,
|
||||||
|
key=lambda x: x.get(sort_option.field),
|
||||||
|
reverse=(sort_option.order.lower() == "desc")
|
||||||
|
)
|
||||||
|
|
||||||
|
# Filter data if a search term is provided
|
||||||
|
if options.search:
|
||||||
|
devices_data = [
|
||||||
|
device for device in devices_data
|
||||||
|
if options.search.lower() in device.get("devName", "").lower()
|
||||||
|
]
|
||||||
|
|
||||||
|
return DeviceResult(devices=devices_data, count=total_count)
|
||||||
|
|
||||||
|
|
||||||
# Schema Definition
|
# Schema Definition
|
||||||
devicesSchema = graphene.Schema(query=Query)
|
devicesSchema = graphene.Schema(query=Query)
|
||||||
|
|
||||||
# # Sample query
|
|
||||||
# $.ajax({
|
|
||||||
# url: 'php/server/query_graphql.php', // The PHP endpoint that proxies to the GraphQL server
|
|
||||||
# type: 'POST',
|
|
||||||
# contentType: 'application/json', // Send the data as JSON
|
|
||||||
# data: JSON.stringify({
|
|
||||||
# query: `
|
|
||||||
# query {
|
|
||||||
# devices {
|
|
||||||
# devMac
|
|
||||||
# devName
|
|
||||||
# devLastConnection
|
|
||||||
# devArchived
|
|
||||||
# }
|
|
||||||
# }
|
|
||||||
# `, // GraphQL query for plugins
|
|
||||||
# variables: {} // Optional, pass variables if needed
|
|
||||||
# }),
|
|
||||||
# success: function(response) {
|
|
||||||
# console.log('GraphQL Response:', response);
|
|
||||||
# // Handle the GraphQL response here
|
|
||||||
# },
|
|
||||||
# error: function(xhr, status, error) {
|
|
||||||
# console.error('AJAX Error:', error);
|
|
||||||
# // Handle errors here
|
|
||||||
# }
|
|
||||||
# });
|
|
||||||
|
|||||||
Reference in New Issue
Block a user