Device Edit Rebuild + New Dummy Device

This commit is contained in:
jokob-sk
2024-11-30 23:34:20 +11:00
parent 67fd08a093
commit afaac3277d
42 changed files with 1891 additions and 1621 deletions

View File

@@ -161,8 +161,8 @@ function cacheSettings()
}
}
setCache(`pia_set_${set.setKey}`, set.setValue)
setCache(`pia_set_opt_${set.setKey}`, resolvedOptions)
setCache(`nax_set_${set.setKey}`, set.setValue)
setCache(`nax_set_opt_${set.setKey}`, resolvedOptions)
});
}).then(() => handleSuccess('cacheSettings', resolve())).catch(() => handleFailure('cacheSettings', reject("cacheSettings already completed"))); // handle AJAX synchronization
})
@@ -177,7 +177,7 @@ function getSettingOptions (key) {
// handle initial load to make sure everything is set-up and cached
// handleFirstLoad()
result = getCache(`pia_set_opt_${key}`, true);
result = getCache(`nax_set_opt_${key}`, true);
if (result == "")
{
@@ -195,7 +195,7 @@ function getSetting (key) {
// handle initial load to make sure everything is set-up and cached
// handleFirstLoad()
result = getCache(`pia_set_${key}`, true);
result = getCache(`nax_set_${key}`, true);
if (result == "")
{
@@ -690,10 +690,12 @@ function openUrl(urls) {
}
// -----------------------------------------------------------------------------
// force laod URL in current window with specific anchor
// force load URL in current window with specific anchor
function forceLoadUrl(relativeUrl) {
window.location.replace(relativeUrl);
window.location.reload()
window.location.reload()
}
@@ -721,7 +723,7 @@ function navigateToDeviceWithIp (ip) {
// -----------------------------------------------------------------------------
function getNameByMacAddress(macAddress) {
return getDeviceDataByMac(macAddress, "devName")
return getDevDataByMac(macAddress, "devName")
}
// -----------------------------------------------------------------------------
@@ -758,6 +760,12 @@ function isValidIPv6(ipAddress) {
return ipv6Regex.test(ipAddress);
}
function isValidIPv4(ip) {
const ipv4Regex = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
return ipv4Regex.test(ip);
}
function formatIPlong(ipAddress) {
if (ipAddress.includes(':') && isValidIPv6(ipAddress)) {
const parts = ipAddress.split(':');
@@ -822,7 +830,11 @@ function isRandomMAC(mac)
// Empty array
if (input === '[]' || input === '') {
return [];
}
}
// handle integer
if (typeof input === 'number') {
input = input.toString();
}
// Regex pattern for brackets
const patternBrackets = /(^\s*\[)|(\]\s*$)/g;
@@ -874,7 +886,7 @@ function isRandomMAC(mac)
// -----------------------------------------------------------------------------
// A function to get a device property using the mac address as key and DB column nakme as parameter
// for the value to be returned
function getDeviceDataByMac(macAddress, dbColumn) {
function getDevDataByMac(macAddress, dbColumn) {
const sessionDataKey = 'devicesListAll_JSON';
const devicesCache = getCache(sessionDataKey);
@@ -1193,6 +1205,40 @@ function hideUIelements(setKey) {
}
// ------------------------------------------------------------
function getDevicesList()
{
// Read cache (skip cookie expiry check)
devicesList = getCache('devicesListAll_JSON', true);
if (devicesList != '') {
devicesList = JSON.parse (devicesList);
} else {
devicesList = [];
}
// only loop thru the filtered down list
visibleDevices = getCache("ntx_visible_macs")
if(visibleDevices != "") {
visibleDevicesMACs = visibleDevices.split(',');
devicesList_tmp = [];
// Iterate through the data and filter only visible devices
$.each(devicesList, function(index, item) {
// Check if the current item's MAC exists in visibleDevicesMACs
if (visibleDevicesMACs.includes(item.devMac)) {
devicesList_tmp.push(item);
}
});
// Update devicesList with the filtered items
devicesList = devicesList_tmp;
}
return devicesList;
}
// -----------------------------------------------------------------------------

View File

@@ -87,7 +87,8 @@ function showModalInput(
message,
btnCancel = getString("Gen_Cancel"),
btnOK = getString("Gen_Okay"),
callbackFunction = null
callbackFunction = null,
triggeredBy = null
) {
prefix = "modal-input";
@@ -101,6 +102,10 @@ function showModalInput(
modalCallbackFunction = callbackFunction;
}
if (triggeredBy != null) {
$('#'+prefix).attr("data-myparam-triggered-by", triggeredBy)
}
// Show modal
$(`#${prefix}`).modal("show");
@@ -117,7 +122,8 @@ function showModalFieldInput(
btnCancel = getString("Gen_Cancel"),
btnOK = getString("Gen_Okay"),
curValue = "",
callbackFunction = null
callbackFunction = null,
triggeredBy = null
) {
// set captions
prefix = "modal-field-input";
@@ -128,9 +134,14 @@ function showModalFieldInput(
$(`#${prefix}-OK`).html(btnOK);
if (callbackFunction != null) {
modalCallbackFunction = callbackFunction;
}
if (triggeredBy != null) {
$('#'+prefix).attr("data-myparam-triggered-by", triggeredBy)
}
$(`#${prefix}-field`).val(curValue);
setTimeout(function () {
@@ -148,7 +159,13 @@ function modalDefaultOK() {
// timer to execute function
window.setTimeout(function () {
window[modalCallbackFunction]();
if (typeof modalCallbackFunction === "function") {
modalCallbackFunction(); // Direct call
} else if (typeof modalCallbackFunction === "string" && typeof window[modalCallbackFunction] === "function") {
window[modalCallbackFunction](); // Call via window
} else {
console.error("Invalid callback function");
}
}, 100);
}
@@ -159,7 +176,13 @@ function modalDefaultInput() {
// timer to execute function
window.setTimeout(function () {
window[modalCallbackFunction]();
if (typeof modalCallbackFunction === "function") {
modalCallbackFunction(); // Direct call
} else if (typeof modalCallbackFunction === "string" && typeof window[modalCallbackFunction] === "function") {
window[modalCallbackFunction](); // Call via window
} else {
console.error("Invalid callback function");
}
}, 100);
}
@@ -170,7 +193,13 @@ function modalDefaultFieldInput() {
// timer to execute function
window.setTimeout(function () {
modalCallbackFunction();
if (typeof modalCallbackFunction === "function") {
modalCallbackFunction(); // Direct call
} else if (typeof modalCallbackFunction === "string" && typeof window[modalCallbackFunction] === "function") {
window[modalCallbackFunction](); // Call via window
} else {
console.error("Invalid callback function");
}
}, 100);
}
@@ -181,7 +210,13 @@ function modalWarningOK() {
// timer to execute function
window.setTimeout(function () {
window[modalCallbackFunction]();
if (typeof modalCallbackFunction === "function") {
modalCallbackFunction(); // Direct call
} else if (typeof modalCallbackFunction === "string" && typeof window[modalCallbackFunction] === "function") {
window[modalCallbackFunction](); // Call via window
} else {
console.error("Invalid callback function");
}
}, 100);
}

View File

@@ -859,3 +859,164 @@ function genListWithInputSet(options, valuesArray, targetField, transformers, pl
// Place the resulting HTML into the specified placeholder div
$("#" + placeholder).replaceWith(listHtml);
}
// ------------------------------------------------------------------------------
// Generate the form control for setting
function generateFormHtml(set, overrideValue) {
let inputHtml = '';
isEmpty(overrideValue) ? inVal = set['setValue'] : inVal = overrideValue;
const setKey = set['setKey'];
const setType = set['setType'];
// console.log(setType);
// console.log(setKey);
// console.log(overrideValue);
// console.log(inVal);
// Parse the setType JSON string
const setTypeObject = JSON.parse(setType.replace(/'/g, '"'));
const dataType = setTypeObject.dataType;
const elements = setTypeObject.elements || [];
// Generate HTML for elements
elements.forEach(elementObj => {
const { elementType, elementOptions = [], transformers = [] } = elementObj;
// Handle element options
const {
inputType,
readOnly,
isMultiSelect,
isOrdeable,
cssClasses,
placeholder,
suffix,
sourceIds,
separator,
editable,
valRes,
getStringKey,
onClick,
onChange,
customParams,
customId
} = handleElementOptions(setKey, elementOptions, transformers, inVal);
// Override value
const val = valRes;
// console.log(val);
// Generate HTML based on elementType
switch (elementType) {
case 'select':
const multi = isMultiSelect ? "multiple" : "";
const addCss = isOrdeable ? "select2 select2-hidden-accessible" : "";
inputHtml += `<select onChange="settingsChanged();${onChange}"
my-data-type="${dataType}"
my-editable="${editable}"
class="form-control ${addCss}"
name="${setKey}"
id="${setKey}"
my-customparams="${customParams}"
my-customid="${customId}"
${multi}>
<option value="" id="${setKey + "_temp_"}"></option>
</select>`;
generateOptionsOrSetOptions(setKey, createArray(val), `${setKey}_temp_`, generateOptions, null, transformers);
break;
case 'input':
const checked = val === 'True' || val === '1' ? 'checked' : '';
const inputClass = inputType === 'checkbox' ? 'checkbox' : 'form-control';
inputHtml += `<input
class="${inputClass} ${cssClasses}"
onChange="settingsChanged();${onChange}"
my-data-type="${dataType}"
my-customparams="${customParams}"
my-customid="${customId}"
id="${setKey}${suffix}"
type="${inputType}"
value="${val}"
${readOnly}
${checked}
placeholder="${placeholder}"
/>`;
break;
case 'button':
inputHtml += `<button
class="btn btn-primary ${cssClasses}"
my-customparams="${customParams}"
my-customid="${customId}"
my-input-from="${sourceIds}"
my-input-to="${setKey}"
onclick="${onClick}">
${getString(getStringKey)}
</button>`;
break;
case 'textarea':
inputHtml += `<textarea
class="form-control input"
my-customparams="${customParams}"
my-customid="${customId}"
my-data-type="${dataType}"
id="${setKey}"
${readOnly}>${val}</textarea>`;
break;
case 'span':
inputHtml += `<span
class="${cssClasses}"
my-data-type="${dataType}"
my-customparams="${customParams}"
my-customid="${customId}">
${getString(getStringKey)}
</span>`;
break;
default:
console.warn(`🟥 Unknown element type: ${elementType}`);
}
});
// Generate event HTML if applicable
let eventsHtml = '';
// console.log(setTypeObject);
// console.log(set);
const eventsList = createArray(set['setEvents']);
// inline buttons events
if (eventsList.length > 0) {
eventsList.forEach(event => {
eventsHtml += `<span class="input-group-addon pointer"
id="${`${event}_${setKey}`}"
data-myparam-setkey="${setKey}"
data-myparam="${setKey}"
data-myparam-plugin="${setTypeObject.prefix || ''}"
data-myevent="${event}"
onclick="execute_settingEvent(this)">
<i title="${getString(event + "_event_tooltip")}" class="fa ${getString(event + "_event_icon")}"></i>
</span>`;
});
}
// Combine and return the final HTML
return inputHtml + eventsHtml;
}

View File

@@ -97,64 +97,66 @@ function generateApiToken(elem, length) {
}
}
// ----------------------------------------------
// Updates the icon preview
function updateIconPreview(elem) {
// Retrieve and parse custom parameters from the element
let params = $(elem).attr("my-customparams")?.split(',').map(param => param.trim());
const targetElement = $('[my-customid="NEWDEV_devIcon_preview"]');
const iconInput = $("#NEWDEV_devIcon");
// console.log(params);
let attempts = 0;
if (params && params.length >= 2) {
var inputElementID = params[0];
var targetElementID = params[1];
} else {
console.error("Invalid parameters passed to updateIconPreview function");
return;
}
function tryUpdateIcon() {
let value = iconInput.val();
// Get the input element using the inputElementID
let iconInput = $("#" + inputElementID);
if (value) {
targetElement.html(atob(value));
iconInput.off('change input').on('change input', function () {
let newValue = $(this).val();
targetElement.html(atob(newValue));
});
return; // Stop retrying if successful
}
if (iconInput.length === 0) {
console.error("Icon input element not found");
return;
}
// Get the initial value and update the target element
let value = iconInput.val();
if (!value) {
console.error("Input value is empty or not defined");
return;
}
if (!targetElementID) {
targetElementID = "txtIcon";
}
// Check if the target element exists, if not find an element with matching custom attribute
let targetElement = $('#' + targetElementID);
if (targetElement.length === 0) {
// Look for an element with my-custom-id attribute equal to targetElementID
targetElement = $('[my-customid="' + targetElementID + '"]');
if (targetElement.length === 0) {
console.error("Neither target element with ID nor element with custom attribute found");
return;
attempts++;
if (attempts < 10) {
setTimeout(tryUpdateIcon, 1000); // Retry after 1 second
} else {
console.error("Input value is empty after 10 attempts");
}
}
// Update the target element with decoded base64 value
targetElement.html(atob(value));
// Add event listener to update the icon on input change
iconInput.on('change input', function () {
let newValue = $(this).val();
$('#' + targetElementID).html(atob(newValue));
});
tryUpdateIcon();
}
// -----------------------------------------------------------------------------
// Nice checkboxes with iCheck
function initializeiCheck () {
// Blue
$('input[type="checkbox"].blue').iCheck({
checkboxClass: 'icheckbox_flat-blue',
radioClass: 'iradio_flat-blue',
increaseArea: '20%'
});
// Orange
$('input[type="checkbox"].orange').iCheck({
checkboxClass: 'icheckbox_flat-orange',
radioClass: 'iradio_flat-orange',
increaseArea: '20%'
});
// Red
$('input[type="checkbox"].red').iCheck({
checkboxClass: 'icheckbox_flat-red',
radioClass: 'iradio_flat-red',
increaseArea: '20%'
});
}
// -----------------------------------------------------------------------------
@@ -219,19 +221,24 @@ function getCellValue(row, index) {
return $(row).children('td').eq(index).text();
}
// -----------------------------------------------------------------------------
// handling events on the backend initiated by the front end START
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// handling events
// -----------------------------------------------------------------------------
modalEventStatusId = 'modal-message-front-event'
modalEventStatusId = 'modal-message-front-event'
// --------------------------------------------------------
// Calls a backend function to add a front-end event (specified by the attributes 'data-myevent' and 'data-myparam-plugin' on the passed element) to an execution queue
function addToExecutionQueue_settingEvent(element)
{
function execute_settingEvent(element) {
feEvent = $(element).attr('data-myevent');
fePlugin = $(element).attr('data-myparam-plugin');
feSetKey = $(element).attr('data-myparam-setkey');
feParam = $(element).attr('data-myparam');
feSourceId = $(element).attr('id');
if (["test", "run"].includes(feEvent)) {
// Calls a backend function to add a front-end event (specified by the attributes 'data-myevent' and 'data-myparam-plugin' on the passed element) to an execution queue
// value has to be in format event|param. e.g. run|ARPSCAN
action = `${getGuid()}|${$(element).attr('data-myevent')}|${$(element).attr('data-myparam-plugin')}`
action = `${getGuid()}|${feEvent}|${fePlugin}`
$.ajax({
method: "POST",
@@ -246,29 +253,138 @@ function getCellValue(row, index) {
updateModalState()
}
})
}
} else if (["add_option"].includes(feEvent)) {
showModalFieldInput (
'<i class="fa fa-square-plus pointer"></i> ' + getString('Gen_Add'),
getString('Gen_Add'),
getString('Gen_Cancel'),
getString('Gen_Okay'),
'', // curValue
'addOptionFromModalInput',
feSourceId // triggered by id
);
} else if (["add_icon"].includes(feEvent)) {
// --------------------------------------------------------
// Updating the execution queue in in modal pop-up
function updateModalState() {
setTimeout(function() {
// Fetch the content from the log file using an AJAX request
$.ajax({
url: '/log/execution_queue.log',
type: 'GET',
success: function(data) {
// Update the content of the HTML element (e.g., a div with id 'logContent')
$('#'+modalEventStatusId).html(data);
// Add new icon as base64 string
showModalInput (
'<i class="fa fa-square-plus pointer"></i> ' + getString('DevDetail_button_AddIcon'),
getString('DevDetail_button_AddIcon_Help'),
getString('Gen_Cancel'),
getString('Gen_Okay'),
() => addIconAsBase64(element), // Wrap in an arrow function
feSourceId // triggered by id
);
} else if (["copy_icons"].includes(feEvent)) {
updateModalState();
},
error: function() {
// Handle error, such as the file not being found
$('#logContent').html('Error: Log file not found.');
}
});
}, 2000);
// Ask overwrite icon types
showModalWarning (
getString('DevDetail_button_OverwriteIcons'),
getString('DevDetail_button_OverwriteIcons_Warning'),
getString('Gen_Cancel'),
getString('Gen_Okay'),
'overwriteIconType'
);
} else if (["go_to_node"].includes(feEvent)) {
goToNetworkNode('NEWDEV_devParentMAC');
} else {
console.warn(`🔺Not implemented: ${feEvent}`)
}
}
// -----------------------------------------------------------------------------
// Go to the correct network node in the Network section
function goToNetworkNode(dropdownId)
{
setCache('activeNetworkTab', $('#'+dropdownId).val().replaceAll(":","_")+'_id');
window.location.href = './network.php';
}
// --------------------------------------------------------
// Updating the execution queue in in modal pop-up
function updateModalState() {
setTimeout(function() {
// Fetch the content from the log file using an AJAX request
$.ajax({
url: '/log/execution_queue.log',
type: 'GET',
success: function(data) {
// Update the content of the HTML element (e.g., a div with id 'logContent')
$('#'+modalEventStatusId).html(data);
updateModalState();
},
error: function() {
// Handle error, such as the file not being found
$('#logContent').html('Error: Log file not found.');
}
});
}, 2000);
}
// --------------------------------------------------------
// A method to add option to select and make it selected
function addOptionFromModalInput() {
var inputVal = $(`#modal-field-input-field`).val();
console.log($('#modal-field-input-field'));
var triggeredBy = $('#modal-field-input').attr("data-myparam-triggered-by");
var targetId = $('#' + triggeredBy).attr("data-myparam-setkey");
// Add new option and set it as selected
$('#' + targetId).append(new Option(inputVal, inputVal)).val(inputVal);
}
// --------------------------------------------------------
// Generate a random MAC address starting 00:1A
function generate_NEWDEV_devMac() {
const randomHexPair = () => Math.floor(Math.random() * 256).toString(16).padStart(2, '0').toUpperCase();
$('#NEWDEV_devMac').val(`00:1A:${randomHexPair()}:${randomHexPair()}:${randomHexPair()}:${randomHexPair()}`.toLowerCase());
}
// --------------------------------------------------------
// Generate a random IP address starting 192.
function generate_NEWDEV_devLastIP() {
const randomByte = () => Math.floor(Math.random() * 256);
$('#NEWDEV_devLastIP').val(`192.${randomByte()}.${randomByte()}.${Math.floor(Math.random() * 254) + 1}`);
}
// -----------------------------------------------------------------------------
// A method to add an Icon as an option to select and make it selected
function addIconAsBase64 (el) {
var iconHtml = $('#modal-input-textarea').val();
console.log(iconHtml);
iconHtmlBase64 = btoa(iconHtml.replace(/"/g, "'"));
console.log(iconHtmlBase64);
console.log($('#modal-field-input-field'));
var triggeredBy = $('#modal-input').attr("data-myparam-triggered-by");
var targetId = $('#' + triggeredBy).attr("data-myparam-setkey");
// $('#'+targetId).val(iconHtmlBase64);
// Add new option and set it as selected
$('#' + targetId).append(new Option(iconHtmlBase64, iconHtmlBase64)).val(iconHtmlBase64);
updateIconPreview(el)
}
// -----------------------------------------------------------------------------
@@ -324,15 +440,14 @@ function initSelect2() {
}
}
// init select2 after dom laoded
// init functions after dom loaded
window.addEventListener("load", function() {
// try to initialize select2
// try to initialize
setTimeout(() => {
initSelect2()
initializeiCheck();
}, 1000);
});
console.log("init ui_components.js")