mirror of
https://github.com/jokob-sk/NetAlertX.git
synced 2026-03-30 23:03:03 -07:00
FE+BE: deviceDetials migration to graphQL endpoints
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
This commit is contained in:
@@ -416,9 +416,25 @@ async function renderSmallBoxes() {
|
|||||||
showSpinner();
|
showSpinner();
|
||||||
|
|
||||||
// Get data from the server
|
// Get data from the server
|
||||||
const response = await fetch(`php/server/devices.php?action=getServerDeviceData&mac=${getMac()}&period=${period}`);
|
const protocol = window.location.protocol.replace(':', '');
|
||||||
|
const host = window.location.hostname;
|
||||||
|
const apiToken = getSetting("API_TOKEN");
|
||||||
|
const port = getSetting("GRAPHQL_PORT"); // same port your Flask app runs on
|
||||||
|
|
||||||
|
const apiBase = `${protocol}://${host}:${port}`;
|
||||||
|
const url = `${apiBase}/device/${getMac()}?period=${encodeURIComponent(period)}`;
|
||||||
|
|
||||||
|
const response = await fetch(url, {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
"Authorization": `Bearer ${apiToken}`,
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`Error fetching device data: ${response.statusText}`);
|
const text = await response.text();
|
||||||
|
throw new Error(`Error fetching device data: ${response.status} ${text}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const deviceData = await response.json();
|
const deviceData = await response.json();
|
||||||
|
|||||||
@@ -1,280 +1,319 @@
|
|||||||
<?php
|
<?php
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// check if authenticated
|
// check if authenticated
|
||||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/php/templates/security.php';
|
require_once $_SERVER["DOCUMENT_ROOT"] . "/php/templates/security.php"; ?>
|
||||||
?>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="row" id="deviceDetailsEdit">
|
<div class="row" id="deviceDetailsEdit">
|
||||||
<div class="box-body form-horizontal">
|
<div class="box-body form-horizontal">
|
||||||
<form id="edit-form">
|
<form id="edit-form">
|
||||||
<!-- Form fields will be appended here -->
|
<!-- Form fields will be appended here -->
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<!-- Buttons -->
|
<!-- Buttons -->
|
||||||
<div class="col-xs-12">
|
<div class="col-xs-12">
|
||||||
<div class="pull-right">
|
<div class="pull-right">
|
||||||
<button type="button"
|
<button type="button"
|
||||||
class="btn btn-default pa-btn pa-btn-delete"
|
class="btn btn-default pa-btn pa-btn-delete"
|
||||||
style="margin-left:0px;"
|
style="margin-left:0px;"
|
||||||
id="btnDelete"
|
id="btnDelete"
|
||||||
onclick="askDeleteDevice()">
|
onclick="askDeleteDevice()">
|
||||||
<i class="fas fa-trash-alt"></i>
|
<i class="fas fa-trash-alt"></i>
|
||||||
<?= lang('DevDetail_button_Delete');?>
|
<?= lang("DevDetail_button_Delete") ?>
|
||||||
</button>
|
</button>
|
||||||
<button type="button"
|
<button type="button"
|
||||||
class="btn btn-primary pa-btn"
|
class="btn btn-primary pa-btn"
|
||||||
style="margin-left:6px; "
|
style="margin-left:6px; "
|
||||||
id="btnSave"
|
id="btnSave"
|
||||||
onclick="setDeviceData()" >
|
onclick="setDeviceData()" >
|
||||||
<i class="fas fa-save"></i>
|
<i class="fas fa-save"></i>
|
||||||
<?= lang('DevDetail_button_Save');?>
|
<?= lang("DevDetail_button_Save") ?>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<script defer>
|
<script defer>
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
// Get plugin and settings data from API endpoints
|
// Get plugin and settings data from API endpoints
|
||||||
function getDeviceData(){
|
function getDeviceData() {
|
||||||
|
|
||||||
mac = getMac()
|
mac = getMac()
|
||||||
|
|
||||||
console.log(mac);
|
console.log(mac);
|
||||||
|
|
||||||
// get data from server
|
const protocol = window.location.protocol.replace(':', '');
|
||||||
$.get('php/server/devices.php?action=getServerDeviceData&mac='+ mac + '&period='+ period, function(data) {
|
const host = window.location.hostname;
|
||||||
|
const apiToken = getSetting("API_TOKEN");
|
||||||
|
const port = getSetting("GRAPHQL_PORT");
|
||||||
|
|
||||||
// show loading dialog
|
const apiBase = `${protocol}://${host}:${port}`;
|
||||||
showSpinner()
|
const url = `${apiBase}/device/${mac}?period=${encodeURIComponent(period)}`;
|
||||||
|
|
||||||
var deviceData = JSON.parse(data);
|
// get data from server
|
||||||
|
$.ajax({
|
||||||
|
url: url,
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
"Authorization": `Bearer ${apiToken}`
|
||||||
|
},
|
||||||
|
dataType: "json",
|
||||||
|
success: function(deviceData) {
|
||||||
|
|
||||||
// some race condition, need to implement delay
|
// some race condition, need to implement delay
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
$.get('php/server/query_json.php', {
|
|
||||||
file: 'table_settings.json',
|
|
||||||
// nocache: Date.now()
|
|
||||||
},
|
|
||||||
function(res) {
|
|
||||||
|
|
||||||
settingsData = res["data"];
|
const query = `
|
||||||
|
query($filters: [FilterOptionsInput]) {
|
||||||
|
settings(filters: $filters) {
|
||||||
|
settings {
|
||||||
|
setKey
|
||||||
|
setName
|
||||||
|
setDescription
|
||||||
|
setType
|
||||||
|
setOptions
|
||||||
|
setGroup
|
||||||
|
setValue
|
||||||
|
setEvents
|
||||||
|
setOverriddenByEnv
|
||||||
|
}
|
||||||
|
count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
// columns to hide
|
// I need to get a subset of settings only (performance improvement), but include both NEWDEV and CUSTPROP settings
|
||||||
hiddenFields = ["NEWDEV_devScan", "NEWDEV_devPresentLastScan" ]
|
const variables = {
|
||||||
// columns to disable/readonly - conditional depending if a new dummy device is created
|
filters: [
|
||||||
disabledFields = mac == "new" ? ["NEWDEV_devLastNotification", "NEWDEV_devFirstConnection", "NEWDEV_devLastConnection"] : ["NEWDEV_devLastNotification", "NEWDEV_devFirstConnection", "NEWDEV_devLastConnection", "NEWDEV_devMac", "NEWDEV_devLastIP", "NEWDEV_devSyncHubNode", "NEWDEV_devFQDN" ];
|
{ filterColumn: "setGroup", filterValue: "NEWDEV" },
|
||||||
|
{ filterColumn: "setGroup", filterValue: "CUSTPROP" }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
// Grouping of fields into categories with associated documentation links
|
const graphQlUrl = `${apiBase}/graphql`;
|
||||||
const fieldGroups = {
|
|
||||||
// Group for device main information
|
$.ajax({
|
||||||
DevDetail_MainInfo_Title: {
|
url: graphQlUrl,
|
||||||
|
method: "POST",
|
||||||
|
contentType: "application/json",
|
||||||
|
headers: { "Authorization": `Bearer ${apiToken}` },
|
||||||
|
data: JSON.stringify({ query, variables }),
|
||||||
|
success: function(response) {
|
||||||
|
|
||||||
|
const settingsData = response.data.settings.settings;
|
||||||
|
|
||||||
|
// columns to hide
|
||||||
|
hiddenFields = ["NEWDEV_devScan", "NEWDEV_devPresentLastScan"]
|
||||||
|
// columns to disable/readonly - conditional depending if a new dummy device is created
|
||||||
|
disabledFields = mac == "new" ? ["NEWDEV_devLastNotification", "NEWDEV_devFirstConnection", "NEWDEV_devLastConnection"] : ["NEWDEV_devLastNotification", "NEWDEV_devFirstConnection", "NEWDEV_devLastConnection", "NEWDEV_devMac", "NEWDEV_devLastIP", "NEWDEV_devSyncHubNode", "NEWDEV_devFQDN"];
|
||||||
|
|
||||||
|
// Grouping of fields into categories with associated documentation links
|
||||||
|
const fieldGroups = {
|
||||||
|
// Group for device main information
|
||||||
|
DevDetail_MainInfo_Title: {
|
||||||
data: ["devMac", "devLastIP", "devName", "devOwner", "devType", "devVendor", "devGroup", "devIcon", "devLocation", "devComments"],
|
data: ["devMac", "devLastIP", "devName", "devOwner", "devType", "devVendor", "devGroup", "devIcon", "devLocation", "devComments"],
|
||||||
docs: "https://github.com/jokob-sk/NetAlertX/blob/main/docs/DEVICE_MANAGEMENT.md",
|
docs: "https://github.com/jokob-sk/NetAlertX/blob/main/docs/DEVICE_MANAGEMENT.md",
|
||||||
iconClass: "fa fa-pencil",
|
iconClass: "fa fa-pencil",
|
||||||
inputGroupClasses: "field-group main-group col-lg-4 col-sm-6 col-xs-12",
|
inputGroupClasses: "field-group main-group col-lg-4 col-sm-6 col-xs-12",
|
||||||
labelClasses: "col-sm-4 col-xs-12 control-label",
|
labelClasses: "col-sm-4 col-xs-12 control-label",
|
||||||
inputClasses: "col-sm-8 col-xs-12 input-group"
|
inputClasses: "col-sm-8 col-xs-12 input-group"
|
||||||
},
|
},
|
||||||
// Group for event and alert settings
|
// Group for event and alert settings
|
||||||
DevDetail_EveandAl_Title: {
|
DevDetail_EveandAl_Title: {
|
||||||
data: ["devAlertEvents", "devAlertDown", "devSkipRepeated", "devReqNicsOnline", "devChildrenNicsDynamic"],
|
data: ["devAlertEvents", "devAlertDown", "devSkipRepeated", "devReqNicsOnline", "devChildrenNicsDynamic"],
|
||||||
docs: "https://github.com/jokob-sk/NetAlertX/blob/main/docs/NOTIFICATIONS.md",
|
docs: "https://github.com/jokob-sk/NetAlertX/blob/main/docs/NOTIFICATIONS.md",
|
||||||
iconClass: "fa fa-bell",
|
iconClass: "fa fa-bell",
|
||||||
inputGroupClasses: "field-group alert-group col-lg-4 col-sm-6 col-xs-12",
|
inputGroupClasses: "field-group alert-group col-lg-4 col-sm-6 col-xs-12",
|
||||||
labelClasses: "col-sm-4 col-xs-12 control-label",
|
labelClasses: "col-sm-4 col-xs-12 control-label",
|
||||||
inputClasses: "col-sm-8 col-xs-12 input-group"
|
inputClasses: "col-sm-8 col-xs-12 input-group"
|
||||||
},
|
},
|
||||||
// Group for network details
|
// Group for network details
|
||||||
DevDetail_MainInfo_Network_Title: {
|
DevDetail_MainInfo_Network_Title: {
|
||||||
data: ["devParentMAC", "devParentRelType", "devParentPort", "devSSID", "devSite", "devSyncHubNode"],
|
data: ["devParentMAC", "devParentRelType", "devParentPort", "devSSID", "devSite", "devSyncHubNode"],
|
||||||
docs: "https://github.com/jokob-sk/NetAlertX/blob/main/docs/NETWORK_TREE.md",
|
docs: "https://github.com/jokob-sk/NetAlertX/blob/main/docs/NETWORK_TREE.md",
|
||||||
iconClass: "fa fa-sitemap fa-rotate-270",
|
iconClass: "fa fa-sitemap fa-rotate-270",
|
||||||
inputGroupClasses: "field-group network-group col-lg-4 col-sm-6 col-xs-12",
|
inputGroupClasses: "field-group network-group col-lg-4 col-sm-6 col-xs-12",
|
||||||
labelClasses: "col-sm-4 col-xs-12 control-label",
|
labelClasses: "col-sm-4 col-xs-12 control-label",
|
||||||
inputClasses: "col-sm-8 col-xs-12 input-group"
|
inputClasses: "col-sm-8 col-xs-12 input-group"
|
||||||
},
|
},
|
||||||
// Group for other fields like static IP, archived status, etc.
|
// Group for other fields like static IP, archived status, etc.
|
||||||
DevDetail_DisplayFields_Title: {
|
DevDetail_DisplayFields_Title: {
|
||||||
data: ["devStaticIP", "devIsNew", "devFavorite", "devIsArchived"],
|
data: ["devStaticIP", "devIsNew", "devFavorite", "devIsArchived"],
|
||||||
docs: "https://github.com/jokob-sk/NetAlertX/blob/main/docs/DEVICE_DISPLAY_SETTINGS.md",
|
docs: "https://github.com/jokob-sk/NetAlertX/blob/main/docs/DEVICE_DISPLAY_SETTINGS.md",
|
||||||
iconClass: "fa fa-list-check",
|
iconClass: "fa fa-list-check",
|
||||||
inputGroupClasses: "field-group display-group col-lg-4 col-sm-6 col-xs-12",
|
inputGroupClasses: "field-group display-group col-lg-4 col-sm-6 col-xs-12",
|
||||||
labelClasses: "col-sm-4 col-xs-12 control-label",
|
labelClasses: "col-sm-4 col-xs-12 control-label",
|
||||||
inputClasses: "col-sm-8 col-xs-12 input-group"
|
inputClasses: "col-sm-8 col-xs-12 input-group"
|
||||||
},
|
},
|
||||||
// Group for session information
|
// Group for session information
|
||||||
DevDetail_SessionInfo_Title: {
|
DevDetail_SessionInfo_Title: {
|
||||||
data: ["devStatus", "devLastConnection", "devFirstConnection", "devFQDN"],
|
data: ["devStatus", "devLastConnection", "devFirstConnection", "devFQDN"],
|
||||||
docs: "https://github.com/jokob-sk/NetAlertX/blob/main/docs/SESSION_INFO.md",
|
docs: "https://github.com/jokob-sk/NetAlertX/blob/main/docs/SESSION_INFO.md",
|
||||||
iconClass: "fa fa-calendar",
|
iconClass: "fa fa-calendar",
|
||||||
inputGroupClasses: "field-group session-group col-lg-4 col-sm-6 col-xs-12",
|
inputGroupClasses: "field-group session-group col-lg-4 col-sm-6 col-xs-12",
|
||||||
labelClasses: "col-sm-4 col-xs-12 control-label",
|
labelClasses: "col-sm-4 col-xs-12 control-label",
|
||||||
inputClasses: "col-sm-8 col-xs-12 input-group"
|
inputClasses: "col-sm-8 col-xs-12 input-group"
|
||||||
},
|
},
|
||||||
// Group for Children.
|
// Group for Children.
|
||||||
DevDetail_Children_Title: {
|
DevDetail_Children_Title: {
|
||||||
data: ["devChildrenDynamic"],
|
data: ["devChildrenDynamic"],
|
||||||
docs: "https://github.com/jokob-sk/NetAlertX/blob/main/docs/NETWORK_TREE.md",
|
docs: "https://github.com/jokob-sk/NetAlertX/blob/main/docs/NETWORK_TREE.md",
|
||||||
iconClass: "fa fa-list",
|
iconClass: "fa fa-list",
|
||||||
inputGroupClasses: "field-group cutprop-group col-lg-6 col-sm-12 col-xs-12",
|
inputGroupClasses: "field-group cutprop-group col-lg-6 col-sm-12 col-xs-12",
|
||||||
labelClasses: "col-sm-12 col-xs-12 control-label",
|
labelClasses: "col-sm-12 col-xs-12 control-label",
|
||||||
inputClasses: "col-sm-12 col-xs-12 input-group"
|
inputClasses: "col-sm-12 col-xs-12 input-group"
|
||||||
},
|
},
|
||||||
// Group for Custom properties.
|
// Group for Custom properties.
|
||||||
DevDetail_CustomProperties_Title: {
|
DevDetail_CustomProperties_Title: {
|
||||||
data: ["devCustomProps"],
|
data: ["devCustomProps"],
|
||||||
docs: "https://github.com/jokob-sk/NetAlertX/blob/main/docs/CUSTOM_PROPERTIES.md",
|
docs: "https://github.com/jokob-sk/NetAlertX/blob/main/docs/CUSTOM_PROPERTIES.md",
|
||||||
iconClass: "fa fa-list",
|
iconClass: "fa fa-list",
|
||||||
inputGroupClasses: "field-group cutprop-group col-lg-6 col-sm-12 col-xs-12",
|
inputGroupClasses: "field-group cutprop-group col-lg-6 col-sm-12 col-xs-12",
|
||||||
labelClasses: "col-sm-12 col-xs-12 control-label",
|
labelClasses: "col-sm-12 col-xs-12 control-label",
|
||||||
inputClasses: "col-sm-12 col-xs-12 input-group"
|
inputClasses: "col-sm-12 col-xs-12 input-group"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Filter settings data to get relevant settings
|
// Filter settings data to get relevant settings
|
||||||
const relevantSettings = settingsData.filter(set =>
|
const relevantSettings = settingsData.filter(set =>
|
||||||
set.setGroup === "NEWDEV" && // Filter for settings in the "NEWDEV" group
|
set.setGroup === "NEWDEV" && // Filter for settings in the "NEWDEV" group
|
||||||
set.setKey.includes("_dev") && // Include settings with '_dev' in the key
|
set.setKey.includes("_dev") && // Include settings with '_dev' in the key
|
||||||
!hiddenFields.includes(set.setKey) && // Exclude settings listed in hiddenFields
|
!hiddenFields.includes(set.setKey) && // Exclude settings listed in hiddenFields
|
||||||
!set.setKey.includes("__metadata") // Exclude metadata fields
|
!set.setKey.includes("__metadata") // Exclude metadata fields
|
||||||
);
|
);
|
||||||
|
|
||||||
// Function to generate the form
|
// Function to generate the form
|
||||||
const generateSimpleForm = settings => {
|
const generateSimpleForm = settings => {
|
||||||
const form = $('#edit-form'); // Get the form element to append generated fields
|
const form = $('#edit-form'); // Get the form element to append generated fields
|
||||||
|
|
||||||
// Loop over each field group to generate sections for each category
|
// Loop over each field group to generate sections for each category
|
||||||
Object.entries(fieldGroups).forEach(([groupName, obj]) => {
|
Object.entries(fieldGroups).forEach(([groupName, obj]) => {
|
||||||
const groupDiv = $('<div>').addClass(obj.inputGroupClasses); // Create a div for each group with responsive Bootstrap classes
|
const groupDiv = $('<div>').addClass(obj.inputGroupClasses); // Create a div for each group with responsive Bootstrap classes
|
||||||
|
|
||||||
// Add group title and documentation link
|
// Add group title and documentation link
|
||||||
groupDiv.append(`<h5><i class="${obj.iconClass}"></i> ${getString(groupName)}
|
groupDiv.append(`<h5><i class="${obj.iconClass}"></i> ${getString(groupName)}
|
||||||
<span class="helpIconSmallTopRight">
|
<span class="helpIconSmallTopRight">
|
||||||
<a target="_blank" href="${obj.docs}">
|
<a target="_blank" href="${obj.docs}">
|
||||||
<i class="fa fa-circle-question"></i>
|
<i class="fa fa-circle-question"></i>
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
</h5>
|
</h5>
|
||||||
<hr>
|
<hr>
|
||||||
`);
|
`);
|
||||||
|
|
||||||
// Filter relevant settings for the current group
|
// Filter relevant settings for the current group
|
||||||
const groupSettings = settings.filter(set => obj.data.includes(set.setKey.replace('NEWDEV_', '')));
|
const groupSettings = settings.filter(set => obj.data.includes(set.setKey.replace('NEWDEV_', '')));
|
||||||
|
|
||||||
// Loop over each setting in the group to generate form fields
|
// Loop over each setting in the group to generate form fields
|
||||||
groupSettings.forEach(setting => {
|
groupSettings.forEach(setting => {
|
||||||
const column = $('<div>'); // Create a column for each setting (Bootstrap column)
|
const column = $('<div>'); // Create a column for each setting (Bootstrap column)
|
||||||
|
|
||||||
// Get the field data (replace 'NEWDEV_' prefix from the key)
|
console.log(setting);
|
||||||
fieldData = deviceData[setting.setKey.replace('NEWDEV_', '')]
|
|
||||||
fieldData = fieldData == null ? "" : fieldData;
|
|
||||||
fieldOptionsOverride = null;
|
|
||||||
|
|
||||||
// console.log(setting.setKey);
|
// Get the field data (replace 'NEWDEV_' prefix from the key)
|
||||||
// console.log(fieldData);
|
fieldData = deviceData[setting.setKey.replace('NEWDEV_', '')]
|
||||||
|
fieldData = fieldData == null ? "" : fieldData;
|
||||||
|
fieldOptionsOverride = null;
|
||||||
|
|
||||||
// Additional form elements like the random MAC address button for devMac
|
console.log(setting.setKey);
|
||||||
let inlineControl = "";
|
// console.log(fieldData);
|
||||||
// handle random mac
|
|
||||||
if (setting.setKey == "NEWDEV_devMac" && deviceData["devIsRandomMAC"] == true) {
|
|
||||||
inlineControl += `<span class="input-group-addon pointer"
|
|
||||||
title="${getString("RandomMAC_hover")}">
|
|
||||||
<a href="https://github.com/jokob-sk/NetAlertX/blob/main/docs/RANDOM_MAC.md" target="_blank">
|
|
||||||
<i class="fa-solid fa-shuffle"></i>
|
|
||||||
</a>
|
|
||||||
</span>`;
|
|
||||||
}
|
|
||||||
// handle generate MAC for new device
|
|
||||||
if (setting.setKey == "NEWDEV_devMac" && deviceData["devMac"] == "") {
|
|
||||||
inlineControl += `<span class="input-group-addon pointer"
|
|
||||||
onclick="generate_NEWDEV_devMac()"
|
|
||||||
title="${getString("Gen_Generate")}">
|
|
||||||
<i class="fa-solid fa-dice" ></i>
|
|
||||||
</span>`;
|
|
||||||
}
|
|
||||||
// handle generate IP for new device
|
|
||||||
if (setting.setKey == "NEWDEV_devLastIP" && deviceData["devLastIP"] == "") {
|
|
||||||
inlineControl += `<span class="input-group-addon pointer"
|
|
||||||
onclick="generate_NEWDEV_devLastIP()"
|
|
||||||
title="${getString("Gen_Generate")}">
|
|
||||||
<i class="fa-solid fa-dice" ></i>
|
|
||||||
</span>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle devChildrenDynamic or NEWDEV_devChildrenNicsDynamic - selected values and options are the same
|
// Additional form elements like the random MAC address button for devMac
|
||||||
if (
|
let inlineControl = "";
|
||||||
Array.isArray(fieldData) &&
|
// handle random mac
|
||||||
(setting.setKey == "NEWDEV_devChildrenDynamic" ||
|
if (setting.setKey == "NEWDEV_devMac" && deviceData["devIsRandomMAC"] == true) {
|
||||||
setting.setKey == "NEWDEV_devChildrenNicsDynamic" )
|
inlineControl += `<span class="input-group-addon pointer"
|
||||||
)
|
title="${getString("RandomMAC_hover")}">
|
||||||
{
|
<a href="https://github.com/jokob-sk/NetAlertX/blob/main/docs/RANDOM_MAC.md" target="_blank">
|
||||||
fieldDataNew = []
|
<i class="fa-solid fa-shuffle"></i>
|
||||||
fieldData.forEach(child => {
|
</a>
|
||||||
fieldDataNew.push(child.devMac)
|
</span>`;
|
||||||
})
|
}
|
||||||
fieldData = fieldDataNew;
|
// handle generate MAC for new device
|
||||||
fieldOptionsOverride = fieldDataNew;
|
if (setting.setKey == "NEWDEV_devMac" && deviceData["devMac"] == "") {
|
||||||
}
|
inlineControl += `<span class="input-group-addon pointer"
|
||||||
|
onclick="generate_NEWDEV_devMac()"
|
||||||
|
title="${getString("Gen_Generate")}">
|
||||||
|
<i class="fa-solid fa-dice" ></i>
|
||||||
|
</span>`;
|
||||||
|
}
|
||||||
|
// handle generate IP for new device
|
||||||
|
if (setting.setKey == "NEWDEV_devLastIP" && deviceData["devLastIP"] == "") {
|
||||||
|
inlineControl += `<span class="input-group-addon pointer"
|
||||||
|
onclick="generate_NEWDEV_devLastIP()"
|
||||||
|
title="${getString("Gen_Generate")}">
|
||||||
|
<i class="fa-solid fa-dice" ></i>
|
||||||
|
</span>`;
|
||||||
|
}
|
||||||
|
|
||||||
// Generate the input field HTML
|
// handle devChildrenDynamic or NEWDEV_devChildrenNicsDynamic - selected values and options are the same
|
||||||
const inputFormHtml = `<div class="form-group col-xs-12">
|
if (
|
||||||
<label id="${setting.setKey}_label" class="${obj.labelClasses}" > ${setting.setName}
|
Array.isArray(fieldData) &&
|
||||||
<i my-set-key="${setting.setKey}"
|
(setting.setKey == "NEWDEV_devChildrenDynamic" ||
|
||||||
title="${getString("Settings_Show_Description")}"
|
setting.setKey == "NEWDEV_devChildrenNicsDynamic")
|
||||||
class="fa fa-circle-info pointer helpIconSmallTopRight"
|
) {
|
||||||
onclick="showDescriptionPopup(this)">
|
fieldDataNew = []
|
||||||
</i>
|
fieldData.forEach(child => {
|
||||||
</label>
|
fieldDataNew.push(child.devMac)
|
||||||
<div class="${obj.inputClasses}">
|
})
|
||||||
${generateFormHtml(settingsData, setting, fieldData.toString(), fieldOptionsOverride, null)}
|
fieldData = fieldDataNew;
|
||||||
${inlineControl}
|
fieldOptionsOverride = fieldDataNew;
|
||||||
</div>
|
}
|
||||||
</div>`;
|
|
||||||
|
|
||||||
column.append(inputFormHtml); // Append the input field to the column
|
// Generate the input field HTML
|
||||||
groupDiv.append(column); // Append the column to the group div
|
const inputFormHtml = `<div class="form-group col-xs-12">
|
||||||
|
<label id="${setting.setKey}_label" class="${obj.labelClasses}" > ${setting.setName}
|
||||||
|
<i my-set-key="${setting.setKey}"
|
||||||
|
title="${getString("Settings_Show_Description")}"
|
||||||
|
class="fa fa-circle-info pointer helpIconSmallTopRight"
|
||||||
|
onclick="showDescriptionPopup(this)">
|
||||||
|
</i>
|
||||||
|
</label>
|
||||||
|
<div class="${obj.inputClasses}">
|
||||||
|
${generateFormHtml(settingsData, setting, fieldData.toString(), fieldOptionsOverride, null)}
|
||||||
|
${inlineControl}
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
column.append(inputFormHtml); // Append the input field to the column
|
||||||
|
groupDiv.append(column); // Append the column to the group div
|
||||||
});
|
});
|
||||||
|
|
||||||
form.append(groupDiv); // Append the group div (containing columns) to the form
|
form.append(groupDiv); // Append the group div (containing columns) to the form
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// wait until everything is initialized to update icons
|
// wait until everything is initialized to update icons
|
||||||
updateAllIconPreviews();
|
updateAllIconPreviews();
|
||||||
|
|
||||||
// update readonly fields
|
// update readonly fields
|
||||||
handleReadOnly(settingsData, disabledFields);
|
handleReadOnly(settingsData, disabledFields);
|
||||||
};
|
};
|
||||||
|
|
||||||
// console.log(relevantSettings)
|
// console.log(relevantSettings)
|
||||||
|
|
||||||
generateSimpleForm(relevantSettings);
|
generateSimpleForm(relevantSettings);
|
||||||
|
|
||||||
toggleNetworkConfiguration(mac == 'Internet')
|
toggleNetworkConfiguration(mac == 'Internet')
|
||||||
|
|
||||||
initSelect2();
|
initSelect2();
|
||||||
initHoverNodeInfo();
|
initHoverNodeInfo();
|
||||||
|
|
||||||
hideSpinner();
|
hideSpinner();
|
||||||
|
|
||||||
})
|
}}); // $.get callback
|
||||||
|
}, 100); // setTimeout
|
||||||
}, 100);
|
} // ajax success
|
||||||
});
|
}); // $.ajax
|
||||||
|
} // getDeviceData
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
// ----------------------------------------
|
||||||
|
// Handle the read-only fields
|
||||||
// ----------------------------------------
|
function handleReadOnly(settingsData, disabledFields) {
|
||||||
// Handle the read-only fields
|
settingsData.forEach(setting => {
|
||||||
function handleReadOnly(settingsData, disabledFields) {
|
|
||||||
settingsData.forEach(setting => {
|
|
||||||
const element = $(`#${setting.setKey}`);
|
const element = $(`#${setting.setKey}`);
|
||||||
if (disabledFields.includes(setting.setKey)) {
|
if (disabledFields.includes(setting.setKey)) {
|
||||||
element.prop('readonly', true);
|
element.prop('readonly', true);
|
||||||
@@ -282,144 +321,144 @@
|
|||||||
element.prop('readonly', false);
|
element.prop('readonly', false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Save device data to DB
|
||||||
|
function setDeviceData(direction = '', refreshCallback = '') {
|
||||||
|
// Check MAC
|
||||||
|
mac = getMac()
|
||||||
|
|
||||||
|
if (isEmpty(mac)) {
|
||||||
|
|
||||||
|
console.error("Mac not defined");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// Determine if a new device should be created
|
||||||
// Save device data to DB
|
const createNew = mac === 'new' ? 1 : 0;
|
||||||
function setDeviceData(direction = '', refreshCallback = '') {
|
|
||||||
// Check MAC
|
|
||||||
mac = getMac()
|
|
||||||
|
|
||||||
if (isEmpty(mac)) {
|
const devLastIP = $('#NEWDEV_devLastIP').val();
|
||||||
|
const newMac = $('#NEWDEV_devMac').val()
|
||||||
|
|
||||||
console.error("Mac not defined");
|
// Validate MAC and Last IP
|
||||||
return;
|
if (mac === '' || !isValidMac(newMac) || !(isValidIPv4(devLastIP) || isValidIPv6(devLastIP))) {
|
||||||
}
|
showMessage(getString("DeviceEdit_ValidMacIp"), 5000, "modal_red");
|
||||||
|
return;
|
||||||
// Determine if a new device should be created
|
|
||||||
const createNew = mac === 'new' ? 1 : 0;
|
|
||||||
|
|
||||||
const devLastIP = $('#NEWDEV_devLastIP').val();
|
|
||||||
const newMac = $('#NEWDEV_devMac').val()
|
|
||||||
|
|
||||||
// Validate MAC and Last IP
|
|
||||||
if (mac === '' || !isValidMac(newMac) || !( isValidIPv4(devLastIP) || isValidIPv6(devLastIP) )) {
|
|
||||||
showMessage(getString("DeviceEdit_ValidMacIp"), 5000, "modal_red");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
showSpinner();
|
|
||||||
|
|
||||||
const apiToken = getSetting("API_TOKEN"); // dynamic token
|
|
||||||
const host = window.location.hostname;
|
|
||||||
const protocol = window.location.protocol;
|
|
||||||
const port = getSetting("GRAPHQL_PORT");
|
|
||||||
|
|
||||||
mac = $('#NEWDEV_devMac').val();
|
|
||||||
|
|
||||||
// Build payload for new endpoint
|
|
||||||
const payload = {
|
|
||||||
devName: $('#NEWDEV_devName').val().replace(/'/g, "’"),
|
|
||||||
devOwner: $('#NEWDEV_devOwner').val().replace(/'/g, "’"),
|
|
||||||
devType: $('#NEWDEV_devType').val().replace(/'/g, ""),
|
|
||||||
devVendor: $('#NEWDEV_devVendor').val().replace(/'/g, "’"),
|
|
||||||
devIcon: $('#NEWDEV_devIcon').val(),
|
|
||||||
|
|
||||||
devFavorite: ($('#NEWDEV_devFavorite')[0].checked * 1),
|
|
||||||
devGroup: $('#NEWDEV_devGroup').val().replace(/'/g, "’"),
|
|
||||||
devLocation: $('#NEWDEV_devLocation').val().replace(/'/g, "’"),
|
|
||||||
devComments: encodeSpecialChars($('#NEWDEV_devComments').val()),
|
|
||||||
|
|
||||||
devParentMAC: $('#NEWDEV_devParentMAC').val(),
|
|
||||||
devParentPort: $('#NEWDEV_devParentPort').val(),
|
|
||||||
devParentRelType: $('#NEWDEV_devParentRelType').val().replace(/'/g, ""),
|
|
||||||
|
|
||||||
devSSID: $('#NEWDEV_devSSID').val(),
|
|
||||||
devSite: $('#NEWDEV_devSite').val(),
|
|
||||||
|
|
||||||
devStaticIP: ($('#NEWDEV_devStaticIP')[0].checked * 1),
|
|
||||||
devScan: 1,
|
|
||||||
|
|
||||||
devAlertEvents: ($('#NEWDEV_devAlertEvents')[0].checked * 1),
|
|
||||||
devAlertDown: ($('#NEWDEV_devAlertDown')[0].checked * 1),
|
|
||||||
devSkipRepeated: $('#NEWDEV_devSkipRepeated').val().split(' ')[0],
|
|
||||||
|
|
||||||
devReqNicsOnline: ($('#NEWDEV_devReqNicsOnline')[0].checked * 1),
|
|
||||||
devIsNew: ($('#NEWDEV_devIsNew')[0].checked * 1),
|
|
||||||
devIsArchived: ($('#NEWDEV_devIsArchived')[0].checked * 1),
|
|
||||||
|
|
||||||
devFirstConnection: $('#NEWDEV_devFirstConnection').val(),
|
|
||||||
devLastConnection: $('#NEWDEV_devLastConnection').val(),
|
|
||||||
devLastIP: $('#NEWDEV_devLastIP').val(),
|
|
||||||
|
|
||||||
devCustomProps: btoa(
|
|
||||||
JSON.stringify(collectTableData("#NEWDEV_devCustomProps_table"))
|
|
||||||
),
|
|
||||||
|
|
||||||
createNew: createNew
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
$.ajax({
|
|
||||||
url: `${protocol}//${host}:${port}/device/${encodeURIComponent(mac)}`,
|
|
||||||
type: "POST",
|
|
||||||
headers: {
|
|
||||||
"Authorization": "Bearer " + apiToken,
|
|
||||||
"Content-Type": "application/json"
|
|
||||||
},
|
|
||||||
data: JSON.stringify(payload),
|
|
||||||
success: function (resp) {
|
|
||||||
|
|
||||||
if (resp && resp.success) {
|
|
||||||
showMessage("Device saved successfully");
|
|
||||||
} else {
|
|
||||||
showMessage("Device update returned an unexpected response");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove navigation prompt
|
|
||||||
window.onbeforeunload = null;
|
|
||||||
somethingChanged = false;
|
|
||||||
|
|
||||||
// Refresh API
|
|
||||||
updateApi("devices,appevents");
|
|
||||||
|
|
||||||
// Callback
|
|
||||||
if (typeof refreshCallback === "function") {
|
|
||||||
refreshCallback(direction);
|
|
||||||
}
|
|
||||||
|
|
||||||
hideSpinner();
|
|
||||||
},
|
|
||||||
error: function (xhr) {
|
|
||||||
if (xhr.status === 403) {
|
|
||||||
showMessage("Unauthorized - invalid API token");
|
|
||||||
} else {
|
|
||||||
showMessage("Failed to save device (" + xhr.status + ")");
|
|
||||||
}
|
|
||||||
hideSpinner();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------------
|
showSpinner();
|
||||||
// Disables or enables network configuration for the root node
|
|
||||||
function toggleNetworkConfiguration(disable) {
|
const apiToken = getSetting("API_TOKEN"); // dynamic token
|
||||||
if (disable) {
|
const host = window.location.hostname;
|
||||||
// Completely disable the NEWDEV_devParentMAC <select> and NEWDEV_devParentPort
|
const protocol = window.location.protocol;
|
||||||
$('#NEWDEV_devParentMAC').prop('disabled', true).val("").prop('selectedIndex', 0);
|
const port = getSetting("GRAPHQL_PORT");
|
||||||
$('#NEWDEV_devParentMAC').empty() // Remove all options
|
|
||||||
|
mac = $('#NEWDEV_devMac').val();
|
||||||
|
|
||||||
|
// Build payload for new endpoint
|
||||||
|
const payload = {
|
||||||
|
devName: $('#NEWDEV_devName').val().replace(/'/g, "’"),
|
||||||
|
devOwner: $('#NEWDEV_devOwner').val().replace(/'/g, "’"),
|
||||||
|
devType: $('#NEWDEV_devType').val().replace(/'/g, ""),
|
||||||
|
devVendor: $('#NEWDEV_devVendor').val().replace(/'/g, "’"),
|
||||||
|
devIcon: $('#NEWDEV_devIcon').val(),
|
||||||
|
|
||||||
|
devFavorite: ($('#NEWDEV_devFavorite')[0].checked * 1),
|
||||||
|
devGroup: $('#NEWDEV_devGroup').val().replace(/'/g, "’"),
|
||||||
|
devLocation: $('#NEWDEV_devLocation').val().replace(/'/g, "’"),
|
||||||
|
devComments: encodeSpecialChars($('#NEWDEV_devComments').val()),
|
||||||
|
|
||||||
|
devParentMAC: $('#NEWDEV_devParentMAC').val(),
|
||||||
|
devParentPort: $('#NEWDEV_devParentPort').val(),
|
||||||
|
devParentRelType: $('#NEWDEV_devParentRelType').val().replace(/'/g, ""),
|
||||||
|
|
||||||
|
devSSID: $('#NEWDEV_devSSID').val(),
|
||||||
|
devSite: $('#NEWDEV_devSite').val(),
|
||||||
|
|
||||||
|
devStaticIP: ($('#NEWDEV_devStaticIP')[0].checked * 1),
|
||||||
|
devScan: 1,
|
||||||
|
|
||||||
|
devAlertEvents: ($('#NEWDEV_devAlertEvents')[0].checked * 1),
|
||||||
|
devAlertDown: ($('#NEWDEV_devAlertDown')[0].checked * 1),
|
||||||
|
devSkipRepeated: $('#NEWDEV_devSkipRepeated').val().split(' ')[0],
|
||||||
|
|
||||||
|
devReqNicsOnline: ($('#NEWDEV_devReqNicsOnline')[0].checked * 1),
|
||||||
|
devIsNew: ($('#NEWDEV_devIsNew')[0].checked * 1),
|
||||||
|
devIsArchived: ($('#NEWDEV_devIsArchived')[0].checked * 1),
|
||||||
|
|
||||||
|
devFirstConnection: $('#NEWDEV_devFirstConnection').val(),
|
||||||
|
devLastConnection: $('#NEWDEV_devLastConnection').val(),
|
||||||
|
devLastIP: $('#NEWDEV_devLastIP').val(),
|
||||||
|
|
||||||
|
devCustomProps: btoa(
|
||||||
|
JSON.stringify(collectTableData("#NEWDEV_devCustomProps_table"))
|
||||||
|
),
|
||||||
|
|
||||||
|
createNew: createNew
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: `${protocol}//${host}:${port}/device/${encodeURIComponent(mac)}`,
|
||||||
|
type: "POST",
|
||||||
|
headers: {
|
||||||
|
"Authorization": "Bearer " + apiToken,
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
},
|
||||||
|
data: JSON.stringify(payload),
|
||||||
|
success: function(resp) {
|
||||||
|
|
||||||
|
if (resp && resp.success) {
|
||||||
|
showMessage("Device saved successfully");
|
||||||
|
} else {
|
||||||
|
showMessage("Device update returned an unexpected response");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove navigation prompt
|
||||||
|
window.onbeforeunload = null;
|
||||||
|
somethingChanged = false;
|
||||||
|
|
||||||
|
// Refresh API
|
||||||
|
updateApi("devices,appevents");
|
||||||
|
|
||||||
|
// Callback
|
||||||
|
if (typeof refreshCallback === "function") {
|
||||||
|
refreshCallback(direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
hideSpinner();
|
||||||
|
},
|
||||||
|
error: function(xhr) {
|
||||||
|
if (xhr.status === 403) {
|
||||||
|
showMessage("Unauthorized - invalid API token");
|
||||||
|
} else {
|
||||||
|
showMessage("Failed to save device (" + xhr.status + ")");
|
||||||
|
}
|
||||||
|
hideSpinner();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------
|
||||||
|
// Disables or enables network configuration for the root node
|
||||||
|
function toggleNetworkConfiguration(disable) {
|
||||||
|
if (disable) {
|
||||||
|
// Completely disable the NEWDEV_devParentMAC <select> and NEWDEV_devParentPort
|
||||||
|
$('#NEWDEV_devParentMAC').prop('disabled', true).val("").prop('selectedIndex', 0);
|
||||||
|
$('#NEWDEV_devParentMAC').empty() // Remove all options
|
||||||
.append('<option value="">Root Node</option>')
|
.append('<option value="">Root Node</option>')
|
||||||
$('#NEWDEV_devParentPort').prop('disabled', true);
|
$('#NEWDEV_devParentPort').prop('disabled', true);
|
||||||
$('#NEWDEV_devParentPort').prop('readonly', true );
|
$('#NEWDEV_devParentPort').prop('readonly', true);
|
||||||
$('#NEWDEV_devParentMAC').prop('readonly', true );
|
$('#NEWDEV_devParentMAC').prop('readonly', true);
|
||||||
} else {
|
} else {
|
||||||
// Enable the NEWDEV_devParentMAC <select> and NEWDEV_devParentPort
|
// Enable the NEWDEV_devParentMAC <select> and NEWDEV_devParentPort
|
||||||
$('#NEWDEV_devParentMAC').prop('disabled', false);
|
$('#NEWDEV_devParentMAC').prop('disabled', false);
|
||||||
$('#NEWDEV_devParentPort').prop('disabled', false);
|
$('#NEWDEV_devParentPort').prop('disabled', false);
|
||||||
$('#NEWDEV_devParentPort').prop('readonly', false );
|
$('#NEWDEV_devParentPort').prop('readonly', false);
|
||||||
$('#NEWDEV_devParentMAC').prop('readonly', false );
|
$('#NEWDEV_devParentMAC').prop('readonly', false);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------
|
// -----------------------------------------------
|
||||||
// INIT with polling for panel element visibility
|
// INIT with polling for panel element visibility
|
||||||
@@ -427,8 +466,7 @@
|
|||||||
|
|
||||||
var deviceDetailsPageInitialized = false;
|
var deviceDetailsPageInitialized = false;
|
||||||
|
|
||||||
function initdeviceDetailsPage()
|
function initdeviceDetailsPage() {
|
||||||
{
|
|
||||||
// Only proceed if .plugin-content is visible
|
// Only proceed if .plugin-content is visible
|
||||||
if (!$('#panDetails:visible').length) {
|
if (!$('#panDetails:visible').length) {
|
||||||
return; // exit early if nothing is visible
|
return; // exit early if nothing is visible
|
||||||
@@ -456,12 +494,9 @@ function deviceDetailsPageUpdater() {
|
|||||||
// if visible, load immediately, if not start updater
|
// if visible, load immediately, if not start updater
|
||||||
if (!$('#panDetails:visible').length) {
|
if (!$('#panDetails:visible').length) {
|
||||||
deviceDetailsPageUpdater();
|
deviceDetailsPageUpdater();
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
getDeviceData();
|
getDeviceData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
@@ -31,7 +31,6 @@
|
|||||||
$action = $_REQUEST['action'];
|
$action = $_REQUEST['action'];
|
||||||
switch ($action) {
|
switch ($action) {
|
||||||
// check server/api_server/api_server_start.py for equivalents
|
// check server/api_server/api_server_start.py for equivalents
|
||||||
case 'getServerDeviceData': getServerDeviceData(); break; // equivalent: get_device_data
|
|
||||||
case 'deleteDevice': deleteDevice(); break; // equivalent: delete_device(mac)
|
case 'deleteDevice': deleteDevice(); break; // equivalent: delete_device(mac)
|
||||||
case 'deleteAllWithEmptyMACs': deleteAllWithEmptyMACs(); break; // equivalent: delete_all_with_empty_macs
|
case 'deleteAllWithEmptyMACs': deleteAllWithEmptyMACs(); break; // equivalent: delete_all_with_empty_macs
|
||||||
|
|
||||||
@@ -55,150 +54,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
// Query Device Data
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
function getServerDeviceData() {
|
|
||||||
global $db;
|
|
||||||
|
|
||||||
// Request Parameters
|
|
||||||
$periodDate = getDateFromPeriod();
|
|
||||||
$mac = $_REQUEST['mac'];
|
|
||||||
|
|
||||||
// Check for "new" MAC case
|
|
||||||
if ($mac === "new") {
|
|
||||||
$now = date('Y-m-d H:i');
|
|
||||||
$deviceData = [
|
|
||||||
"devMac" => "",
|
|
||||||
"devName" => "",
|
|
||||||
"devOwner" => "",
|
|
||||||
"devType" => "",
|
|
||||||
"devVendor" => "",
|
|
||||||
"devFavorite" => 0,
|
|
||||||
"devGroup" => "",
|
|
||||||
"devComments" => "",
|
|
||||||
"devFirstConnection" => $now,
|
|
||||||
"devLastConnection" => $now,
|
|
||||||
"devLastIP" => "",
|
|
||||||
"devStaticIP" => 0,
|
|
||||||
"devScan" => 0,
|
|
||||||
"devLogEvents" => 0,
|
|
||||||
"devAlertEvents" => 0,
|
|
||||||
"devAlertDown" => 0,
|
|
||||||
"devParentRelType" => "default",
|
|
||||||
"devReqNicsOnline" => 0,
|
|
||||||
"devSkipRepeated" => 0,
|
|
||||||
"devLastNotification" => "",
|
|
||||||
"devPresentLastScan" => 0,
|
|
||||||
"devIsNew" => 1,
|
|
||||||
"devLocation" => "",
|
|
||||||
"devIsArchived" => 0,
|
|
||||||
"devParentMAC" => "",
|
|
||||||
"devParentPort" => "",
|
|
||||||
"devIcon" => "",
|
|
||||||
"devGUID" => "",
|
|
||||||
"devSite" => "",
|
|
||||||
"devSSID" => "",
|
|
||||||
"devSyncHubNode" => "",
|
|
||||||
"devSourcePlugin" => "",
|
|
||||||
"devCustomProps" => "",
|
|
||||||
"devStatus" => "Unknown",
|
|
||||||
"devIsRandomMAC" => false,
|
|
||||||
"devSessions" => 0,
|
|
||||||
"devEvents" => 0,
|
|
||||||
"devDownAlerts" => 0,
|
|
||||||
"devPresenceHours" => 0,
|
|
||||||
"devFQDN" => ""
|
|
||||||
];
|
|
||||||
echo json_encode($deviceData);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Get current date (used in presence calc)
|
|
||||||
$currentdate = date("Y-m-d H:i:s");
|
|
||||||
|
|
||||||
// Fetch Device Info + Children + Events Stats
|
|
||||||
$sql =<<<SQL
|
|
||||||
SELECT
|
|
||||||
d.rowid,
|
|
||||||
d.*,
|
|
||||||
CASE
|
|
||||||
WHEN d.devAlertDown != 0 AND d.devPresentLastScan = 0 THEN "Down"
|
|
||||||
WHEN d.devPresentLastScan = 1 THEN "On-line"
|
|
||||||
ELSE "Off-line"
|
|
||||||
END AS devStatus,
|
|
||||||
|
|
||||||
-- Event counters
|
|
||||||
(SELECT COUNT(*) FROM Sessions
|
|
||||||
WHERE ses_MAC = d.devMac AND (
|
|
||||||
ses_DateTimeConnection >= $periodDate OR
|
|
||||||
ses_DateTimeDisconnection >= $periodDate OR
|
|
||||||
ses_StillConnected = 1
|
|
||||||
)
|
|
||||||
) AS devSessions,
|
|
||||||
|
|
||||||
(SELECT COUNT(*) FROM Events
|
|
||||||
WHERE eve_MAC = d.devMac AND
|
|
||||||
eve_DateTime >= $periodDate AND
|
|
||||||
eve_EventType NOT IN ("Connected", "Disconnected")
|
|
||||||
) AS devEvents,
|
|
||||||
|
|
||||||
(SELECT COUNT(*) FROM Events
|
|
||||||
WHERE eve_MAC = d.devMac AND
|
|
||||||
eve_DateTime >= $periodDate AND
|
|
||||||
eve_EventType = "Device Down"
|
|
||||||
) AS devDownAlerts,
|
|
||||||
|
|
||||||
(SELECT CAST(( MAX (0, SUM (julianday (IFNULL (ses_DateTimeDisconnection,'$currentdate'))
|
|
||||||
- julianday (CASE WHEN ses_DateTimeConnection < $periodDate
|
|
||||||
THEN $periodDate
|
|
||||||
ELSE ses_DateTimeConnection END)) *24 )) AS INT)
|
|
||||||
FROM Sessions
|
|
||||||
WHERE ses_MAC = d.devMac AND
|
|
||||||
ses_DateTimeConnection IS NOT NULL AND
|
|
||||||
(ses_DateTimeDisconnection IS NOT NULL OR ses_StillConnected = 1) AND
|
|
||||||
(
|
|
||||||
ses_DateTimeConnection >= $periodDate OR
|
|
||||||
ses_DateTimeDisconnection >= $periodDate OR
|
|
||||||
ses_StillConnected = 1
|
|
||||||
)
|
|
||||||
) AS devPresenceHours
|
|
||||||
|
|
||||||
FROM Devices d
|
|
||||||
WHERE d.devMac = "$mac" OR CAST(d.rowid AS TEXT) = "$mac"
|
|
||||||
SQL;
|
|
||||||
|
|
||||||
$row = $db->query($sql)->fetchArray(SQLITE3_ASSOC);
|
|
||||||
$deviceData = $row;
|
|
||||||
$mac = $deviceData['devMac'];
|
|
||||||
|
|
||||||
$deviceData['devFirstConnection'] = formatDate($deviceData['devFirstConnection']);
|
|
||||||
$deviceData['devLastConnection'] = formatDate($deviceData['devLastConnection']);
|
|
||||||
$deviceData['devIsRandomMAC'] = isRandomMAC($mac);
|
|
||||||
|
|
||||||
// Fetch children once and split in PHP
|
|
||||||
$sql = 'SELECT rowid, * FROM Devices WHERE devParentMAC = "' . $mac . '" ORDER BY devPresentLastScan DESC';
|
|
||||||
$result = $db->query($sql);
|
|
||||||
$children = [];
|
|
||||||
$childrenNics = [];
|
|
||||||
|
|
||||||
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
|
|
||||||
$children[] = $row;
|
|
||||||
if ($row['devParentRelType'] === 'nic') {
|
|
||||||
$childrenNics[] = $row;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$deviceData['devChildrenDynamic'] = $children;
|
|
||||||
$deviceData['devChildrenNicsDynamic'] = $childrenNics;
|
|
||||||
|
|
||||||
// Return JSON
|
|
||||||
echo json_encode($deviceData);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Delete Device
|
// Delete Device
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -366,9 +366,9 @@ class Query(ObjectType):
|
|||||||
return DeviceResult(devices=devices, count=total_count)
|
return DeviceResult(devices=devices, count=total_count)
|
||||||
|
|
||||||
# --- SETTINGS ---
|
# --- SETTINGS ---
|
||||||
settings = Field(SettingResult)
|
settings = Field(SettingResult, filters=List(FilterOptionsInput))
|
||||||
|
|
||||||
def resolve_settings(root, info):
|
def resolve_settings(root, info, filters=None):
|
||||||
try:
|
try:
|
||||||
with open(folder + "table_settings.json", "r") as f:
|
with open(folder + "table_settings.json", "r") as f:
|
||||||
settings_data = json.load(f)["data"]
|
settings_data = json.load(f)["data"]
|
||||||
@@ -379,7 +379,18 @@ class Query(ObjectType):
|
|||||||
mylog("trace", f"[graphql_schema] settings_data: {settings_data}")
|
mylog("trace", f"[graphql_schema] settings_data: {settings_data}")
|
||||||
|
|
||||||
# Convert to Setting objects
|
# Convert to Setting objects
|
||||||
settings = [Setting(**setting) for setting in settings_data]
|
settings = [Setting(**s) for s in settings_data]
|
||||||
|
|
||||||
|
# Apply dynamic filters (OR)
|
||||||
|
if filters:
|
||||||
|
filtered_settings = []
|
||||||
|
for s in settings:
|
||||||
|
for f in filters:
|
||||||
|
if f.filterColumn and f.filterValue is not None:
|
||||||
|
if str(getattr(s, f.filterColumn, "")).lower() == str(f.filterValue).lower():
|
||||||
|
filtered_settings.append(s)
|
||||||
|
break # match one filter is enough (OR)
|
||||||
|
settings = filtered_settings
|
||||||
|
|
||||||
return SettingResult(settings=settings, count=len(settings))
|
return SettingResult(settings=settings, count=len(settings))
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user