diff --git a/front/devices.php b/front/devices.php index 44a8680c..5c780ca8 100755 --- a/front/devices.php +++ b/front/devices.php @@ -159,6 +159,7 @@ var tableColumnHide = []; var tableColumnOrder = []; var tableColumnVisible = []; + headersDefaultOrder = []; // Read parameters & Initialize components callAfterAppInitialized(main) @@ -171,7 +172,7 @@ function main () { //initialize the table headers in the correct order var availableColumns = getSettingOptions("UI_device_columns").split(","); - var headersDefaultOrder = availableColumns.map(val => getString(val)); + headersDefaultOrder = availableColumns.map(val => getString(val)); var selectedColumns = JSON.parse(getSetting("UI_device_columns").replace(/'/g, '"')); // generate default order lists of given length @@ -197,18 +198,6 @@ function main () { // Concatenate the inputArray with the missingNumbers tableColumnOrder = [...tableColumnVisible, ...missingNumbers]; - // render table headers - html = ''; - - for(index = 0; index < tableColumnOrder.length; index++) - { - html += '' + headersDefaultOrder[tableColumnOrder[index]] + ''; - } - - $('#tableDevices tr').html(html); - - hideUIelements("UI_DEV_SECTIONS") - // Initialize components with parameters initializeDatatable(getUrlAnchor('my_devices')); @@ -376,12 +365,13 @@ function getDeviceStatus(item) } // ----------------------------------------------------------------------------- -function initializeDatatable_new (status) { +function initializeDatatable_n (status) { - console.log(tableColumnVisible); +console.log(tableColumnVisible); // Build GraphQL query dynamically based on tableColumnVisible +let requiredColumns = ['devMac', 'devName', 'devIsNew', 'devPresentLastScan', 'devAlertDown', 'devIsArchived'] let columnsToFetch = [ 'devMac', 'devName', 'devLastConnection', 'devIsArchived', 'devOwner', 'devType', 'devIcon', 'devFavorite', 'devGroup', 'devFirstConnection', 'devLastIP', 'devNetworkNodeMAC', @@ -391,6 +381,8 @@ let columnsToFetch = [ let selectedColumns = columnsToFetch.filter(col => tableColumnVisible.includes(col)); + + // Construct the GraphQL query let graphqlQuery = ` query { @@ -536,9 +528,10 @@ $.ajax({ } - +// --------------------------------------------------------- function initializeDatatable (status) { + if(!status) { status = 'my_devices' @@ -565,6 +558,17 @@ function initializeDatatable (status) { $('#tableDevicesBox')[0].className = 'box box-'+ color; $('#tableDevicesTitle').html (tableTitle); + // render table headers + html = ''; + + for(index = 0; index < tableColumnOrder.length; index++) + { + html += '' + headersDefaultOrder[tableColumnOrder[index]] + ''; + } + + $('#tableDevices tr').html(html); + + hideUIelements("UI_DEV_SECTIONS") for(i = 0; i < tableColumnOrder.length; i++) { @@ -575,268 +579,322 @@ function initializeDatatable (status) { } } - $.get('api/table_devices.json?nocache=' + Date.now(), function(result) { - - // refresh devices cache - devicesListAll_JSON = result["data"] - devicesListAll_JSON_str = JSON.stringify(devicesListAll_JSON) - setCache('devicesListAll_JSON', devicesListAll_JSON_str) - - // query data - getDevicesTotals(result.data); - - // Filter the data based on deviceStatus - var filteredData = filterDataByStatus(result.data, 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.data) || 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 (''+ cellData +''); - } }, - - // 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 (''+ cellData +''); - } - else - { - $(td).html (``) - } - - } }, - - // 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 (''+cellData+''); - } else { - $(td).html (''); - } - } }, - - // IP address - {targets: [mapIndx(8)], - 'createdCell': function (td, cellData, rowData, row, col) { - if (!emptyArr.includes(cellData)){ - $(td).html (` - - ${cellData} - - - - - `); - } else { - $(td).html (''); - } - } - }, - // IP address (ordeable) - {targets: [mapIndx(12)], - 'createdCell': function (td, cellData, rowData, row, col) { - if (!emptyArr.includes(cellData)){ - $(td).html (`${cellData}`); - } else { - $(td).html (''); - } - } - }, - - // Favorite - {targets: [mapIndx(4)], - 'createdCell': function (td, cellData, rowData, row, col) { - if (cellData == 1){ - $(td).html (''); - } else { - $(td).html (''); - } - } }, - - // Dates - {targets: [mapIndx(6), mapIndx(7)], - '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 - {targets: [mapIndx(9)], - 'createdCell': function (td, cellData, rowData, row, col) { - // console.log(cellData) - if (cellData == 1){ - $(td).html (''); - } 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 = '' - } else if (devData.devPresentLastScan != 1 && devData.devAlertDown == 1) - { - css = "red text-white statusDown" - icon = '' - } else if(devData.devPresentLastScan != 1) - { - css = "gray text-white statusOffline" - icon = '' - } else - { - css = "gray text-white statusUnknown" - icon = '' - } - - $(td).html (`${icon} ${cellData.replace('-', '')}`); - } }, - ], - - // Processing - 'processing' : true, - 'language' : { - processing: '
Loading...
', - emptyTable: 'No data', - "lengthMenu": "", - "search": ": ", - "paginate": { - "next": "", - "previous": "" - }, - "info": "", + // Construct the GraphQL query + let graphqlQuery = ` + query { + devices { + rowid + devMac + devName + devOwner + devType + devVendor + devFavorite + devGroup + devComments + devFirstConnection + devLastConnection + devLastIP + devStaticIP + devScan + devLogEvents + devAlertEvents + devAlertDown + devSkipRepeated + devLastNotification + devPresentLastScan + devIsNew + devLocation + devIsArchived + devParentMAC + devParentPort + devIcon + devGUID + devSite + devSSID + devSyncHubNode + devSourcePlugin + } } - }); + `; - // Save cookie Rows displayed, and Parameters rows & order - $('#tableDevices').on( 'length.dt', function ( e, settings, len ) { - setCookie ("nax_parTableRows", len, 129600); // save for 90 days - } ); + 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(result) { + + // refresh devices cache + devicesListAll_JSON = result["devices"]; + console.log(devicesListAll_JSON); - $('#tableDevices').on( 'order.dt', function () { - setCookie ("nax_parTableOrder", JSON.stringify (table.order()), 129600); // save for 90 days - } ); - - // add multi-edit button - $('#multiEditPlc').append( - ``) - - // Event listener for row selection in DataTable - $('#tableDevices').on('click', 'tr', function (e) { - setTimeout(function(){ - // Check if any row is selected - var anyRowSelected = $('#tableDevices tr.selected').length > 0; - - // Toggle visibility of element with ID 'multiEdit' - $('#multiEdit').toggle(anyRowSelected); - }, 200); - + 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); - hideSpinner(); + // 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 (''+ cellData +''); + } }, + + // 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 (''+ cellData +''); + } + else + { + $(td).html (``) + } + + } }, + + // 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 (''+cellData+''); + } else { + $(td).html (''); + } + } }, + + // IP address + {targets: [mapIndx(8)], + 'createdCell': function (td, cellData, rowData, row, col) { + if (!emptyArr.includes(cellData)){ + $(td).html (` + + ${cellData} + + + + + `); + } else { + $(td).html (''); + } + } + }, + // IP address (ordeable) + {targets: [mapIndx(12)], + 'createdCell': function (td, cellData, rowData, row, col) { + if (!emptyArr.includes(cellData)){ + $(td).html (`${cellData}`); + } else { + $(td).html (''); + } + } + }, + + // Favorite + {targets: [mapIndx(4)], + 'createdCell': function (td, cellData, rowData, row, col) { + if (cellData == 1){ + $(td).html (''); + } else { + $(td).html (''); + } + } }, + + // Dates + {targets: [mapIndx(6), mapIndx(7)], + '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 + {targets: [mapIndx(9)], + 'createdCell': function (td, cellData, rowData, row, col) { + // console.log(cellData) + if (cellData == 1){ + $(td).html (''); + } 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 = '' + } else if (devData.devPresentLastScan != 1 && devData.devAlertDown == 1) + { + css = "red text-white statusDown" + icon = '' + } else if(devData.devPresentLastScan != 1) + { + css = "gray text-white statusOffline" + icon = '' + } else + { + css = "gray text-white statusUnknown" + icon = '' + } + + $(td).html (`${icon} ${cellData.replace('-', '')}`); + } }, + ], + + // Processing + 'processing' : true, + 'language' : { + processing: '
Loading...
', + emptyTable: 'No data', + "lengthMenu": "", + "search": ": ", + "paginate": { + "next": "", + "previous": "" + }, + "info": "", + } + }); + + // Save cookie Rows displayed, and Parameters rows & order + $('#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 + $('#multiEditPlc').append( + ``) + + // Event listener for row selection in DataTable + $('#tableDevices').on('click', 'tr', function (e) { + setTimeout(function(){ + // Check if any row is selected + var anyRowSelected = $('#tableDevices tr.selected').length > 0; + + // Toggle visibility of element with ID 'multiEdit' + $('#multiEdit').toggle(anyRowSelected); + }, 200); + + + }); + + hideSpinner(); + + + } + } + ); }; diff --git a/server/graphql_server/graphql_schema.py b/server/graphql_server/graphql_schema.py index 7b4a7eac..ff88f203 100755 --- a/server/graphql_server/graphql_schema.py +++ b/server/graphql_server/graphql_schema.py @@ -17,36 +17,36 @@ folder = apiPath # Device ObjectType class Device(ObjectType): rowid = Int() - devMac = String() # This should match devMac, not devMac - devName = String() # This should match devName, not devName - devOwner = String() # This should match devOwner, not devOwner - devType = String() # This should match devType, not devType - devVendor = String() # This should match devVendor, not devVendor - devFavorite = Int() # This should match devFavorite, not devFavorite - devGroup = String() # This should match devGroup, not devGroup - devComments = String() # This should match devComments, not devComments - devFirstConnection = String() # This should match devFirstConnection, not devFirstConnection - devLastConnection = String() # This should match devLastConnection, not devLastConnection - devLastIP = String() # This should match devLastIP, not devLastIP - devStaticIP = Int() # This should match devStaticIP, not devStaticIP - devScan = Int() # This should match devScan, not devScan - devLogEvents = Int() # This should match devLogEvents, not devLogEvents - devAlertEvents = Int() # This should match devAlertEvents, not devAlertEvents - devAlertDeviceDown = Int() # This should match devAlertDeviceDown, not devAlertDown - devSkipRepeated = Int() # This should match devSkipRepeated, not devSkipRepeated - devLastNotification = String() # This should match devLastNotification, not devLastNotification - devPresentLastScan = Int() # This should match devPresentLastScan, not devPresentLastScan - devNewDevice = Int() # This should match devNewDevice, not devIsNew - devLocation = String() # This should match devLocation, not devLocation - devArchived = Int() # This should match devArchived, not devIsArchived - devNetworkNodeMACADDR = String() # This should match devNetworkNodeMACADDR, not devParentMAC - devNetworkNodePort = String() # This should match devNetworkNodePort, not devParentPort - devIcon = String() # This should match devIcon, not devIcon - devGUID = String() # This should match devGUID, not devGUID - devNetworkSite = String() # This should match devNetworkSite, not devSite - devSSID = String() # This should match devSSID, not devSSID - devSyncHubNodeName = String() # This should match devSyncHubNodeName, not devSyncHubNode - devSourcePlugin = String() # This should match devSourcePlugin, not devSourcePlugin + devMac = String() + devName = String() + devOwner = String() + devType = String() + devVendor = String() + devFavorite = Int() + devGroup = String() + devComments = String() + devFirstConnection = String() + devLastConnection = String() + devLastIP = String() + devStaticIP = Int() + devScan = Int() + devLogEvents = Int() + devAlertEvents = Int() + devAlertDown = Int() + devSkipRepeated = Int() + devLastNotification = String() + devPresentLastScan = Int() + devIsNew = Int() + devLocation = String() + devIsArchived = Int() + devParentMAC = String() + devParentPort = String() + devIcon = String() + devGUID = String() + devSite = String() + devSSID = String() + devSyncHubNode = String() + devSourcePlugin = String() class Query(ObjectType): @@ -68,7 +68,7 @@ class Query(ObjectType): # Schema Definition 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',