GraphQL 0.12 - devices.php use

This commit is contained in:
jokob-sk
2024-11-11 22:45:15 +11:00
parent 39bf09c24c
commit 79fe759470
2 changed files with 361 additions and 303 deletions

View File

@@ -159,6 +159,7 @@
var tableColumnHide = []; var tableColumnHide = [];
var tableColumnOrder = []; var tableColumnOrder = [];
var tableColumnVisible = []; var tableColumnVisible = [];
headersDefaultOrder = [];
// Read parameters & Initialize components // Read parameters & Initialize components
callAfterAppInitialized(main) callAfterAppInitialized(main)
@@ -171,7 +172,7 @@ function main () {
//initialize the table headers in the correct order //initialize the table headers in the correct order
var availableColumns = getSettingOptions("UI_device_columns").split(","); 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, '"')); var selectedColumns = JSON.parse(getSetting("UI_device_columns").replace(/'/g, '"'));
// generate default order lists of given length // generate default order lists of given length
@@ -197,18 +198,6 @@ function main () {
// Concatenate the inputArray with the missingNumbers // Concatenate the inputArray with the missingNumbers
tableColumnOrder = [...tableColumnVisible, ...missingNumbers]; tableColumnOrder = [...tableColumnVisible, ...missingNumbers];
// render table headers
html = '';
for(index = 0; index < tableColumnOrder.length; index++)
{
html += '<th>' + headersDefaultOrder[tableColumnOrder[index]] + '</th>';
}
$('#tableDevices tr').html(html);
hideUIelements("UI_DEV_SECTIONS")
// Initialize components with parameters // Initialize components with parameters
initializeDatatable(getUrlAnchor('my_devices')); 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 // Build GraphQL query dynamically based on tableColumnVisible
let requiredColumns = ['devMac', 'devName', 'devIsNew', 'devPresentLastScan', 'devAlertDown', 'devIsArchived']
let columnsToFetch = [ let columnsToFetch = [
'devMac', 'devName', 'devLastConnection', 'devIsArchived', 'devOwner', 'devType', 'devMac', 'devName', 'devLastConnection', 'devIsArchived', 'devOwner', 'devType',
'devIcon', 'devFavorite', 'devGroup', 'devFirstConnection', 'devLastIP', 'devNetworkNodeMAC', 'devIcon', 'devFavorite', 'devGroup', 'devFirstConnection', 'devLastIP', 'devNetworkNodeMAC',
@@ -391,6 +381,8 @@ let columnsToFetch = [
let selectedColumns = columnsToFetch.filter(col => tableColumnVisible.includes(col)); let selectedColumns = columnsToFetch.filter(col => tableColumnVisible.includes(col));
// Construct the GraphQL query // Construct the GraphQL query
let graphqlQuery = ` let graphqlQuery = `
query { query {
@@ -536,9 +528,10 @@ $.ajax({
} }
// ---------------------------------------------------------
function initializeDatatable (status) { function initializeDatatable (status) {
if(!status) if(!status)
{ {
status = 'my_devices' status = 'my_devices'
@@ -565,6 +558,17 @@ function initializeDatatable (status) {
$('#tableDevicesBox')[0].className = 'box box-'+ color; $('#tableDevicesBox')[0].className = 'box box-'+ color;
$('#tableDevicesTitle').html (tableTitle); $('#tableDevicesTitle').html (tableTitle);
// render table headers
html = '';
for(index = 0; index < tableColumnOrder.length; index++)
{
html += '<th>' + headersDefaultOrder[tableColumnOrder[index]] + '</th>';
}
$('#tableDevices tr').html(html);
hideUIelements("UI_DEV_SECTIONS")
for(i = 0; i < tableColumnOrder.length; i++) for(i = 0; i < tableColumnOrder.length; i++)
{ {
@@ -575,268 +579,322 @@ function initializeDatatable (status) {
} }
} }
$.get('api/table_devices.json?nocache=' + Date.now(), function(result) { // Construct the GraphQL query
let graphqlQuery = `
// refresh devices cache query {
devicesListAll_JSON = result["data"] devices {
devicesListAll_JSON_str = JSON.stringify(devicesListAll_JSON) rowid
setCache('devicesListAll_JSON', devicesListAll_JSON_str) devMac
devName
// query data devOwner
getDevicesTotals(result.data); devType
devVendor
// Filter the data based on deviceStatus devFavorite
var filteredData = filterDataByStatus(result.data, deviceStatus); devGroup
devComments
// Convert JSON data into the desired format devFirstConnection
var dataArray = { devLastConnection
data: filteredData.map(function(item) { devLastIP
var originalRow = [ devStaticIP
item.devName || "", devScan
item.devOwner || "", devLogEvents
item.devType || "", devAlertEvents
item.devIcon || "", devAlertDown
item.devFavorite || "", devSkipRepeated
item.devGroup || "", devLastNotification
// --- devPresentLastScan
item.devFirstConnection || "", devIsNew
item.devLastConnection || "", devLocation
item.devLastIP || "", devIsArchived
(isRandomMAC(item.devMac)) || "", // Check if randomized MAC devParentMAC
getDeviceStatus(item) || "", devParentPort
item.devMac || "", // hidden devIcon
formatIPlong(item.devLastIP) || "", // IP orderable devGUID
item.rowid || "", devSite
item.devParentMAC || "", devSSID
getNumberOfChildren(item.devMac, result.data) || 0, devSyncHubNode
item.devLocation || "", devSourcePlugin
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
{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 ('<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' : {
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');?>",
} }
}); `;
// Save cookie Rows displayed, and Parameters rows & order console.log(graphqlQuery);
$('#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(
`<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>`)
// 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);
}); $.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) {
hideSpinner(); // 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 ('<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
{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 ('<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' : {
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');?>",
}
});
// 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(
`<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>`)
// 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();
}
}
);
}; };

View File

@@ -17,36 +17,36 @@ folder = apiPath
# Device ObjectType # Device ObjectType
class Device(ObjectType): class Device(ObjectType):
rowid = Int() rowid = Int()
devMac = String() # This should match devMac, not devMac devMac = String()
devName = String() # This should match devName, not devName devName = String()
devOwner = String() # This should match devOwner, not devOwner devOwner = String()
devType = String() # This should match devType, not devType devType = String()
devVendor = String() # This should match devVendor, not devVendor devVendor = String()
devFavorite = Int() # This should match devFavorite, not devFavorite devFavorite = Int()
devGroup = String() # This should match devGroup, not devGroup devGroup = String()
devComments = String() # This should match devComments, not devComments devComments = String()
devFirstConnection = String() # This should match devFirstConnection, not devFirstConnection devFirstConnection = String()
devLastConnection = String() # This should match devLastConnection, not devLastConnection devLastConnection = String()
devLastIP = String() # This should match devLastIP, not devLastIP devLastIP = String()
devStaticIP = Int() # This should match devStaticIP, not devStaticIP devStaticIP = Int()
devScan = Int() # This should match devScan, not devScan devScan = Int()
devLogEvents = Int() # This should match devLogEvents, not devLogEvents devLogEvents = Int()
devAlertEvents = Int() # This should match devAlertEvents, not devAlertEvents devAlertEvents = Int()
devAlertDeviceDown = Int() # This should match devAlertDeviceDown, not devAlertDown devAlertDown = Int()
devSkipRepeated = Int() # This should match devSkipRepeated, not devSkipRepeated devSkipRepeated = Int()
devLastNotification = String() # This should match devLastNotification, not devLastNotification devLastNotification = String()
devPresentLastScan = Int() # This should match devPresentLastScan, not devPresentLastScan devPresentLastScan = Int()
devNewDevice = Int() # This should match devNewDevice, not devIsNew devIsNew = Int()
devLocation = String() # This should match devLocation, not devLocation devLocation = String()
devArchived = Int() # This should match devArchived, not devIsArchived devIsArchived = Int()
devNetworkNodeMACADDR = String() # This should match devNetworkNodeMACADDR, not devParentMAC devParentMAC = String()
devNetworkNodePort = String() # This should match devNetworkNodePort, not devParentPort devParentPort = String()
devIcon = String() # This should match devIcon, not devIcon devIcon = String()
devGUID = String() # This should match devGUID, not devGUID devGUID = String()
devNetworkSite = String() # This should match devNetworkSite, not devSite devSite = String()
devSSID = String() # This should match devSSID, not devSSID devSSID = String()
devSyncHubNodeName = String() # This should match devSyncHubNodeName, not devSyncHubNode devSyncHubNode = String()
devSourcePlugin = String() # This should match devSourcePlugin, not devSourcePlugin devSourcePlugin = String()
class Query(ObjectType): class Query(ObjectType):
@@ -68,7 +68,7 @@ class Query(ObjectType):
# Schema Definition # Schema Definition
devicesSchema = graphene.Schema(query=Query) devicesSchema = graphene.Schema(query=Query)
# # Sample query
# $.ajax({ # $.ajax({
# url: 'php/server/query_graphql.php', // The PHP endpoint that proxies to the GraphQL server # url: 'php/server/query_graphql.php', // The PHP endpoint that proxies to the GraphQL server
# type: 'POST', # type: 'POST',