From f007eac6565c5db5aea88148b2e6411cf7592241 Mon Sep 17 00:00:00 2001 From: jokob-sk Date: Tue, 12 Nov 2024 23:17:20 +1100 Subject: [PATCH] GraphQl 0.121 - Pagination working --- front/devices.php | 774 ++++++++++-------------- front/js/common.js | 28 +- server/graphql_server/graphql_schema.py | 83 +-- 3 files changed, 375 insertions(+), 510 deletions(-) diff --git a/front/devices.php b/front/devices.php index 5c780ca8..6a0e71ed 100755 --- a/front/devices.php +++ b/front/devices.php @@ -364,174 +364,25 @@ function getDeviceStatus(item) return "Unknown status" } -// ----------------------------------------------------------------------------- -function initializeDatatable_n (status) { - -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', - '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 (''+ cellData +''); - }}, - - // 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 (` - ${cellData} - - `); - } else { - $(td).html(''); - } - }} - - // Other columns (Status, MAC, Date, etc.) can be similarly customized. - ], - 'processing': true, - 'language': { - processing: '
Loading...
', - emptyTable: 'No data', - "lengthMenu": "", - "search": ": ", - "paginate": { - "next": "", - "previous": "" - }, - "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( - `` - ); - - $('#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); - } -}); - +// Map column index to column name for GraphQL query +function mapColumnIndexToFieldName(index) { + const columnNames = [ + "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" + ]; + return columnNames[index] || null; } // --------------------------------------------------------- function initializeDatatable (status) { - - + if(!status) { status = 'my_devices' @@ -579,323 +430,328 @@ function initializeDatatable (status) { } } - // 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 + + var table = $('#tableDevices').DataTable({ + "serverSide": true, + "processing": true, + "ajax": { + "url": 'php/server/query_graphql.php', // PHP endpoint that proxies to the GraphQL server + "type": "POST", + "contentType": "application/json", + "data": function (d) { + // Construct GraphQL query with pagination and sorting options + let graphqlQuery = ` + query devices($options: PageQueryOptionsInput) { + devices(options: $options) { + 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 + } + 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({ - 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) { + '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) }, - // refresh devices cache - devicesListAll_JSON = result["devices"]; - console.log(devicesListAll_JSON); - - 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 (''+ 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 (''); - } - } }, + // Device Name + {targets: [mapIndx(0)], + 'createdCell': function (td, cellData, rowData, row, col) { - // 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)); - } }, + // console.log(cellData) + $(td).html (''+ cellData +''); + } }, - // Random MAC - {targets: [mapIndx(9)], - 'createdCell': function (td, cellData, rowData, row, col) { - // console.log(cellData) - if (cellData == 1){ - $(td).html (''); - } else { - $(td).html (''); - } - } }, + // Connected Devices + {targets: [mapIndx(15)], + 'createdCell': function (td, cellData, rowData, row, col) { - // Status color - {targets: [mapIndx(10)], - '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 (``) + } + + } }, - 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) - { - 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('-', '')}`); - } }, - ], + // 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 (''); + } + } }, - // Processing - 'processing' : true, - 'language' : { - processing: '
Loading...
', - emptyTable: 'No data', - "lengthMenu": "", - "search": ": ", - "paginate": { - "next": "", - "previous": "" - }, - "info": "", - } - }); + // 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' : { + emptyTable: 'No data', + "lengthMenu": "", + "search": ": ", + "paginate": { + "next": "", + "previous": "" + }, + "info": "", + }, + initComplete: function (settings, JSON) { + // Handle any additional interactions or event listeners as required // 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 - } ); + 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( - ``) + // 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; + // 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); + // Toggle visibility of element with ID 'multiEdit' + $('#multiEdit').toggle(anyRowSelected); + }, 100); + + }); - - }); - - hideSpinner(); - - - } + + hideSpinner(); + } - ); -}; + + }); + + +} + + + // ----------------------------------------------------------------------------- diff --git a/front/js/common.js b/front/js/common.js index 6f440381..3c787cc5 100755 --- a/front/js/common.js +++ b/front/js/common.js @@ -970,6 +970,19 @@ function getGuid() { // ----------------------------------------------------------------------------- // Loading Spinner overlay // ----------------------------------------------------------------------------- +spinnerHtml = ` + +
+
+
+ + + +
_text_
+
+
+ ` + function showSpinner(stringKey='Loading') { @@ -988,20 +1001,7 @@ function showSpinner(stringKey='Loading') $("#loadingSpinner").show(); } else{ - html = ` - -
-
-
- - - -
${text}
-
-
- ` - - $(".wrapper").append(html) + $(".wrapper").append(spinnerHtml.replace('_text_',text)) } } // ----------------------------------------------------------------------------- diff --git a/server/graphql_server/graphql_schema.py b/server/graphql_server/graphql_schema.py index ff88f203..bd0a6035 100755 --- a/server/graphql_server/graphql_schema.py +++ b/server/graphql_server/graphql_schema.py @@ -1,9 +1,8 @@ import graphene -from graphene import ObjectType, String, Int, Boolean, Field, List +from graphene import ObjectType, String, Int, Boolean, List, Field, InputObjectType import json import sys - # Register NetAlertX directories INSTALL_PATH="/app" 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 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 class Device(ObjectType): rowid = Int() @@ -48,50 +58,49 @@ class Device(ObjectType): devSyncHubNode = String() devSourcePlugin = String() - -class Query(ObjectType): +class DeviceResult(ObjectType): devices = List(Device) + count = Int() - def resolve_devices(self, info): - # Load JSON data only when the query executes +# Define Query Type with Pagination Support +class Query(ObjectType): + devices = Field(DeviceResult, options=PageQueryOptionsInput()) + + def resolve_devices(self, info, options=None): try: with open(folder + 'table_devices.json', 'r') as f: devices_data = json.load(f)["data"] except (FileNotFoundError, json.JSONDecodeError) as e: - mylog('error', f'[graphql_schema] Error loading devices data: {e}') - return [] + mylog('none', f'[graphql_schema] Error loading devices data: {e}') + 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 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 -# } -# });