mirror of
https://github.com/jokob-sk/NetAlertX.git
synced 2025-12-07 09:36:05 -08:00
Custom Device Properties v0.1 #876
This commit is contained in:
85
docs/CUSTOM_PROPERTIES.md
Executable file
85
docs/CUSTOM_PROPERTIES.md
Executable file
@@ -0,0 +1,85 @@
|
||||
# Custom Properties for Network Devices
|
||||
|
||||

|
||||
|
||||
## Overview
|
||||
|
||||
This functionality allows you to define **custom properties** for network devices, which can store and display additional information on the device listing page. By marking properties as visible, you can enhance the user interface with quick actions, notes, or external links.
|
||||
|
||||
### Key Features:
|
||||
- **Customizable Properties**: Define specific properties for each device.
|
||||
- **Visibility Control**: Choose which properties are displayed on the device listing page.
|
||||
- **Interactive Elements**: Include actions like links, modals, and device management directly in the interface.
|
||||
|
||||
---
|
||||
|
||||
## Defining Custom Properties
|
||||
|
||||
Custom properties are structured as a list of objects, where each property includes the following fields:
|
||||
|
||||
| Field | Description |
|
||||
|--------------------|-----------------------------------------------------------------------------|
|
||||
| `CUSTPROP_icon` | The icon (Base64-encoded HTML) displayed for the property. |
|
||||
| `CUSTPROP_type` | The action type (e.g., `show_notes`, `link`, `delete_dev`). |
|
||||
| `CUSTPROP_name` | A short name or title for the property. |
|
||||
| `CUSTPROP_args` | Arguments for the action (e.g., URL or modal text). |
|
||||
| `CUSTPROP_notes` | Additional notes or details displayed when applicable. |
|
||||
| `CUSTPROP_show` | A boolean to control visibility (`true` to show on the listing page). |
|
||||
|
||||
---
|
||||
|
||||
## Available Action Types
|
||||
|
||||
- **Show Notes**: Displays a modal with a title and additional notes.
|
||||
- **Example**: Show firmware details or custom messages.
|
||||
- **Link**: Redirects to a specified URL in the current browser tab. (**Arguments** Needs to contain the full URL.)
|
||||
- **Link (New Tab)**: Opens a specified URL in a new browser tab. (**Arguments** Needs to contain the full URL.)
|
||||
- **Delete Device**: Deletes the device using its MAC address.
|
||||
- **Run Plugin**: Placeholder for executing custom plugins (not implemented yet).
|
||||
|
||||
---
|
||||
|
||||
## Usage on the Device Listing Page
|
||||
|
||||

|
||||
|
||||
Visible properties (`CUSTPROP_show: true`) are displayed as interactive icons in the device listing. Each icon can perform one of the following actions based on the `CUSTPROP_type`:
|
||||
|
||||
1. **Modals (e.g., Show Notes)**:
|
||||
- Displays detailed information in a popup modal.
|
||||
- Example: Firmware version details.
|
||||
|
||||
2. **Links**:
|
||||
- Redirect to an external or internal URL.
|
||||
- Example: Open a device's documentation or external site.
|
||||
|
||||
3. **Device Actions**:
|
||||
- Manage devices with actions like delete.
|
||||
- Example: Quickly remove a device from the network.
|
||||
|
||||
4. **Plugins**:
|
||||
- Future placeholder for running custom plugin scripts.
|
||||
- **Note**: Not implemented yet.
|
||||
|
||||
---
|
||||
|
||||
## Example Scenarios
|
||||
|
||||
1. **Device Documentation Link**:
|
||||
- Add a custom property with `CUSTPROP_type` set to `link` or `link_new_tab` to allow quick navigation to the documentation.
|
||||
|
||||
2. **Firmware Details**:
|
||||
- Use `CUSTPROP_type: show_notes` to display firmware versions or upgrade instructions in a modal.
|
||||
|
||||
3. **Device Removal**:
|
||||
- Enable device removal functionality using `CUSTPROP_type: delete_dev`.
|
||||
|
||||
---
|
||||
|
||||
## Notes
|
||||
|
||||
- **Plugin Functionality**: The `run_plugin` action type is currently not implemented and will show an alert if used.
|
||||
- **Custom Icons (Experimental 🧪)**: Use Base64-encoded HTML to provide custom icons for each property. You can add your icons in Setttings via the `CUSTPROP_icon` settings
|
||||
- **Visibility Control**: Only properties with `CUSTPROP_show: true` will appear on the listing page.
|
||||
|
||||
This feature provides a flexible way to enhance device management and display with interactive elements tailored to your needs.
|
||||
BIN
docs/img/CUSTOM_PROPERTIES/Device_Custom_Properties.png
Executable file
BIN
docs/img/CUSTOM_PROPERTIES/Device_Custom_Properties.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 39 KiB |
BIN
docs/img/CUSTOM_PROPERTIES/Device_Custom_Properties_vid.gif
Executable file
BIN
docs/img/CUSTOM_PROPERTIES/Device_Custom_Properties_vid.gif
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 1.6 MiB |
@@ -1382,9 +1382,36 @@ input[readonly] {
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------- */
|
||||
/* MODAL popups */
|
||||
/* Device details */
|
||||
/* ----------------------------------------------------------------- */
|
||||
|
||||
.dataTables_length label .form-control, .dataTables_filter label .form-control
|
||||
{
|
||||
float: none;
|
||||
}
|
||||
|
||||
|
||||
.form-inline .input-group
|
||||
{
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.input-group .actionIcon
|
||||
{
|
||||
height: 2.4em;
|
||||
}
|
||||
|
||||
.input-group .actionIcon:hover
|
||||
{
|
||||
backdrop-filter: brightness(50%);
|
||||
background-color: rgba(0, 0, 0, 0.2); /* darkens the background */
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
|
||||
transition: box-shadow 0.1s ease-in-out, background-color 0.1s ease-in-out;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------- */
|
||||
/* MODAL popups */
|
||||
/* ----------------------------------------------------------------- */
|
||||
#modal-input-textarea
|
||||
{
|
||||
width: 100%;
|
||||
|
||||
@@ -14,26 +14,21 @@
|
||||
<!-- Buttons -->
|
||||
<div class="col-xs-12">
|
||||
<div class="pull-right">
|
||||
<button type="button"
|
||||
class="btn btn-default pa-btn pa-btn-delete"
|
||||
style="margin-left:0px;"
|
||||
id="btnDeleteEvents"
|
||||
onclick="askDeleteDeviceEvents()">
|
||||
<?= lang('DevDetail_button_DeleteEvents');?>
|
||||
</button>
|
||||
<button type="button"
|
||||
class="btn btn-default pa-btn pa-btn-delete"
|
||||
style="margin-left:0px;"
|
||||
id="btnDelete"
|
||||
onclick="askDeleteDevice()">
|
||||
<?= lang('DevDetail_button_Delete');?>
|
||||
<i class="fas fa-trash-alt"></i>
|
||||
<?= lang('DevDetail_button_Delete');?>
|
||||
</button>
|
||||
<button type="button"
|
||||
class="btn btn-primary pa-btn"
|
||||
style="margin-left:6px; "
|
||||
id="btnSave"
|
||||
onclick="setDeviceData()" >
|
||||
<?= lang('DevDetail_button_Save');?>
|
||||
<i class="fas fa-save"></i>
|
||||
<?= lang('DevDetail_button_Save');?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -83,32 +78,55 @@
|
||||
DevDetail_MainInfo_Title: {
|
||||
data: ["devMac", "devLastIP", "devName", "devOwner", "devType", "devVendor", "devGroup", "devIcon", "devLocation", "devComments"],
|
||||
docs: "https://github.com/jokob-sk/NetAlertX/blob/main/docs/DEVICE_MANAGEMENT.md",
|
||||
iconClass: "fa fa-pencil"
|
||||
iconClass: "fa fa-pencil",
|
||||
inputGroupClasses: "field-group col-lg-4 col-sm-6 col-xs-12",
|
||||
labelClasses: "col-sm-4 col-xs-12 control-label",
|
||||
inputClasses: "col-sm-8 col-xs-12 input-group"
|
||||
},
|
||||
// Group for session information
|
||||
DevDetail_SessionInfo_Title: {
|
||||
data: ["devStatus", "devLastConnection", "devFirstConnection"],
|
||||
docs: "https://github.com/jokob-sk/NetAlertX/blob/main/docs/SESSION_INFO.md",
|
||||
iconClass: "fa fa-calendar"
|
||||
iconClass: "fa fa-calendar",
|
||||
inputGroupClasses: "field-group col-lg-4 col-sm-6 col-xs-12",
|
||||
labelClasses: "col-sm-4 col-xs-12 control-label",
|
||||
inputClasses: "col-sm-8 col-xs-12 input-group"
|
||||
},
|
||||
// Group for event and alert settings
|
||||
DevDetail_EveandAl_Title: {
|
||||
data: ["devAlertEvents", "devAlertDown", "devSkipRepeated"],
|
||||
docs: "https://github.com/jokob-sk/NetAlertX/blob/main/docs/NOTIFICATIONS.md",
|
||||
iconClass: "fa fa-bell"
|
||||
iconClass: "fa fa-bell",
|
||||
inputGroupClasses: "field-group col-lg-4 col-sm-6 col-xs-12",
|
||||
labelClasses: "col-sm-4 col-xs-12 control-label",
|
||||
inputClasses: "col-sm-8 col-xs-12 input-group"
|
||||
},
|
||||
// Group for network details
|
||||
DevDetail_MainInfo_Network_Title: {
|
||||
data: ["devParentMAC", "devParentPort", "devSSID", "devSite"],
|
||||
docs: "https://github.com/jokob-sk/NetAlertX/blob/main/docs/NETWORK_TREE.md",
|
||||
iconClass: "fa fa-network-wired"
|
||||
iconClass: "fa fa-network-wired",
|
||||
inputGroupClasses: "field-group col-lg-4 col-sm-6 col-xs-12",
|
||||
labelClasses: "col-sm-4 col-xs-12 control-label",
|
||||
inputClasses: "col-sm-8 col-xs-12 input-group"
|
||||
},
|
||||
// Group for other fields like static IP, archived status, etc.
|
||||
DevDetail_DisplayFields_Title: {
|
||||
data: ["devStaticIP", "devIsNew", "devFavorite", "devIsArchived"],
|
||||
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 col-lg-4 col-sm-6 col-xs-12",
|
||||
labelClasses: "col-sm-4 col-xs-12 control-label",
|
||||
inputClasses: "col-sm-8 col-xs-12 input-group"
|
||||
},
|
||||
// Group for Custom properties.
|
||||
DevDetail_CustomProperties_Title: {
|
||||
data: ["devCustomProps"],
|
||||
docs: "https://github.com/jokob-sk/NetAlertX/blob/main/docs/CUSTOM_PROPERTIES.md",
|
||||
iconClass: "fa fa-list",
|
||||
inputGroupClasses: "field-group col-lg-12 col-sm-12 col-xs-12",
|
||||
labelClasses: "col-sm-12 col-xs-12 control-label",
|
||||
inputClasses: "col-sm-12 col-xs-12 input-group"
|
||||
}
|
||||
};
|
||||
|
||||
@@ -126,7 +144,7 @@
|
||||
|
||||
// Loop over each field group to generate sections for each category
|
||||
Object.entries(fieldGroups).forEach(([groupName, obj]) => {
|
||||
const groupDiv = $('<div>').addClass('field-group col-lg-4 col-sm-6 col-xs-12'); // 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
|
||||
groupDiv.append(`<h5><i class="${obj.iconClass}"></i> ${getString(groupName)}
|
||||
@@ -137,7 +155,7 @@
|
||||
</span>
|
||||
</h5>
|
||||
<hr>
|
||||
`);
|
||||
`);
|
||||
|
||||
// Filter relevant settings for the current group
|
||||
const groupSettings = settings.filter(set => obj.data.includes(set.setKey.replace('NEWDEV_', '')));
|
||||
@@ -193,15 +211,15 @@
|
||||
|
||||
// Generate the input field HTML
|
||||
const inputFormHtml = `<div class="form-group col-xs-12">
|
||||
<label class="col-sm-4 col-xs-12 control-label"> ${setting.setName}
|
||||
<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="col-sm-8 col-xs-12 input-group">
|
||||
${generateFormHtml(setting, fieldData.toString())}
|
||||
<div class="${obj.inputClasses}">
|
||||
${generateFormHtml(settingsData, setting, fieldData.toString(), null, null)}
|
||||
${inlineControl}
|
||||
</div>
|
||||
</div>`;
|
||||
@@ -214,8 +232,8 @@
|
||||
});
|
||||
|
||||
|
||||
// wait until everything is initialized to update icon
|
||||
updateIconPreview();
|
||||
// wait until everything is initialized to update icons
|
||||
updateAllIconPreviews();
|
||||
|
||||
// update readonly fields
|
||||
handleReadOnly(settingsData, disabledFields);
|
||||
@@ -317,64 +335,7 @@
|
||||
showModalOK("Info", getString($(e).attr("my-set-key") + '_description'))
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
function askDeleteDeviceEvents () {
|
||||
// Check MAC
|
||||
if (mac == '') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ask delete device Events
|
||||
showModalWarning ('<?= lang('DevDetail_button_DeleteEvents');?>', '<?= lang('DevDetail_button_DeleteEvents_Warning');?>',
|
||||
'<?= lang('Gen_Cancel');?>', '<?= lang('Gen_Delete');?>', 'deleteDeviceEvents');
|
||||
}
|
||||
|
||||
function deleteDeviceEvents () {
|
||||
// Check MAC
|
||||
if (mac == '') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Delete device events
|
||||
$.get('php/server/devices.php?action=deleteDeviceEvents&mac='+ mac, function(msg) {
|
||||
showMessage (msg);
|
||||
});
|
||||
|
||||
// Deactivate controls
|
||||
$('#panDetails :input').attr('disabled', true);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
function askDeleteDevice () {
|
||||
// Check MAC
|
||||
if (mac == '') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ask delete device
|
||||
showModalWarning ('Delete Device', 'Are you sure you want to delete this device?<br>(maybe you prefer to archive it)',
|
||||
'<?= lang('Gen_Cancel');?>', '<?= lang('Gen_Delete');?>', 'deleteDevice');
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
function deleteDevice () {
|
||||
// Check MAC
|
||||
if (mac == '') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Delete device
|
||||
$.get('php/server/devices.php?action=deleteDevice&mac='+ mac, function(msg) {
|
||||
showMessage (msg);
|
||||
});
|
||||
|
||||
// Deactivate controls
|
||||
$('#panDetails :input').attr('disabled', true);
|
||||
|
||||
// refresh API
|
||||
updateApi("devices,appevents")
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
function setDeviceData(direction = '', refreshCallback = '') {
|
||||
@@ -396,51 +357,53 @@
|
||||
|
||||
showSpinner();
|
||||
|
||||
// update data to server
|
||||
$.get('php/server/devices.php?action=setDeviceData&mac='+ $('#NEWDEV_devMac').val()
|
||||
+ '&name=' + encodeURIComponent($('#NEWDEV_devName').val().replace(/'/g, ""))
|
||||
+ '&owner=' + encodeURIComponent($('#NEWDEV_devOwner').val().replace(/'/g, ""))
|
||||
+ '&type=' + $('#NEWDEV_devType').val().replace(/'/g, "")
|
||||
+ '&vendor=' + encodeURIComponent($('#NEWDEV_devVendor').val().replace(/'/g, ""))
|
||||
+ '&icon=' + encodeURIComponent($('#NEWDEV_devIcon').val())
|
||||
+ '&favorite=' + ($('#NEWDEV_devFavorite')[0].checked * 1)
|
||||
+ '&group=' + encodeURIComponent($('#NEWDEV_devGroup').val().replace(/'/g, ""))
|
||||
+ '&location=' + encodeURIComponent($('#NEWDEV_devLocation').val().replace(/'/g, ""))
|
||||
+ '&comments=' + encodeURIComponent(encodeSpecialChars($('#NEWDEV_devComments').val()))
|
||||
+ '&networknode=' + $('#NEWDEV_devParentMAC').val()
|
||||
+ '&networknodeport=' + $('#NEWDEV_devParentPort').val()
|
||||
+ '&ssid=' + $('#NEWDEV_devSSID').val()
|
||||
+ '&networksite=' + $('#NEWDEV_devSite').val()
|
||||
+ '&staticIP=' + ($('#NEWDEV_devStaticIP')[0].checked * 1)
|
||||
+ '&scancycle=' + "1"
|
||||
+ '&alertevents=' + ($('#NEWDEV_devAlertEvents')[0].checked * 1)
|
||||
+ '&alertdown=' + ($('#NEWDEV_devAlertDown')[0].checked * 1)
|
||||
+ '&skiprepeated=' + $('#NEWDEV_devSkipRepeated').val().split(' ')[0]
|
||||
+ '&newdevice=' + ($('#NEWDEV_devIsNew')[0].checked * 1)
|
||||
+ '&archived=' + ($('#NEWDEV_devIsArchived')[0].checked * 1)
|
||||
+ '&devFirstConnection=' + ($('#NEWDEV_devFirstConnection').val())
|
||||
+ '&devLastConnection=' + ($('#NEWDEV_devLastConnection').val())
|
||||
+ '&ip=' + ($('#NEWDEV_devLastIP').val())
|
||||
+ '&createNew=' + createNew
|
||||
, function(msg) {
|
||||
|
||||
showMessage (msg);
|
||||
// Update data to server using POST
|
||||
$.post('php/server/devices.php?action=setDeviceData', {
|
||||
mac: $('#NEWDEV_devMac').val(),
|
||||
name: encodeURIComponent($('#NEWDEV_devName').val().replace(/'/g, "")),
|
||||
owner: encodeURIComponent($('#NEWDEV_devOwner').val().replace(/'/g, "")),
|
||||
type: $('#NEWDEV_devType').val().replace(/'/g, ""),
|
||||
vendor: encodeURIComponent($('#NEWDEV_devVendor').val().replace(/'/g, "")),
|
||||
icon: encodeURIComponent($('#NEWDEV_devIcon').val()),
|
||||
favorite: ($('#NEWDEV_devFavorite')[0].checked * 1),
|
||||
group: encodeURIComponent($('#NEWDEV_devGroup').val().replace(/'/g, "")),
|
||||
location: encodeURIComponent($('#NEWDEV_devLocation').val().replace(/'/g, "")),
|
||||
comments: encodeURIComponent(encodeSpecialChars($('#NEWDEV_devComments').val())),
|
||||
networknode: $('#NEWDEV_devParentMAC').val(),
|
||||
networknodeport: $('#NEWDEV_devParentPort').val(),
|
||||
ssid: $('#NEWDEV_devSSID').val(),
|
||||
networksite: $('#NEWDEV_devSite').val(),
|
||||
staticIP: ($('#NEWDEV_devStaticIP')[0].checked * 1),
|
||||
scancycle: "1",
|
||||
alertevents: ($('#NEWDEV_devAlertEvents')[0].checked * 1),
|
||||
alertdown: ($('#NEWDEV_devAlertDown')[0].checked * 1),
|
||||
skiprepeated: $('#NEWDEV_devSkipRepeated').val().split(' ')[0],
|
||||
newdevice: ($('#NEWDEV_devIsNew')[0].checked * 1),
|
||||
archived: ($('#NEWDEV_devIsArchived')[0].checked * 1),
|
||||
devFirstConnection: ($('#NEWDEV_devFirstConnection').val()),
|
||||
devLastConnection: ($('#NEWDEV_devLastConnection').val()),
|
||||
devCustomProps: btoa(JSON.stringify(collectTableData("#NEWDEV_devCustomProps_table"))),
|
||||
ip: ($('#NEWDEV_devLastIP').val()),
|
||||
createNew: createNew
|
||||
}, function(msg) {
|
||||
showMessage(msg);
|
||||
|
||||
// Remove navigation prompt "Are you sure you want to leave..."
|
||||
window.onbeforeunload = null;
|
||||
somethingChanged = false;
|
||||
// Remove navigation prompt "Are you sure you want to leave..."
|
||||
window.onbeforeunload = null;
|
||||
somethingChanged = false;
|
||||
|
||||
// refresh API
|
||||
updateApi("devices,appevents")
|
||||
// refresh API
|
||||
updateApi("devices,appevents");
|
||||
|
||||
// Callback fuction
|
||||
if (typeof refreshCallback == 'function') {
|
||||
refreshCallback(direction);
|
||||
}
|
||||
// Callback function
|
||||
if (typeof refreshCallback == 'function') {
|
||||
refreshCallback(direction);
|
||||
}
|
||||
|
||||
// Everything loaded
|
||||
hideSpinner();
|
||||
});
|
||||
|
||||
// everything loaded
|
||||
hideSpinner();
|
||||
});
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------
|
||||
|
||||
@@ -227,11 +227,7 @@ function initializeCalendar() {
|
||||
loading: function( isLoading, view ) {
|
||||
if (isLoading) {
|
||||
showSpinner()
|
||||
} else {
|
||||
// setTimeout(() => {
|
||||
// updateIconPreview($('#txtIcon'))
|
||||
// }, 500);
|
||||
|
||||
} else {
|
||||
hideSpinner()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,6 +65,48 @@
|
||||
|
||||
<?php } ?>
|
||||
|
||||
|
||||
<!-- Delete Events -->
|
||||
<h4 class=""><i class="fa-solid fa-bell"></i>
|
||||
<?= lang("DevDetail_button_DeleteEvents") ?>
|
||||
</h4>
|
||||
<h5 class="">
|
||||
<?= lang("DevDetail_button_DeleteEvents_Warning") ?>
|
||||
</h5>
|
||||
<br>
|
||||
<div style="width:100%; text-align: center; margin-bottom: 50px;">
|
||||
<button type="button"
|
||||
class="btn btn-default pa-btn pa-btn-delete"
|
||||
style="margin-left:0px;"
|
||||
id="btnDeleteEvents"
|
||||
onclick="askDeleteDeviceEvents()">
|
||||
<?= lang('DevDetail_button_DeleteEvents');?>
|
||||
</button>
|
||||
<br>
|
||||
<div id="wol_output" style="margin-top: 10px;"></div>
|
||||
</div>
|
||||
|
||||
<!-- Reset Custom Proprties -->
|
||||
<h4 class=""><i class="fa-solid fa-list"></i>
|
||||
<?= lang("DevDetail_CustomProperties_Title") ?>
|
||||
</h4>
|
||||
<h5 class="">
|
||||
<?= lang("DevDetail_CustomProps_reset_info") ?>
|
||||
</h5>
|
||||
<br>
|
||||
<div style="width:100%; text-align: center; margin-bottom: 50px;">
|
||||
<button type="button"
|
||||
class="btn btn-default pa-btn pa-btn-delete"
|
||||
style="margin-left:0px;"
|
||||
id="btnDeleteEvents"
|
||||
onclick="askResetDeviceProps()">
|
||||
<?= lang("Gen_Reset") ?>
|
||||
</button>
|
||||
<br>
|
||||
<div id="wol_output" style="margin-top: 10px;"></div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- SPEEDTEST -->
|
||||
<?php if ($_REQUEST["mac"] == "Internet") { ?>
|
||||
<h4 class=""><i class="fa-solid fa-gauge-high"></i>
|
||||
@@ -336,6 +378,56 @@
|
||||
return devicesList;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
function askDeleteDeviceEvents () {
|
||||
// Check MAC
|
||||
if (mac == '') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ask delete device Events
|
||||
showModalWarning ('<?= lang('DevDetail_button_DeleteEvents');?>', '<?= lang('DevDetail_button_DeleteEvents_Warning');?>',
|
||||
'<?= lang('Gen_Cancel');?>', '<?= lang('Gen_Delete');?>', 'deleteDeviceEvents');
|
||||
}
|
||||
|
||||
function deleteDeviceEvents () {
|
||||
// Check MAC
|
||||
if (mac == '') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Delete device events
|
||||
$.get('php/server/devices.php?action=deleteDeviceEvents&mac='+ mac, function(msg) {
|
||||
showMessage (msg);
|
||||
});
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
function askResetDeviceProps () {
|
||||
// Check MAC
|
||||
if (mac == '') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ask Resert Custom properties
|
||||
showModalWarning ('<?= lang('Gen_Reset');?>', '<?= lang('DevDetail_CustomProps_reset_info');?>',
|
||||
'<?= lang('Gen_Cancel');?>', '<?= lang('Gen_Delete');?>', 'resetDeviceProps');
|
||||
}
|
||||
|
||||
function resetDeviceProps () {
|
||||
// Check MAC
|
||||
if (mac == '') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Execute
|
||||
$.get('php/server/devices.php?action=resetDeviceProps&mac='+ mac, function(msg) {
|
||||
showMessage (msg);
|
||||
});
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
function internetinfo() {
|
||||
$( "#internetinfooutput" ).empty();
|
||||
|
||||
@@ -144,6 +144,10 @@ function main () {
|
||||
//initialize the table headers in the correct order
|
||||
var availableColumns = getSettingOptions("UI_device_columns").split(",");
|
||||
headersDefaultOrder = availableColumns.map(val => getString(val));
|
||||
|
||||
console.log(headersDefaultOrder);
|
||||
|
||||
|
||||
var selectedColumns = JSON.parse(getSetting("UI_device_columns").replace(/'/g, '"'));
|
||||
|
||||
// generate default order lists of given length
|
||||
@@ -181,6 +185,9 @@ function main () {
|
||||
// mapping the default order to the user specified one
|
||||
function mapIndx(oldIndex)
|
||||
{
|
||||
// console.log(oldIndex);
|
||||
// console.log(tableColumnOrder);
|
||||
|
||||
for(i=0;i<tableColumnOrder.length;i++)
|
||||
{
|
||||
if(tableColumnOrder[i] == oldIndex)
|
||||
@@ -359,7 +366,8 @@ function mapColumnIndexToFieldName(index, tableColumnVisible) {
|
||||
"devSSID",
|
||||
"devSourcePlugin",
|
||||
"devPresentLastScan",
|
||||
"devAlertDown"
|
||||
"devAlertDown",
|
||||
"devCustomProps"
|
||||
];
|
||||
|
||||
// console.log("OrderBy: " + columnNames[tableColumnOrder[index]]);
|
||||
@@ -469,6 +477,7 @@ function initializeDatatable (status) {
|
||||
devStatus
|
||||
devParentChildrenCount
|
||||
devIpLong
|
||||
devCustomProps
|
||||
}
|
||||
count
|
||||
}
|
||||
@@ -535,7 +544,8 @@ function initializeDatatable (status) {
|
||||
device.devSSID || "",
|
||||
device.devSourcePlugin || "",
|
||||
device.devPresentLastScan || "",
|
||||
device.devAlertDown || ""
|
||||
device.devAlertDown || "",
|
||||
device.devCustomProps || ""
|
||||
];
|
||||
|
||||
const newRow = [];
|
||||
@@ -652,6 +662,17 @@ function initializeDatatable (status) {
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Custom Properties
|
||||
{targets: [mapIndx(26)],
|
||||
'createdCell': function (td, cellData, rowData, row, col) {
|
||||
if (!emptyArr.includes(cellData)){
|
||||
$(td).html (`<span>${renderCustomProps(cellData, rowData[mapIndx(11)])}<span>`);
|
||||
} else {
|
||||
$(td).html ('');
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Favorite
|
||||
{targets: [mapIndx(4)],
|
||||
@@ -830,34 +851,88 @@ function multiEditDevices()
|
||||
// -----------------------------------------------------------------------------
|
||||
// Function collects shown devices from the DataTable
|
||||
function getMacsOfShownDevices() {
|
||||
|
||||
rows = $('#tableDevices')[0].rows
|
||||
macs = []
|
||||
rows = $('#tableDevices')[0].rows;
|
||||
macs = [];
|
||||
|
||||
// var devicesDataTableData = $('#tableDevices').dataTable().fnGetData();
|
||||
var devicesDataTableData = $('#tableDevices').DataTable().rows({ selected: false, page: 'current' }).data().toArray();
|
||||
|
||||
console.log(devicesDataTableData);
|
||||
|
||||
|
||||
var selectedDevices = [];
|
||||
|
||||
// first row is the heading, skip
|
||||
for (var i = 1; i < rows.length; i++) {
|
||||
|
||||
// console.log(rows[i]._DT_RowIndex);
|
||||
var rowIndex = rows[i]._DT_RowIndex;
|
||||
|
||||
selectedDevices.push(devicesDataTableData[rows[i]._DT_RowIndex]);
|
||||
}
|
||||
// Ensure the rowIndex is valid and within bounds of devicesDataTableData
|
||||
if (rowIndex >= 0 && rowIndex < devicesDataTableData.length) {
|
||||
selectedDevices.push(devicesDataTableData[rowIndex]);
|
||||
} else {
|
||||
console.log(`Invalid rowIndex: ${rowIndex} at row ${i}`);
|
||||
}
|
||||
}
|
||||
|
||||
for (var j = 0; j < selectedDevices.length; j++) {
|
||||
macs.push(selectedDevices[j][mapIndx(11)]); // mapIndx(11) == MAC
|
||||
// Ensure that selectedDevices[j] is not undefined
|
||||
if (selectedDevices[j]) {
|
||||
macs.push(selectedDevices[j][mapIndx(11)]); // mapIndx(11) == MAC
|
||||
} else {
|
||||
console.log(`selectedDevices[${j}] is undefined`);
|
||||
}
|
||||
}
|
||||
|
||||
return macs;
|
||||
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Handle custom actions/properties on a device
|
||||
// -----------------------------------------------------------------------------
|
||||
// Handle custom actions/properties on a device
|
||||
function renderCustomProps(custProps, mac) {
|
||||
// Decode and parse the custom properties
|
||||
|
||||
// console.log(custProps);
|
||||
|
||||
const props = JSON.parse(atob(custProps));
|
||||
let html = "";
|
||||
|
||||
props.forEach((propGroup, index) => {
|
||||
const propMap = Object.fromEntries(
|
||||
propGroup.map(prop => Object.entries(prop)[0]) // Convert array of objects to key-value pairs
|
||||
);
|
||||
|
||||
if (propMap["CUSTPROP_show"] === true) { // Render if visible
|
||||
let onClickEvent = "";
|
||||
|
||||
switch (propMap["CUSTPROP_type"]) {
|
||||
case "show_notes":
|
||||
onClickEvent = `showModalOK('${propMap["CUSTPROP_name"]}','${propMap["CUSTPROP_notes"]}')`;
|
||||
break;
|
||||
case "link":
|
||||
onClickEvent = `window.location.href='${propMap["CUSTPROP_args"]}';`;
|
||||
break;
|
||||
case "link_new_tab":
|
||||
onClickEvent = `openInNewTab('${propMap["CUSTPROP_args"]}')`;
|
||||
break;
|
||||
case "run_plugin":
|
||||
onClickEvent = `alert('Not implemented')`;
|
||||
break;
|
||||
case "delete_dev":
|
||||
onClickEvent = `deleteDeviceByMac('${mac}')`;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
html += `<span class="pointer" onclick="${onClickEvent}" title="${propMap["CUSTPROP_name"]} ${propMap["CUSTPROP_args"]}"> ${atob(propMap["CUSTPROP_icon"])} </span>`;
|
||||
}
|
||||
});
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Update cache with shown devices before navigating away
|
||||
|
||||
@@ -171,7 +171,7 @@ function cacheSettings()
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Get a setting value by key
|
||||
// Get a setting options value by key
|
||||
function getSettingOptions (key) {
|
||||
|
||||
// handle initial load to make sure everything is set-up and cached
|
||||
@@ -353,6 +353,30 @@ function getLangCode() {
|
||||
// String utilities
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// ----------------------------------------------------
|
||||
/**
|
||||
* Replaces double quotes within single-quoted strings, then converts all single quotes to double quotes,
|
||||
* while preserving the intended structure.
|
||||
*
|
||||
* @param {string} inputString - The input string to process.
|
||||
* @returns {string} - The processed string with transformations applied.
|
||||
*/
|
||||
function processQuotes(inputString) {
|
||||
// Step 1: Replace double quotes within single-quoted strings
|
||||
let tempString = inputString.replace(/'([^']*?)'/g, (match, p1) => {
|
||||
const escapedContent = p1.replace(/"/g, '_escaped_double_quote_'); // Temporarily replace double quotes
|
||||
return `'${escapedContent}'`;
|
||||
});
|
||||
|
||||
// Step 2: Replace all single quotes with double quotes
|
||||
tempString = tempString.replace(/'/g, '"');
|
||||
|
||||
// Step 3: Restore escaped double quotes
|
||||
const processedString = tempString.replace(/_escaped_double_quote_/g, "'");
|
||||
|
||||
return processedString;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------
|
||||
function jsonSyntaxHighlight(json) {
|
||||
if (typeof json != 'string') {
|
||||
|
||||
47
front/js/device.js
Executable file
47
front/js/device.js
Executable file
@@ -0,0 +1,47 @@
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
function askDeleteDevice () {
|
||||
// Check MAC
|
||||
if (mac == '') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ask delete device
|
||||
showModalWarning ('Delete Device', 'Are you sure you want to delete this device?<br>(maybe you prefer to archive it)',
|
||||
getString('Gen_Cancel'), getString('Gen_Delete'), 'deleteDevice');
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
function deleteDevice () {
|
||||
// Check MAC
|
||||
if (mac == '') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Delete device
|
||||
$.get('php/server/devices.php?action=deleteDevice&mac='+ mac, function(msg) {
|
||||
showMessage (msg);
|
||||
});
|
||||
|
||||
// refresh API
|
||||
updateApi("devices,appevents")
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
function deleteDeviceByMac (mac) {
|
||||
// Check MAC
|
||||
if (mac == '') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Delete device
|
||||
$.get('php/server/devices.php?action=deleteDevice&mac='+ mac, function(msg) {
|
||||
showMessage (msg);
|
||||
});
|
||||
|
||||
// refresh API
|
||||
updateApi("devices,appevents")
|
||||
}
|
||||
|
||||
@@ -245,6 +245,68 @@ function settingsCollectedCorrectly(settingsArray, settingsJSON_DB) {
|
||||
// Manipulating Editable List options
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// Add row to datatable
|
||||
function addDataTableRow(el)
|
||||
{
|
||||
alert("a")
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// Clone datatable row
|
||||
function cloneDataTableRow(el){
|
||||
|
||||
console.log(el);
|
||||
|
||||
const id = "NEWDEV_devCustomProps_table"; // Your table ID
|
||||
const table = $('#'+id).DataTable();
|
||||
|
||||
|
||||
// Get the 'my-index' attribute from the closest tr element
|
||||
const myIndex = parseInt($(el).closest("tr").attr("my-index"));
|
||||
|
||||
// Find the row in the table with the matching 'my-index'
|
||||
const row = table.rows().nodes().to$().filter(`[my-index="${myIndex}"]`).first().get(0);
|
||||
|
||||
// Clone the row (including its data and controls)
|
||||
let clonedRow = $(row).clone(true, true); // The true arguments copy the data and event handlers
|
||||
|
||||
|
||||
$(clonedRow).attr("my-index",table.rows().count())
|
||||
|
||||
|
||||
console.log(clonedRow);
|
||||
|
||||
|
||||
// Add the cloned row to the DataTable
|
||||
table.row.add(clonedRow[0]).draw();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// Remove current datatable row
|
||||
function removeDataTableRow(el) {
|
||||
console.log(el);
|
||||
|
||||
const id = "NEWDEV_devCustomProps_table"; // Your table ID
|
||||
const table = $('#'+id).DataTable();
|
||||
|
||||
if(table.rows().count() > 1)
|
||||
{
|
||||
// Get the 'my-index' attribute from the closest tr element
|
||||
const myIndex = parseInt($(el).closest("tr").attr("my-index"));
|
||||
|
||||
// Find the row in the table with the matching 'my-index'
|
||||
const row = table.rows().nodes().to$().filter(`[my-index="${myIndex}"]`).first().get(0);
|
||||
|
||||
// Remove the row from the DataTable
|
||||
table.row(row).remove().draw();
|
||||
}
|
||||
else
|
||||
{
|
||||
showMessage (getString("CustProps_cant_remove"), 3000, "modal_red");
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// Add item to list
|
||||
function addList(element, clearInput = true) {
|
||||
@@ -551,7 +613,7 @@ function overrideToggle(element) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// Generate options or set options based on the provided parameters
|
||||
function generateOptionsOrSetOptions(
|
||||
setKey,
|
||||
@@ -559,14 +621,21 @@ function generateOptionsOrSetOptions(
|
||||
placeholder, // ID of the HTML element where dropdown should be rendered (will be replaced)
|
||||
processDataCallback, // Callback function to generate entries based on options
|
||||
targetField, // Target field or element where selected value should be applied or updated
|
||||
transformers = [] // Transformers to be applied to the values
|
||||
transformers = [], // Transformers to be applied to the values
|
||||
overrideOptions = null // override options if available
|
||||
) {
|
||||
|
||||
// console.log(setKey);
|
||||
|
||||
// NOTE {value} options to replace with a setting or SQL value are handled in the cacheSettings() function
|
||||
options = arrayToObject(createArray(getSettingOptions(setKey)))
|
||||
// console.log(overrideOptions);
|
||||
// console.log( getSettingOptions(setKey));
|
||||
// console.log( setKey);
|
||||
|
||||
// NOTE {value} options to replace with a setting or SQL value are handled in the cacheSettings() function
|
||||
options = arrayToObject(createArray(overrideOptions ? overrideOptions : getSettingOptions(setKey)))
|
||||
|
||||
|
||||
|
||||
// Call to render lists
|
||||
renderList(
|
||||
options,
|
||||
@@ -655,6 +724,7 @@ const handleElementOptions = (setKey, elementOptions, transformers, val) => {
|
||||
let onChange = "console.log('onChange - Not implemented');";
|
||||
let customParams = "";
|
||||
let customId = "";
|
||||
let columns = [];
|
||||
|
||||
|
||||
elementOptions.forEach((option) => {
|
||||
@@ -708,6 +778,9 @@ const handleElementOptions = (setKey, elementOptions, transformers, val) => {
|
||||
if (option.customId) {
|
||||
customId = option.customId;
|
||||
}
|
||||
if (option.columns) {
|
||||
columns = option.columns;
|
||||
}
|
||||
});
|
||||
|
||||
if (transformers.includes("sha256")) {
|
||||
@@ -730,7 +803,8 @@ const handleElementOptions = (setKey, elementOptions, transformers, val) => {
|
||||
onClick,
|
||||
onChange,
|
||||
customParams,
|
||||
customId
|
||||
customId,
|
||||
columns
|
||||
};
|
||||
};
|
||||
|
||||
@@ -863,7 +937,7 @@ function genListWithInputSet(options, valuesArray, targetField, transformers, pl
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Generate the form control for setting
|
||||
function generateFormHtml(set, overrideValue) {
|
||||
function generateFormHtml(settingsData, set, overrideValue, overrideOptions, originalSetKey) {
|
||||
let inputHtml = '';
|
||||
|
||||
|
||||
@@ -872,13 +946,13 @@ function generateFormHtml(set, overrideValue) {
|
||||
const setType = set['setType'];
|
||||
|
||||
// console.log(setType);
|
||||
// console.log(setTypeEscaped); // Final transformed result
|
||||
// console.log(setKey);
|
||||
// console.log(overrideValue);
|
||||
// console.log(inVal);
|
||||
|
||||
// console.log(inVal);
|
||||
|
||||
// Parse the setType JSON string
|
||||
const setTypeObject = JSON.parse(setType.replace(/'/g, '"'));
|
||||
const setTypeObject = JSON.parse(processQuotes(setType))
|
||||
const dataType = setTypeObject.dataType;
|
||||
const elements = setTypeObject.elements || [];
|
||||
|
||||
@@ -903,14 +977,12 @@ function generateFormHtml(set, overrideValue) {
|
||||
onClick,
|
||||
onChange,
|
||||
customParams,
|
||||
customId
|
||||
customId,
|
||||
columns
|
||||
} = handleElementOptions(setKey, elementOptions, transformers, inVal);
|
||||
|
||||
// Override value
|
||||
const val = valRes;
|
||||
|
||||
// console.log(val);
|
||||
|
||||
let val = valRes;
|
||||
|
||||
// Generate HTML based on elementType
|
||||
switch (elementType) {
|
||||
@@ -921,20 +993,21 @@ function generateFormHtml(set, overrideValue) {
|
||||
inputHtml += `<select onChange="settingsChanged();${onChange}"
|
||||
my-data-type="${dataType}"
|
||||
my-editable="${editable}"
|
||||
class="form-control ${addCss}"
|
||||
class="form-control ${addCss} ${cssClasses}"
|
||||
name="${setKey}"
|
||||
id="${setKey}"
|
||||
my-customparams="${customParams}"
|
||||
my-customid="${customId}"
|
||||
my-originalSetKey="${originalSetKey}"
|
||||
${multi}>
|
||||
<option value="" id="${setKey + "_temp_"}"></option>
|
||||
</select>`;
|
||||
|
||||
generateOptionsOrSetOptions(setKey, createArray(val), `${setKey}_temp_`, generateOptions, null, transformers);
|
||||
generateOptionsOrSetOptions(setKey, createArray(val), `${setKey}_temp_`, generateOptions, null, transformers, overrideOptions);
|
||||
break;
|
||||
|
||||
case 'input':
|
||||
const checked = val === 'True' || val === '1' ? 'checked' : '';
|
||||
const checked = val === 'True' || val === 'true' || val === '1' ? 'checked' : '';
|
||||
const inputClass = inputType === 'checkbox' ? 'checkbox' : 'form-control';
|
||||
|
||||
inputHtml += `<input
|
||||
@@ -943,6 +1016,7 @@ function generateFormHtml(set, overrideValue) {
|
||||
my-data-type="${dataType}"
|
||||
my-customparams="${customParams}"
|
||||
my-customid="${customId}"
|
||||
my-originalSetKey="${originalSetKey}"
|
||||
id="${setKey}${suffix}"
|
||||
type="${inputType}"
|
||||
value="${val}"
|
||||
@@ -957,6 +1031,7 @@ function generateFormHtml(set, overrideValue) {
|
||||
class="btn btn-primary ${cssClasses}"
|
||||
my-customparams="${customParams}"
|
||||
my-customid="${customId}"
|
||||
my-originalSetKey="${originalSetKey}"
|
||||
my-input-from="${sourceIds}"
|
||||
my-input-to="${setKey}"
|
||||
onclick="${onClick}">
|
||||
@@ -969,6 +1044,7 @@ function generateFormHtml(set, overrideValue) {
|
||||
class="form-control input"
|
||||
my-customparams="${customParams}"
|
||||
my-customid="${customId}"
|
||||
my-originalSetKey="${originalSetKey}"
|
||||
my-data-type="${dataType}"
|
||||
id="${setKey}"
|
||||
${readOnly}>${val}</textarea>`;
|
||||
@@ -979,10 +1055,115 @@ function generateFormHtml(set, overrideValue) {
|
||||
class="${cssClasses}"
|
||||
my-data-type="${dataType}"
|
||||
my-customparams="${customParams}"
|
||||
my-customid="${customId}">
|
||||
${getString(getStringKey)}
|
||||
my-customid="${customId}"
|
||||
my-originalSetKey="${originalSetKey}"
|
||||
onclick="${onClick}">
|
||||
${getString(getStringKey)}${placeholder}
|
||||
</span>`;
|
||||
break;
|
||||
case 'datatable':
|
||||
|
||||
const tableId = `${setKey}_table`;
|
||||
let datatableHtml = `<table id="${tableId}" class="table table-striped">`;
|
||||
|
||||
// Dynamic array creation
|
||||
let emptyVal = [];
|
||||
|
||||
let columnSettings = [];
|
||||
|
||||
// Generate table headers
|
||||
datatableHtml += '<thead><tr>';
|
||||
|
||||
columns.forEach(column => {
|
||||
let columnSetting = getSetObject(settingsData, column.settingKey) || {};
|
||||
|
||||
datatableHtml += `<th>${columnSetting.setName}</th>`;
|
||||
|
||||
if(column.typeOverride)
|
||||
{
|
||||
columnSetting["setType"] = JSON.stringify(column.typeOverride);
|
||||
}
|
||||
|
||||
if(column.optionsOverride)
|
||||
{
|
||||
if (column.optionsOverride.startsWith("setting.")) {
|
||||
columnSetting["setOptions"] = getSetting(column.optionsOverride.replace("setting.",""));
|
||||
} else {
|
||||
columnSetting["setOptions"] = column.optionsOverride;
|
||||
}
|
||||
}
|
||||
|
||||
columnSettings.push(columnSetting)
|
||||
|
||||
// helper for if val is empty
|
||||
emptyVal.push('');
|
||||
});
|
||||
datatableHtml += '</tr></thead>';
|
||||
|
||||
// Generate table body
|
||||
datatableHtml += '<tbody>';
|
||||
|
||||
if(val.length > 0 && isBase64(val))
|
||||
{
|
||||
val = atob(val)
|
||||
// console.log(val);
|
||||
val = JSON.parse(val)
|
||||
}else{
|
||||
// init empty
|
||||
val = [emptyVal]
|
||||
}
|
||||
|
||||
let index = 0;
|
||||
val.forEach(rowData => {
|
||||
datatableHtml += `<tr my-index="${index}">`;
|
||||
|
||||
let j = 0;
|
||||
columnSettings.forEach(set => {
|
||||
// Extract the value for the current column based on the new structure
|
||||
let columnOverrideValue = rowData[j] && Object.values(rowData[j])[0];
|
||||
|
||||
if(columnOverrideValue == undefined)
|
||||
{
|
||||
columnOverrideValue = ""
|
||||
}
|
||||
|
||||
// Create unique key to prevent dropdown data duplication
|
||||
const oldKey = set["setKey"];
|
||||
set["setKey"] = oldKey + "_" + index;
|
||||
|
||||
// Generate the cell HTML using the extracted value
|
||||
const cellHtml = generateFormHtml(
|
||||
settingsData,
|
||||
set,
|
||||
columnOverrideValue.toString(),
|
||||
set["setOptions"],
|
||||
oldKey
|
||||
);
|
||||
datatableHtml += `<td> <div class="input-group"> ${cellHtml} </div></td>`;
|
||||
|
||||
// Restore the original key
|
||||
set["setKey"] = oldKey;
|
||||
|
||||
j++;
|
||||
});
|
||||
datatableHtml += '</tr>';
|
||||
index++;
|
||||
});
|
||||
|
||||
|
||||
datatableHtml += '</tbody></table>';
|
||||
|
||||
inputHtml += datatableHtml;
|
||||
|
||||
// Initialize DataTable with jQuery
|
||||
$(document).ready(() => {
|
||||
$(`#${tableId}`).DataTable({
|
||||
ordering: false, // Disables sorting on all columns
|
||||
searching: false // Disables the search box
|
||||
});
|
||||
});
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
console.warn(`🟥 Unknown element type: ${elementType}`);
|
||||
@@ -991,10 +1172,6 @@ function generateFormHtml(set, overrideValue) {
|
||||
|
||||
// Generate event HTML if applicable
|
||||
let eventsHtml = '';
|
||||
|
||||
// console.log(setTypeObject);
|
||||
|
||||
// console.log(set);
|
||||
|
||||
const eventsList = createArray(set['setEvents']);
|
||||
// inline buttons events
|
||||
@@ -1019,4 +1196,68 @@ function generateFormHtml(set, overrideValue) {
|
||||
return inputHtml + eventsHtml;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------
|
||||
// Return the setting object by setKey
|
||||
function getSetObject(settingsData, setKey) {
|
||||
|
||||
found = false;
|
||||
result = ""
|
||||
|
||||
settingsData.forEach(function(set) {
|
||||
|
||||
if (set.setKey == setKey) {
|
||||
// console.log(set);
|
||||
|
||||
result = set;
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
if(result == "")
|
||||
{
|
||||
console.error(settingsData);
|
||||
console.error(`Setting not found: ${setKey}`);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// ---------------------------------------
|
||||
// Collect DataTable data
|
||||
function collectTableData(tableSelector) {
|
||||
const table = $(tableSelector).DataTable();
|
||||
|
||||
let tableData = [];
|
||||
|
||||
table.rows().every(function () {
|
||||
const rowData = [];
|
||||
const cells = $(this.node()).find('td');
|
||||
|
||||
cells.each((index, cell) => {
|
||||
const input = $(cell).find('input, select, textarea');
|
||||
|
||||
if (input.length) {
|
||||
if (input.attr('type') === 'checkbox') {
|
||||
// For checkboxes, check if they are checked
|
||||
rowData[index] = { [input.attr("my-originalsetkey")] : input.prop('checked') };
|
||||
} else {
|
||||
// Generic sync for other inputs (text, select, textarea)
|
||||
rowData[index] = { [input.attr("my-originalsetkey")] : input.val() };
|
||||
}
|
||||
} else {
|
||||
// Handle plain text
|
||||
// rowData[index] = { [input.attr("my-originalsetkey")] : $(cell).text()};
|
||||
console.log(`Nothig to collect: ${$(cell).html()}`)
|
||||
}
|
||||
});
|
||||
|
||||
tableData.push(rowData);
|
||||
});
|
||||
|
||||
return tableData;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -98,11 +98,22 @@ function generateApiToken(elem, length) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// ----------------------------------------------
|
||||
// Updates the icon preview
|
||||
function updateAllIconPreviews() {
|
||||
$(".iconInputVal").each((index, el)=>{
|
||||
updateIconPreview(el)
|
||||
})
|
||||
}
|
||||
|
||||
// ----------------------------------------------
|
||||
// Updates the icon preview
|
||||
function updateIconPreview(elem) {
|
||||
const targetElement = $('[my-customid="NEWDEV_devIcon_preview"]');
|
||||
const iconInput = $("#NEWDEV_devIcon");
|
||||
|
||||
const previewSpan = $(elem).parent().find(".iconPreview");
|
||||
const iconInput = $(elem);
|
||||
|
||||
let attempts = 0;
|
||||
|
||||
@@ -110,10 +121,10 @@ function updateIconPreview(elem) {
|
||||
let value = iconInput.val();
|
||||
|
||||
if (value) {
|
||||
targetElement.html(atob(value));
|
||||
previewSpan.html(atob(value));
|
||||
iconInput.off('change input').on('change input', function () {
|
||||
let newValue = $(this).val();
|
||||
targetElement.html(atob(newValue));
|
||||
let newValue = $(elem).val();
|
||||
previewSpan.html(atob(newValue));
|
||||
});
|
||||
return; // Stop retrying if successful
|
||||
}
|
||||
@@ -449,7 +460,7 @@ function showIconSelection() {
|
||||
iconDiv.addEventListener('click', () => {
|
||||
selectElement.value = value; // Update the select element value
|
||||
$(`#${modalId}`).modal('hide'); // Hide the modal
|
||||
updateIconPreview();
|
||||
updateAllIconPreviews();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -81,7 +81,7 @@
|
||||
|
||||
settingsData = res["data"];
|
||||
|
||||
excludedColumns = ["NEWDEV_devMac", "NEWDEV_devFirstConnection", "NEWDEV_devLastConnection", "NEWDEV_devLastNotification", "NEWDEV_devLastIP", "NEWDEV_devStaticIP", "NEWDEV_devScan", "NEWDEV_devPresentLastScan" ]
|
||||
excludedColumns = ["NEWDEV_devMac", "NEWDEV_devFirstConnection", "NEWDEV_devLastConnection", "NEWDEV_devLastNotification", "NEWDEV_devLastIP", "NEWDEV_devStaticIP", "NEWDEV_devScan", "NEWDEV_devPresentLastScan", "NEWDEV_devCustomProps" ]
|
||||
|
||||
const relevantColumns = settingsData.filter(set =>
|
||||
set.setGroup === "NEWDEV" &&
|
||||
@@ -90,21 +90,21 @@
|
||||
!set.setKey.includes("__metadata")
|
||||
);
|
||||
|
||||
const generateSimpleForm = columns => {
|
||||
const generateSimpleForm = multiEditColumns => {
|
||||
const form = $('#multi-edit-form');
|
||||
const numColumns = 2; // Number of columns
|
||||
|
||||
// Calculate number of elements per column
|
||||
const elementsPerColumn = Math.ceil(columns.length / numColumns);
|
||||
const elementsPerColumn = Math.ceil(multiEditColumns.length / numColumns);
|
||||
|
||||
// Divide columns equally
|
||||
for (let i = 0; i < numColumns; i++) {
|
||||
const column = $('<div>').addClass('col-md-6');
|
||||
|
||||
// Append form groups to the column
|
||||
for (let j = i * elementsPerColumn; j < Math.min((i + 1) * elementsPerColumn, columns.length); j++) {
|
||||
for (let j = i * elementsPerColumn; j < Math.min((i + 1) * elementsPerColumn, multiEditColumns.length); j++) {
|
||||
|
||||
const setTypeObject = JSON.parse(columns[j].setType.replace(/'/g, '"'));
|
||||
const setTypeObject = JSON.parse(multiEditColumns[j].setType.replace(/'/g, '"'));
|
||||
|
||||
// get the element with the input value(s)
|
||||
let elements = setTypeObject.elements.filter(element => element.elementHasInputValue === 1);
|
||||
@@ -135,37 +135,38 @@
|
||||
onClick,
|
||||
onChange,
|
||||
customParams,
|
||||
customId
|
||||
customId,
|
||||
columns
|
||||
} = handleElementOptions('none', elementOptions, transformers, val = "");
|
||||
|
||||
// render based on element type
|
||||
if (elementType === 'select') {
|
||||
|
||||
targetLocation = columns[j].setKey + "_generateSetOptions"
|
||||
targetLocation = multiEditColumns[j].setKey + "_generateSetOptions"
|
||||
|
||||
generateOptionsOrSetOptions(columns[j].setKey, [], targetLocation, generateOptions)
|
||||
generateOptionsOrSetOptions(multiEditColumns[j].setKey, [], targetLocation, generateOptions, null)
|
||||
|
||||
console.log(columns[j].setKey)
|
||||
console.log(multiEditColumns[j].setKey)
|
||||
// Handle Icons as they need a preview
|
||||
if(columns[j].setKey == 'NEWDEV_devIcon')
|
||||
if(multiEditColumns[j].setKey == 'NEWDEV_devIcon')
|
||||
{
|
||||
input = `
|
||||
<span class="input-group-addon iconPreview" my-customid="NEWDEV_devIcon_preview"></span>
|
||||
<select class="form-control"
|
||||
onChange="updateIconPreview(this)"
|
||||
my-customparams="NEWDEV_devIcon,NEWDEV_devIcon_preview"
|
||||
id="${columns[j].setKey}"
|
||||
data-my-column="${columns[j].setKey}"
|
||||
data-my-targetColumns="${columns[j].setKey.replace('NEWDEV_','')}" >
|
||||
id="${multiEditColumns[j].setKey}"
|
||||
data-my-column="${multiEditColumns[j].setKey}"
|
||||
data-my-targetColumns="${multiEditColumns[j].setKey.replace('NEWDEV_','')}" >
|
||||
<option id="${targetLocation}"></option>
|
||||
</select>`
|
||||
|
||||
} else{
|
||||
|
||||
input = `<select class="form-control"
|
||||
id="${columns[j].setKey}"
|
||||
data-my-column="${columns[j].setKey}"
|
||||
data-my-targetColumns="${columns[j].setKey.replace('NEWDEV_','')}" >
|
||||
id="${multiEditColumns[j].setKey}"
|
||||
data-my-column="${multiEditColumns[j].setKey}"
|
||||
data-my-targetColumns="${multiEditColumns[j].setKey.replace('NEWDEV_','')}" >
|
||||
<option id="${targetLocation}"></option>
|
||||
</select>`
|
||||
}
|
||||
@@ -178,20 +179,20 @@
|
||||
|
||||
|
||||
input = `<input class="${inputClass}"
|
||||
id="${columns[j].setKey}"
|
||||
my-customid="${columns[j].setKey}"
|
||||
data-my-column="${columns[j].setKey}"
|
||||
data-my-targetColumns="${columns[j].setKey.replace('NEWDEV_','')}"
|
||||
id="${multiEditColumns[j].setKey}"
|
||||
my-customid="${multiEditColumns[j].setKey}"
|
||||
data-my-column="${multiEditColumns[j].setKey}"
|
||||
data-my-targetColumns="${multiEditColumns[j].setKey.replace('NEWDEV_','')}"
|
||||
type="${inputType}">`
|
||||
}
|
||||
|
||||
|
||||
const inputEntry = `<div class="form-group col-sm-12" >
|
||||
<label class="col-sm-3 control-label">${columns[j].setName}</label>
|
||||
<label class="col-sm-3 control-label">${multiEditColumns[j].setName}</label>
|
||||
<div class="col-sm-9">
|
||||
<div class="input-group red-hover-border">
|
||||
${input}
|
||||
<span class="input-group-addon pointer red-hover-background" onclick="massUpdateField('${columns[j].setKey}');" title="${getString('Device_MultiEdit_Tooltip')}">
|
||||
<span class="input-group-addon pointer red-hover-background" onclick="massUpdateField('${multiEditColumns[j].setKey}');" title="${getString('Device_MultiEdit_Tooltip')}">
|
||||
<i class="fa fa-save"></i>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
case 'deleteEvents30': deleteEvents30(); break;
|
||||
case 'deleteActHistory': deleteActHistory(); break;
|
||||
case 'deleteDeviceEvents': deleteDeviceEvents(); break;
|
||||
case 'resetDeviceProps': resetDeviceProps(); break;
|
||||
case 'PiaBackupDBtoArchive': PiaBackupDBtoArchive(); break;
|
||||
case 'PiaRestoreDBfromArchive': PiaRestoreDBfromArchive(); break;
|
||||
case 'PiaPurgeDBBackups': PiaPurgeDBBackups(); break;
|
||||
@@ -105,6 +106,7 @@ function getServerDeviceData() {
|
||||
"devSSID" => "",
|
||||
"devSyncHubNode" => "",
|
||||
"devSourcePlugin" => "",
|
||||
"devCustomProps" => "",
|
||||
"devStatus" => "Unknown",
|
||||
"devIsRandomMAC" => false,
|
||||
"devSessions" => 0,
|
||||
@@ -190,129 +192,131 @@ function setDeviceData() {
|
||||
global $db;
|
||||
|
||||
// Sanitize input
|
||||
$mac = quotes($_REQUEST['mac']);
|
||||
$name = quotes($_REQUEST['name']);
|
||||
$owner = quotes($_REQUEST['owner']);
|
||||
$type = quotes($_REQUEST['type']);
|
||||
$vendor = quotes($_REQUEST['vendor']);
|
||||
$icon = quotes($_REQUEST['icon']);
|
||||
$favorite = quotes($_REQUEST['favorite']);
|
||||
$group = quotes($_REQUEST['group']);
|
||||
$location = quotes($_REQUEST['location']);
|
||||
$comments = quotes($_REQUEST['comments']);
|
||||
$parentMac = quotes($_REQUEST['networknode']);
|
||||
$parentPort = quotes($_REQUEST['networknodeport']);
|
||||
$ssid = quotes($_REQUEST['ssid']);
|
||||
$site = quotes($_REQUEST['networksite']);
|
||||
$staticIP = quotes($_REQUEST['staticIP']);
|
||||
$scancycle = quotes($_REQUEST['scancycle']);
|
||||
$alertevents = quotes($_REQUEST['alertevents']);
|
||||
$alertdown = quotes($_REQUEST['alertdown']);
|
||||
$skiprepeated = quotes($_REQUEST['skiprepeated']);
|
||||
$newdevice = quotes($_REQUEST['newdevice']);
|
||||
$archived = quotes($_REQUEST['archived']);
|
||||
$devFirstConnection = quotes($_REQUEST['devFirstConnection']);
|
||||
$devLastConnection = quotes($_REQUEST['devLastConnection']);
|
||||
$ip = quotes($_REQUEST['ip']);
|
||||
$createNew = quotes($_REQUEST['createNew']);
|
||||
$mac = quotes($_POST['mac']);
|
||||
$name = urldecode(quotes($_POST['name']));
|
||||
$owner = urldecode(quotes($_POST['owner']));
|
||||
$type = urldecode(quotes($_POST['type']));
|
||||
$vendor = urldecode(quotes($_POST['vendor']));
|
||||
$icon = urldecode(quotes($_POST['icon']));
|
||||
$favorite = quotes($_POST['favorite']);
|
||||
$group = urldecode(quotes($_POST['group']));
|
||||
$location = urldecode(quotes($_POST['location']));
|
||||
$comments = urldecode(quotes($_POST['comments']));
|
||||
$parentMac = quotes($_POST['networknode']);
|
||||
$parentPort = quotes($_POST['networknodeport']);
|
||||
$ssid = urldecode(quotes($_POST['ssid']));
|
||||
$site = quotes($_POST['networksite']);
|
||||
$staticIP = quotes($_POST['staticIP']);
|
||||
$scancycle = quotes($_POST['scancycle']);
|
||||
$alertevents = quotes($_POST['alertevents']);
|
||||
$alertdown = quotes($_POST['alertdown']);
|
||||
$skiprepeated = quotes($_POST['skiprepeated']);
|
||||
$newdevice = quotes($_POST['newdevice']);
|
||||
$archived = quotes($_POST['archived']);
|
||||
$devFirstConnection = quotes($_POST['devFirstConnection']);
|
||||
$devLastConnection = quotes($_POST['devLastConnection']);
|
||||
$ip = quotes($_POST['ip']);
|
||||
$devCustomProps = quotes($_POST['devCustomProps']);
|
||||
$createNew = quotes($_POST['createNew']);
|
||||
$devNewGuid = generateGUID();
|
||||
|
||||
// an update
|
||||
if ($_REQUEST['createNew'] == 0)
|
||||
{
|
||||
// UPDATE SQL query
|
||||
$sql = "UPDATE Devices SET
|
||||
devName = '$name',
|
||||
devOwner = '$owner',
|
||||
devType = '$type',
|
||||
devVendor = '$vendor',
|
||||
devIcon = '$icon',
|
||||
devFavorite = '$favorite',
|
||||
devGroup = '$group',
|
||||
devLocation = '$location',
|
||||
devComments = '$comments',
|
||||
devParentMAC = '$parentMac',
|
||||
devParentPort = '$parentPort',
|
||||
devSSID = '$ssid',
|
||||
devSite = '$site',
|
||||
devStaticIP = '$staticIP',
|
||||
devScan = '$scancycle',
|
||||
devAlertEvents = '$alertevents',
|
||||
devAlertDown = '$alertdown',
|
||||
devSkipRepeated = '$skiprepeated',
|
||||
devIsNew = '$newdevice',
|
||||
devIsArchived = '$archived'
|
||||
WHERE devMac = '$mac'";
|
||||
} else // an INSERT
|
||||
{
|
||||
$sql = "INSERT INTO Devices (
|
||||
devMac,
|
||||
devName,
|
||||
devOwner,
|
||||
devType,
|
||||
devVendor,
|
||||
devIcon,
|
||||
devFavorite,
|
||||
devGroup,
|
||||
devLocation,
|
||||
devComments,
|
||||
devParentMAC,
|
||||
devParentPort,
|
||||
devSSID,
|
||||
devSite,
|
||||
devStaticIP,
|
||||
devScan,
|
||||
devAlertEvents,
|
||||
devAlertDown,
|
||||
devSkipRepeated,
|
||||
devIsNew,
|
||||
devIsArchived,
|
||||
devLastConnection,
|
||||
devFirstConnection,
|
||||
devLastIP,
|
||||
devGUID
|
||||
) VALUES (
|
||||
'$mac',
|
||||
'$name',
|
||||
'$owner',
|
||||
'$type',
|
||||
'$vendor',
|
||||
'$icon',
|
||||
'$favorite',
|
||||
'$group',
|
||||
'$location',
|
||||
'$comments',
|
||||
'$parentMac',
|
||||
'$parentPort',
|
||||
'$ssid',
|
||||
'$site',
|
||||
'$staticIP',
|
||||
'$scancycle',
|
||||
'$alertevents',
|
||||
'$alertdown',
|
||||
'$skiprepeated',
|
||||
'$newdevice',
|
||||
'$archived',
|
||||
'$devLastConnection',
|
||||
'$devFirstConnection',
|
||||
'$ip',
|
||||
'$devNewGuid'
|
||||
)
|
||||
";
|
||||
// An update
|
||||
if ($_POST['createNew'] == 0) {
|
||||
// UPDATE SQL query
|
||||
$sql = "UPDATE Devices SET
|
||||
devName = '$name',
|
||||
devOwner = '$owner',
|
||||
devType = '$type',
|
||||
devVendor = '$vendor',
|
||||
devIcon = '$icon',
|
||||
devFavorite = '$favorite',
|
||||
devGroup = '$group',
|
||||
devLocation = '$location',
|
||||
devComments = '$comments',
|
||||
devParentMAC = '$parentMac',
|
||||
devParentPort = '$parentPort',
|
||||
devSSID = '$ssid',
|
||||
devSite = '$site',
|
||||
devStaticIP = '$staticIP',
|
||||
devScan = '$scancycle',
|
||||
devAlertEvents = '$alertevents',
|
||||
devAlertDown = '$alertdown',
|
||||
devSkipRepeated = '$skiprepeated',
|
||||
devIsNew = '$newdevice',
|
||||
devIsArchived = '$archived',
|
||||
devCustomProps = '$devCustomProps'
|
||||
WHERE devMac = '$mac'";
|
||||
} else { // An INSERT
|
||||
$sql = "INSERT INTO Devices (
|
||||
devMac,
|
||||
devName,
|
||||
devOwner,
|
||||
devType,
|
||||
devVendor,
|
||||
devIcon,
|
||||
devFavorite,
|
||||
devGroup,
|
||||
devLocation,
|
||||
devComments,
|
||||
devParentMAC,
|
||||
devParentPort,
|
||||
devSSID,
|
||||
devSite,
|
||||
devStaticIP,
|
||||
devScan,
|
||||
devAlertEvents,
|
||||
devAlertDown,
|
||||
devSkipRepeated,
|
||||
devIsNew,
|
||||
devIsArchived,
|
||||
devLastConnection,
|
||||
devFirstConnection,
|
||||
devLastIP,
|
||||
devGUID,
|
||||
devCustomProps
|
||||
) VALUES (
|
||||
'$mac',
|
||||
'$name',
|
||||
'$owner',
|
||||
'$type',
|
||||
'$vendor',
|
||||
'$icon',
|
||||
'$favorite',
|
||||
'$group',
|
||||
'$location',
|
||||
'$comments',
|
||||
'$parentMac',
|
||||
'$parentPort',
|
||||
'$ssid',
|
||||
'$site',
|
||||
'$staticIP',
|
||||
'$scancycle',
|
||||
'$alertevents',
|
||||
'$alertdown',
|
||||
'$skiprepeated',
|
||||
'$newdevice',
|
||||
'$archived',
|
||||
'$devLastConnection',
|
||||
'$devFirstConnection',
|
||||
'$ip',
|
||||
'$devNewGuid',
|
||||
'$devCustomProps'
|
||||
)";
|
||||
}
|
||||
|
||||
// update Data
|
||||
// Execute the query
|
||||
$result = $db->query($sql);
|
||||
|
||||
// check result
|
||||
// Check the result
|
||||
if ($result == TRUE) {
|
||||
echo lang('BackDevices_DBTools_UpdDev');
|
||||
echo lang('BackDevices_DBTools_UpdDev');
|
||||
} else {
|
||||
echo lang('BackDevices_DBTools_UpdDevError')."\n\n$sql \n\n". $db->lastErrorMsg();
|
||||
echo lang('BackDevices_DBTools_UpdDevError')."\n\n$sql \n\n". $db->lastErrorMsg();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Delete Device
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -389,6 +393,26 @@ function deleteDeviceEvents() {
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Delete Device Properties
|
||||
//------------------------------------------------------------------------------
|
||||
function resetDeviceProps() {
|
||||
global $db;
|
||||
|
||||
// sql
|
||||
$sql = 'UPDATE Devices set devCustomProps = "'.getSettingValue("NEWDEV_devCustomProps").'" WHERE devMac="' . $_REQUEST['mac'] .'"';
|
||||
|
||||
// execute sql
|
||||
$result = $db->query($sql);
|
||||
|
||||
// check result
|
||||
if ($result == TRUE) {
|
||||
echo lang('Gen_Okay');
|
||||
} else {
|
||||
echo lang('Gen_Error')."\n\n$sql \n\n". $db->lastErrorMsg();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Delete all devices
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -356,6 +356,8 @@ function saveSettings()
|
||||
$txt .= $setKey . "='" . $val . "'\n";
|
||||
} elseif ($dataType == 'integer') {
|
||||
$txt .= $setKey . "=" . $settingValue . "\n";
|
||||
} elseif ($dataType == 'none') {
|
||||
$txt .= $setKey . "=''\n";
|
||||
} elseif ($dataType == 'json') {
|
||||
$txt .= $setKey . "=" . $settingValue . "\n";
|
||||
} elseif ($dataType == 'boolean') {
|
||||
@@ -551,6 +553,7 @@ function decodeSpecialChars($str) {
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------------------------
|
||||
// used in Export CSV
|
||||
function getDevicesColumns(){
|
||||
|
||||
$columns = ["devMac",
|
||||
@@ -582,7 +585,8 @@ function getDevicesColumns(){
|
||||
"devSyncHubNode",
|
||||
"devSite",
|
||||
"devSSID",
|
||||
"devSourcePlugin"
|
||||
"devSourcePlugin",
|
||||
"devCustomProps"
|
||||
];
|
||||
|
||||
return $columns;
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
<script src="js/tests.js?v=<?php include 'php/templates/version.php'; ?>"></script>
|
||||
<script src="js/db_methods.js?v=<?php include 'php/templates/version.php'; ?>"></script>
|
||||
<script src="js/settings_utils.js?v=<?php include 'php/templates/version.php'; ?>"></script>
|
||||
<script src="js/device.js?v=<?php include 'php/templates/version.php'; ?>"></script>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -60,12 +60,15 @@
|
||||
"BackDevices_darkmode_enabled": "",
|
||||
"CLEAR_NEW_FLAG_description": "",
|
||||
"CLEAR_NEW_FLAG_name": "",
|
||||
"CustProps_cant_remove": "",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "",
|
||||
"DISCOVER_PLUGINS_description": "",
|
||||
"DISCOVER_PLUGINS_name": "",
|
||||
"DevDetail_Copy_Device_Title": "",
|
||||
"DevDetail_Copy_Device_Tooltip": "",
|
||||
"DevDetail_CustomProperties_Title": "",
|
||||
"DevDetail_CustomProps_reset_info": "",
|
||||
"DevDetail_DisplayFields_Title": "",
|
||||
"DevDetail_EveandAl_AlertAllEvents": "",
|
||||
"DevDetail_EveandAl_AlertDown": "",
|
||||
@@ -205,6 +208,7 @@
|
||||
"Device_Shortcut_OnlineChart": "",
|
||||
"Device_TableHead_AlertDown": "",
|
||||
"Device_TableHead_Connected_Devices": "",
|
||||
"Device_TableHead_CustomProps": "",
|
||||
"Device_TableHead_Favorite": "",
|
||||
"Device_TableHead_FirstSession": "",
|
||||
"Device_TableHead_GUID": "",
|
||||
@@ -305,6 +309,7 @@
|
||||
"Gen_ReadDocs": "",
|
||||
"Gen_Remove_All": "",
|
||||
"Gen_Remove_Last": "",
|
||||
"Gen_Reset": "",
|
||||
"Gen_Restore": "",
|
||||
"Gen_Run": "",
|
||||
"Gen_Save": "",
|
||||
|
||||
@@ -60,12 +60,15 @@
|
||||
"BackDevices_darkmode_enabled": "Mode fosc Activat",
|
||||
"CLEAR_NEW_FLAG_description": "Si està habilitat (<code>0</code> està desactivat), els dispositius marcats com <b>Nou dispositiu</b> es desmarcaran si el temps límit (especificat en hores) supera <b>Primera sessió</b>.",
|
||||
"CLEAR_NEW_FLAG_name": "Netejar indicador de nou",
|
||||
"CustProps_cant_remove": "",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "Això és una configuració de manteniment. Especifica el nombre de dies que es conservaran els esdeveniments. Els esdeveniments antics s'esborraran periòdicament. També aplica als esdeveniments dels Connectors (Plugins).",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "Esborrar esdeveniments més vells de",
|
||||
"DISCOVER_PLUGINS_description": "Desactiva aquesta opció per accelerar la inicialització i l'estalvi de configuració. Quan està desactivat, els connectors no es descobreixen, i no podeu afegir nous connectors a la configuració <code>LOADED_PLUGINS</code>.",
|
||||
"DISCOVER_PLUGINS_name": "Descobreix els plugins",
|
||||
"DevDetail_Copy_Device_Title": "<i class=\"fa fa-copy\"></i> Copiar detalls des del dispositiu",
|
||||
"DevDetail_Copy_Device_Tooltip": "Copiar detalls del dispositius des de la llista desplegable. Tot el d'aquesta pàgina es sobre-escriurà",
|
||||
"DevDetail_CustomProperties_Title": "",
|
||||
"DevDetail_CustomProps_reset_info": "",
|
||||
"DevDetail_DisplayFields_Title": "Pantalla",
|
||||
"DevDetail_EveandAl_AlertAllEvents": "Alertes",
|
||||
"DevDetail_EveandAl_AlertDown": "Cancel·lar alerta",
|
||||
@@ -205,6 +208,7 @@
|
||||
"Device_Shortcut_OnlineChart": "Presència de dispositius",
|
||||
"Device_TableHead_AlertDown": "Cancel·lar alerta",
|
||||
"Device_TableHead_Connected_Devices": "Connexions",
|
||||
"Device_TableHead_CustomProps": "",
|
||||
"Device_TableHead_Favorite": "Favorit",
|
||||
"Device_TableHead_FirstSession": "Primera Sessió",
|
||||
"Device_TableHead_GUID": "GUID",
|
||||
@@ -305,6 +309,7 @@
|
||||
"Gen_ReadDocs": "Llegit més dins el docs.",
|
||||
"Gen_Remove_All": "Esborra tot",
|
||||
"Gen_Remove_Last": "Esborra el darrer",
|
||||
"Gen_Reset": "",
|
||||
"Gen_Restore": "Executar Restaurar",
|
||||
"Gen_Run": "Executar",
|
||||
"Gen_Save": "Guardar",
|
||||
|
||||
@@ -60,12 +60,15 @@
|
||||
"BackDevices_darkmode_enabled": "",
|
||||
"CLEAR_NEW_FLAG_description": "",
|
||||
"CLEAR_NEW_FLAG_name": "",
|
||||
"CustProps_cant_remove": "",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "",
|
||||
"DISCOVER_PLUGINS_description": "",
|
||||
"DISCOVER_PLUGINS_name": "",
|
||||
"DevDetail_Copy_Device_Title": "",
|
||||
"DevDetail_Copy_Device_Tooltip": "",
|
||||
"DevDetail_CustomProperties_Title": "",
|
||||
"DevDetail_CustomProps_reset_info": "",
|
||||
"DevDetail_DisplayFields_Title": "",
|
||||
"DevDetail_EveandAl_AlertAllEvents": "",
|
||||
"DevDetail_EveandAl_AlertDown": "",
|
||||
@@ -205,6 +208,7 @@
|
||||
"Device_Shortcut_OnlineChart": "",
|
||||
"Device_TableHead_AlertDown": "",
|
||||
"Device_TableHead_Connected_Devices": "",
|
||||
"Device_TableHead_CustomProps": "",
|
||||
"Device_TableHead_Favorite": "",
|
||||
"Device_TableHead_FirstSession": "",
|
||||
"Device_TableHead_GUID": "",
|
||||
@@ -305,6 +309,7 @@
|
||||
"Gen_ReadDocs": "",
|
||||
"Gen_Remove_All": "",
|
||||
"Gen_Remove_Last": "",
|
||||
"Gen_Reset": "",
|
||||
"Gen_Restore": "",
|
||||
"Gen_Run": "",
|
||||
"Gen_Save": "",
|
||||
|
||||
@@ -72,12 +72,15 @@
|
||||
"BackDevices_darkmode_enabled": "Dunkler Modus aktiviert",
|
||||
"CLEAR_NEW_FLAG_description": "Wenn aktiviert (<code>0</code> bedeutet deaktiviert), werden Geräte, die als <b>Neues Gerät</b> gekennzeichnet sind, wieder freigegeben, wenn das Zeitlimit (in Stunden) die Zeit ihrer <b>Ersten Sitzung</b> überschreitet.",
|
||||
"CLEAR_NEW_FLAG_name": "Neues Flag löschen",
|
||||
"CustProps_cant_remove": "",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "Dies ist eine Wartungseinstellung. Spezifiziert wie viele Tage Events gespeichert bleiben. Alle älteren Events werden periodisch gelöscht. Wird auch auf die Plugins History angewendet.",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "Ereignisse löschen, die älter sind als",
|
||||
"DISCOVER_PLUGINS_description": "",
|
||||
"DISCOVER_PLUGINS_name": "",
|
||||
"DevDetail_Copy_Device_Title": "Details von Gerät kopieren",
|
||||
"DevDetail_Copy_Device_Tooltip": "Details vom Gerät aus der Dropdown-Liste kopieren. Alles auf dieser Seite wird überschrieben",
|
||||
"DevDetail_CustomProperties_Title": "",
|
||||
"DevDetail_CustomProps_reset_info": "",
|
||||
"DevDetail_DisplayFields_Title": "Anzeige",
|
||||
"DevDetail_EveandAl_AlertAllEvents": "Alarmereignisse",
|
||||
"DevDetail_EveandAl_AlertDown": "Melde Down",
|
||||
@@ -217,6 +220,7 @@
|
||||
"Device_Shortcut_OnlineChart": "Gerätepräsenz im Laufe der Zeit",
|
||||
"Device_TableHead_AlertDown": "",
|
||||
"Device_TableHead_Connected_Devices": "Verbindungen",
|
||||
"Device_TableHead_CustomProps": "",
|
||||
"Device_TableHead_Favorite": "Favorit",
|
||||
"Device_TableHead_FirstSession": "Erste Sitzung",
|
||||
"Device_TableHead_GUID": "GUID",
|
||||
@@ -317,6 +321,7 @@
|
||||
"Gen_ReadDocs": "Mehr in der Dokumentation.",
|
||||
"Gen_Remove_All": "Alle entfernen",
|
||||
"Gen_Remove_Last": "Letzte entfernen",
|
||||
"Gen_Reset": "",
|
||||
"Gen_Restore": "Wiederherstellen",
|
||||
"Gen_Run": "Ausführen",
|
||||
"Gen_Save": "Speichern",
|
||||
|
||||
@@ -60,12 +60,15 @@
|
||||
"BackDevices_darkmode_enabled": "Darkmode Enabled",
|
||||
"CLEAR_NEW_FLAG_description": "If enabled (<code>0</code> is disabled), devices flagged as <b>New Device</b> will be unflagged if the time limit (specified in hours) exceeds their <b>First Session</b> time.",
|
||||
"CLEAR_NEW_FLAG_name": "Clear new flag",
|
||||
"CustProps_cant_remove": "Can't remove, at least one property is needed.",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "This is a maintenance setting. This specifies the number of days worth of event entries that will be kept. All older events will be deleted periodically. Also applies on Plugin Events History.",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "Delete events older than",
|
||||
"DISCOVER_PLUGINS_description": "Disable this option to speed up initialization and settings saving. When disabled, plugins are not discovered, and you cannot add new plugins to the <code>LOADED_PLUGINS</code> setting.",
|
||||
"DISCOVER_PLUGINS_name": "Discover plugins",
|
||||
"DevDetail_Copy_Device_Title": "Copy details from device",
|
||||
"DevDetail_Copy_Device_Tooltip": "Copy details from device from the dropdown list. Everything on this page will be overwritten",
|
||||
"DevDetail_CustomProperties_Title": "Custom Properties",
|
||||
"DevDetail_CustomProps_reset_info": "This will remove your custom properties on this device and reset them to the default value.",
|
||||
"DevDetail_DisplayFields_Title": "Display",
|
||||
"DevDetail_EveandAl_AlertAllEvents": "Alert Events",
|
||||
"DevDetail_EveandAl_AlertDown": "Alert Down",
|
||||
@@ -205,6 +208,7 @@
|
||||
"Device_Shortcut_OnlineChart": "Device presence",
|
||||
"Device_TableHead_AlertDown": "Alert Down",
|
||||
"Device_TableHead_Connected_Devices": "Connections",
|
||||
"Device_TableHead_CustomProps": "Props / Actions",
|
||||
"Device_TableHead_Favorite": "Favorite",
|
||||
"Device_TableHead_FirstSession": "First Session",
|
||||
"Device_TableHead_GUID": "GUID",
|
||||
@@ -305,6 +309,7 @@
|
||||
"Gen_ReadDocs": "Read more in the docs.",
|
||||
"Gen_Remove_All": "Remove all",
|
||||
"Gen_Remove_Last": "Remove last",
|
||||
"Gen_Reset": "Reset",
|
||||
"Gen_Restore": "Run Restore",
|
||||
"Gen_Run": "Run",
|
||||
"Gen_Save": "Save",
|
||||
|
||||
@@ -70,12 +70,15 @@
|
||||
"BackDevices_darkmode_enabled": "Darkmode Activado",
|
||||
"CLEAR_NEW_FLAG_description": "Si está habilitado (<code>0</code> está desactivado), los dispositivos marcados como <b>Nuevo dispositivo</b> se desmarcarán si el límite de tiempo (especificado en horas) excede su tiempo de <b>primera sesión</b>.",
|
||||
"CLEAR_NEW_FLAG_name": "Eliminar la nueva bandera",
|
||||
"CustProps_cant_remove": "",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "Esta es una configuración de mantenimiento. Esto especifica el número de días de entradas de eventos que se guardarán. Todos los eventos anteriores se eliminarán periódicamente.",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "Eliminar eventos anteriores a",
|
||||
"DISCOVER_PLUGINS_description": "",
|
||||
"DISCOVER_PLUGINS_name": "",
|
||||
"DevDetail_Copy_Device_Title": "Copiar detalles del dispositivo",
|
||||
"DevDetail_Copy_Device_Tooltip": "Copiar detalles del dispositivo de la lista desplegable. Todo en esta página se sobrescribirá",
|
||||
"DevDetail_CustomProperties_Title": "",
|
||||
"DevDetail_CustomProps_reset_info": "",
|
||||
"DevDetail_DisplayFields_Title": "Mostrar",
|
||||
"DevDetail_EveandAl_AlertAllEvents": "Notificaciones de eventos",
|
||||
"DevDetail_EveandAl_AlertDown": "Alerta de caída",
|
||||
@@ -215,6 +218,7 @@
|
||||
"Device_Shortcut_OnlineChart": "Presencia del dispositivo a lo largo del tiempo",
|
||||
"Device_TableHead_AlertDown": "Alerta desactivada",
|
||||
"Device_TableHead_Connected_Devices": "Conexiones",
|
||||
"Device_TableHead_CustomProps": "",
|
||||
"Device_TableHead_Favorite": "Favorito",
|
||||
"Device_TableHead_FirstSession": "1ra. sesión",
|
||||
"Device_TableHead_GUID": "GUID",
|
||||
@@ -315,6 +319,7 @@
|
||||
"Gen_ReadDocs": "Lee más en los documentos.",
|
||||
"Gen_Remove_All": "Quitar todo",
|
||||
"Gen_Remove_Last": "Quitar el último",
|
||||
"Gen_Reset": "",
|
||||
"Gen_Restore": "Ejecutar restauración",
|
||||
"Gen_Run": "Ejecutar",
|
||||
"Gen_Save": "Guardar",
|
||||
|
||||
@@ -60,12 +60,15 @@
|
||||
"BackDevices_darkmode_enabled": "Mode sombre activé",
|
||||
"CLEAR_NEW_FLAG_description": "Si activé (<code>0</code> est désactivé), les appareils marqués comme <b>Nouvel appareil</b> seront démarqués si la limite de temps (spécifiée en heures) dépasse la durée de <b>Première Session</b>.",
|
||||
"CLEAR_NEW_FLAG_name": "Supprime le nouveau drapeau",
|
||||
"CustProps_cant_remove": "",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "Il s'agit d'un paramètre de maintenance. Il indique le nombre de jours pendant lesquels les entrées d'événements seront conservées. Tous les événements plus anciens seront supprimés périodiquement. S'applique également à l'historique des événements du plugin.",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "Supprimer les événements plus anciens que",
|
||||
"DISCOVER_PLUGINS_description": "",
|
||||
"DISCOVER_PLUGINS_name": "",
|
||||
"DevDetail_Copy_Device_Title": "Copier les détails de l'appareil",
|
||||
"DevDetail_Copy_Device_Tooltip": "Copier les détails de l'appareil dans la liste déroulante. Tout ce qui se trouve sur cette page sera remplacé",
|
||||
"DevDetail_CustomProperties_Title": "",
|
||||
"DevDetail_CustomProps_reset_info": "",
|
||||
"DevDetail_DisplayFields_Title": "Afficher",
|
||||
"DevDetail_EveandAl_AlertAllEvents": "Alerter les événements",
|
||||
"DevDetail_EveandAl_AlertDown": "Alerte de panne",
|
||||
@@ -205,6 +208,7 @@
|
||||
"Device_Shortcut_OnlineChart": "Présence de l'appareil",
|
||||
"Device_TableHead_AlertDown": "Alerter si En panne",
|
||||
"Device_TableHead_Connected_Devices": "Connexions",
|
||||
"Device_TableHead_CustomProps": "",
|
||||
"Device_TableHead_Favorite": "Favori",
|
||||
"Device_TableHead_FirstSession": "Première session",
|
||||
"Device_TableHead_GUID": "GUID",
|
||||
@@ -305,6 +309,7 @@
|
||||
"Gen_ReadDocs": "Plus d'infos dans la documentation.",
|
||||
"Gen_Remove_All": "Enlever tous",
|
||||
"Gen_Remove_Last": "Enlever le dernier",
|
||||
"Gen_Reset": "",
|
||||
"Gen_Restore": "Lancer une restauration",
|
||||
"Gen_Run": "Lancer",
|
||||
"Gen_Save": "Enregistrer",
|
||||
|
||||
@@ -60,12 +60,15 @@
|
||||
"BackDevices_darkmode_enabled": "Modalità scura abilitata",
|
||||
"CLEAR_NEW_FLAG_description": "Se abilitato (<code>0</code> è disabilitato), i dispositivi contrassegnati come <b>Nuovo dispositivo</b> verranno deselezionati se il limite di tempo (specificato in ore) supera il tempo della <b>Prima sessione</b>.",
|
||||
"CLEAR_NEW_FLAG_name": "Cancella nuova bandiera",
|
||||
"CustProps_cant_remove": "",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "Questa è un'impostazione di manutenzione. Specifica il numero di giorni delle voci degli eventi che verranno conservati. Tutti gli eventi più vecchi verranno eliminati periodicamente. Si applica anche alla cronologia degli eventi del plugin (Plugin Events History).",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "Elimina eventi più vecchi di",
|
||||
"DISCOVER_PLUGINS_description": "Disattiva questa opzione per velocizzare l'inizializzazione e il salvataggio delle impostazioni. Quando è disattivata, i plugin non vengono scoperti e non puoi aggiungere nuovi plugin all'impostazione <code>LOADED_PLUGINS</code>.",
|
||||
"DISCOVER_PLUGINS_name": "Scopri i plugin",
|
||||
"DevDetail_Copy_Device_Title": "Copia dettagli dal dispositivo",
|
||||
"DevDetail_Copy_Device_Tooltip": "Copia i dettagli dal dispositivo dall'elenco a discesa. Tutto in questa pagina verrà sovrascritto",
|
||||
"DevDetail_CustomProperties_Title": "",
|
||||
"DevDetail_CustomProps_reset_info": "",
|
||||
"DevDetail_DisplayFields_Title": "Visualizza",
|
||||
"DevDetail_EveandAl_AlertAllEvents": "Notifica eventi",
|
||||
"DevDetail_EveandAl_AlertDown": "Avviso disconnessione",
|
||||
@@ -205,6 +208,7 @@
|
||||
"Device_Shortcut_OnlineChart": "Presenza dispositivo",
|
||||
"Device_TableHead_AlertDown": "Avviso disconnessione",
|
||||
"Device_TableHead_Connected_Devices": "Connessioni",
|
||||
"Device_TableHead_CustomProps": "",
|
||||
"Device_TableHead_Favorite": "Preferito",
|
||||
"Device_TableHead_FirstSession": "Prima sessione",
|
||||
"Device_TableHead_GUID": "GUID",
|
||||
@@ -305,6 +309,7 @@
|
||||
"Gen_ReadDocs": "Maggiori informazioni nella documentazione.",
|
||||
"Gen_Remove_All": "Rimuovi tutti",
|
||||
"Gen_Remove_Last": "Rimuovi ultimo",
|
||||
"Gen_Reset": "",
|
||||
"Gen_Restore": "Esegui ripristino",
|
||||
"Gen_Run": "Esegui",
|
||||
"Gen_Save": "Salva",
|
||||
|
||||
@@ -60,12 +60,15 @@
|
||||
"BackDevices_darkmode_enabled": "Mørk modus Aktivert",
|
||||
"CLEAR_NEW_FLAG_description": "",
|
||||
"CLEAR_NEW_FLAG_name": "",
|
||||
"CustProps_cant_remove": "",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "Dette er en vedlikeholdsinnstilling. Dette spesifiserer antall dager verdt med hendelsesoppføringer som vil beholdes. Alle eldre hendelser vil bli slettet med jevne mellomrom. Gjelder også for plugin-hendelseshistorikk.",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "Slett hendelser eldre enn",
|
||||
"DISCOVER_PLUGINS_description": "",
|
||||
"DISCOVER_PLUGINS_name": "",
|
||||
"DevDetail_Copy_Device_Title": "<i class=\"fa fa-copy\"></i> Kopier detaljer fra enhet",
|
||||
"DevDetail_Copy_Device_Tooltip": "Kopier detaljer fra enheten via nedtrekks menyen. Alt på denne siden vil bli overskrevet",
|
||||
"DevDetail_CustomProperties_Title": "",
|
||||
"DevDetail_CustomProps_reset_info": "",
|
||||
"DevDetail_DisplayFields_Title": "",
|
||||
"DevDetail_EveandAl_AlertAllEvents": "Varsel Alle Hendelser",
|
||||
"DevDetail_EveandAl_AlertDown": "Varsel Nede",
|
||||
@@ -205,6 +208,7 @@
|
||||
"Device_Shortcut_OnlineChart": "Enhetens tilstedeværelse",
|
||||
"Device_TableHead_AlertDown": "",
|
||||
"Device_TableHead_Connected_Devices": "Tilkoblinger",
|
||||
"Device_TableHead_CustomProps": "",
|
||||
"Device_TableHead_Favorite": "Favoritt",
|
||||
"Device_TableHead_FirstSession": "Første Økt",
|
||||
"Device_TableHead_GUID": "GUID",
|
||||
@@ -305,6 +309,7 @@
|
||||
"Gen_ReadDocs": "Les mer i dokumentasjonen.",
|
||||
"Gen_Remove_All": "Fjern alle",
|
||||
"Gen_Remove_Last": "Fjern sist",
|
||||
"Gen_Reset": "",
|
||||
"Gen_Restore": "Kjør Gjenopprett",
|
||||
"Gen_Run": "Kjør",
|
||||
"Gen_Save": "Lagre",
|
||||
|
||||
@@ -60,12 +60,15 @@
|
||||
"BackDevices_darkmode_enabled": "Tryb ciemny Włączony",
|
||||
"CLEAR_NEW_FLAG_description": "",
|
||||
"CLEAR_NEW_FLAG_name": "",
|
||||
"CustProps_cant_remove": "",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "To jest ustawienie konserwacji. Określa ile dni mają być utrzymywane wpisy wydarzeń. Wszystkie starsze wpisy wydarzeń zostaną usunięte okresowo. Dotyczy także Historii Wydarzeń Pluginów.",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "Usuń wydarzenia starsze niż",
|
||||
"DISCOVER_PLUGINS_description": "",
|
||||
"DISCOVER_PLUGINS_name": "",
|
||||
"DevDetail_Copy_Device_Title": "<i class=\"fa fa-copy\"></i>Kopiuj opis z urządzenia",
|
||||
"DevDetail_Copy_Device_Tooltip": "Kopiuj opis z urządzenia z listy rozwijanej. Wszystko na tej stronie zostanie nadpisane",
|
||||
"DevDetail_CustomProperties_Title": "",
|
||||
"DevDetail_CustomProps_reset_info": "",
|
||||
"DevDetail_DisplayFields_Title": "",
|
||||
"DevDetail_EveandAl_AlertAllEvents": "Powiadamiaj o wszystkich wydarzeniach",
|
||||
"DevDetail_EveandAl_AlertDown": "Wyłącz powiadomienia",
|
||||
@@ -205,6 +208,7 @@
|
||||
"Device_Shortcut_OnlineChart": "Obecność urządzenia",
|
||||
"Device_TableHead_AlertDown": "",
|
||||
"Device_TableHead_Connected_Devices": "Połączenia",
|
||||
"Device_TableHead_CustomProps": "",
|
||||
"Device_TableHead_Favorite": "Ulubione",
|
||||
"Device_TableHead_FirstSession": "Pierwsza Sesja",
|
||||
"Device_TableHead_GUID": "GUID",
|
||||
@@ -305,6 +309,7 @@
|
||||
"Gen_ReadDocs": "Przeczytaj więcej w dokumentacji.",
|
||||
"Gen_Remove_All": "Usuń wszystko",
|
||||
"Gen_Remove_Last": "Usuń ostatnie",
|
||||
"Gen_Reset": "",
|
||||
"Gen_Restore": "Wykonaj Przywracanie",
|
||||
"Gen_Run": "Wykonaj",
|
||||
"Gen_Save": "Zapisz",
|
||||
|
||||
@@ -60,12 +60,15 @@
|
||||
"BackDevices_darkmode_enabled": "Modo Noturno Habilitado",
|
||||
"CLEAR_NEW_FLAG_description": "Se habilitado (<code>0</code> está desativado), dispositivos marcados como<b>Novo Dispositivo</b> serão desmarcados se o limite (especificado em horas) exceder o tempo da <b>Primeira Sessão </b>.",
|
||||
"CLEAR_NEW_FLAG_name": "",
|
||||
"CustProps_cant_remove": "",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "Esta é uma definição de manutenção. Especifica o número de dias de entradas de eventos que serão mantidas. Todos os eventos mais antigos serão eliminados periodicamente. Também se aplica ao Histórico de eventos do plug-in.",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "Excluir eventos mais antigos que",
|
||||
"DISCOVER_PLUGINS_description": "",
|
||||
"DISCOVER_PLUGINS_name": "",
|
||||
"DevDetail_Copy_Device_Title": "<i class=\"fa fa-copy\"></i> Copiar detalhes do dispositivo",
|
||||
"DevDetail_Copy_Device_Tooltip": "Copiar detalhes do dispositivo a partir da lista pendente. Tudo o que se encontra nesta página será substituído",
|
||||
"DevDetail_CustomProperties_Title": "",
|
||||
"DevDetail_CustomProps_reset_info": "",
|
||||
"DevDetail_DisplayFields_Title": "",
|
||||
"DevDetail_EveandAl_AlertAllEvents": "Alerte Todos os Eventos",
|
||||
"DevDetail_EveandAl_AlertDown": "Alerta Desligado",
|
||||
@@ -205,6 +208,7 @@
|
||||
"Device_Shortcut_OnlineChart": "Presença do dispositivo",
|
||||
"Device_TableHead_AlertDown": "",
|
||||
"Device_TableHead_Connected_Devices": "Conexões",
|
||||
"Device_TableHead_CustomProps": "",
|
||||
"Device_TableHead_Favorite": "Favorito",
|
||||
"Device_TableHead_FirstSession": "Primeira sessão",
|
||||
"Device_TableHead_GUID": "GUID",
|
||||
@@ -305,6 +309,7 @@
|
||||
"Gen_ReadDocs": "Leia mais em documentos.",
|
||||
"Gen_Remove_All": "Remover tudo",
|
||||
"Gen_Remove_Last": "Remover o último",
|
||||
"Gen_Reset": "",
|
||||
"Gen_Restore": "Executar restauração",
|
||||
"Gen_Run": "Executar",
|
||||
"Gen_Save": "Salvar",
|
||||
|
||||
@@ -60,12 +60,15 @@
|
||||
"BackDevices_darkmode_enabled": "Темный режим включен",
|
||||
"CLEAR_NEW_FLAG_description": "Если этот параметр включен (<code>0</code> отключен), устройства, помеченные как <b>Новое устройство</b>, станут неотмеченными, если лимит времени, указанный в часах, превышает время их <b>первой сессии</b>.",
|
||||
"CLEAR_NEW_FLAG_name": "Удалить новый флаг",
|
||||
"CustProps_cant_remove": "",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "Это настройка обслуживания. Здесь указывается количество дней, в течение которых будут храниться записи о событиях. Все старые события будут периодически удаляться. Также применимо к истории событий плагина.",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "Удалить события старше",
|
||||
"DISCOVER_PLUGINS_description": "",
|
||||
"DISCOVER_PLUGINS_name": "",
|
||||
"DevDetail_Copy_Device_Title": "Скопировать данные с устройства",
|
||||
"DevDetail_Copy_Device_Tooltip": "Скопируйте данные с устройства из раскрывающегося списка. Все на этой странице будет перезаписано",
|
||||
"DevDetail_CustomProperties_Title": "",
|
||||
"DevDetail_CustomProps_reset_info": "",
|
||||
"DevDetail_DisplayFields_Title": "Дисплей",
|
||||
"DevDetail_EveandAl_AlertAllEvents": "Оповещения о событиях",
|
||||
"DevDetail_EveandAl_AlertDown": "Оповещение о доступности",
|
||||
@@ -205,6 +208,7 @@
|
||||
"Device_Shortcut_OnlineChart": "Присутствие устройств",
|
||||
"Device_TableHead_AlertDown": "Оповещение о сост. ВЫКЛ",
|
||||
"Device_TableHead_Connected_Devices": "Соединения",
|
||||
"Device_TableHead_CustomProps": "",
|
||||
"Device_TableHead_Favorite": "Избранное",
|
||||
"Device_TableHead_FirstSession": "Первый сеанс",
|
||||
"Device_TableHead_GUID": "GUID",
|
||||
@@ -305,6 +309,7 @@
|
||||
"Gen_ReadDocs": "Подробнее читайте в документации.",
|
||||
"Gen_Remove_All": "Удалить все",
|
||||
"Gen_Remove_Last": "Удалить последний",
|
||||
"Gen_Reset": "",
|
||||
"Gen_Restore": "Запустить восстановление",
|
||||
"Gen_Run": "Запустить",
|
||||
"Gen_Save": "Сохранить",
|
||||
|
||||
@@ -60,12 +60,15 @@
|
||||
"BackDevices_darkmode_enabled": "",
|
||||
"CLEAR_NEW_FLAG_description": "",
|
||||
"CLEAR_NEW_FLAG_name": "",
|
||||
"CustProps_cant_remove": "",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "",
|
||||
"DISCOVER_PLUGINS_description": "",
|
||||
"DISCOVER_PLUGINS_name": "",
|
||||
"DevDetail_Copy_Device_Title": "",
|
||||
"DevDetail_Copy_Device_Tooltip": "",
|
||||
"DevDetail_CustomProperties_Title": "",
|
||||
"DevDetail_CustomProps_reset_info": "",
|
||||
"DevDetail_DisplayFields_Title": "",
|
||||
"DevDetail_EveandAl_AlertAllEvents": "",
|
||||
"DevDetail_EveandAl_AlertDown": "",
|
||||
@@ -205,6 +208,7 @@
|
||||
"Device_Shortcut_OnlineChart": "",
|
||||
"Device_TableHead_AlertDown": "",
|
||||
"Device_TableHead_Connected_Devices": "Bağlantılar",
|
||||
"Device_TableHead_CustomProps": "",
|
||||
"Device_TableHead_Favorite": "",
|
||||
"Device_TableHead_FirstSession": "İlk Oturum",
|
||||
"Device_TableHead_GUID": "",
|
||||
@@ -305,6 +309,7 @@
|
||||
"Gen_ReadDocs": "",
|
||||
"Gen_Remove_All": "Tümünü kaldır",
|
||||
"Gen_Remove_Last": "",
|
||||
"Gen_Reset": "",
|
||||
"Gen_Restore": "",
|
||||
"Gen_Run": "Çalıştır",
|
||||
"Gen_Save": "Kaydet",
|
||||
|
||||
@@ -60,12 +60,15 @@
|
||||
"BackDevices_darkmode_enabled": "Темний режим увімкнено",
|
||||
"CLEAR_NEW_FLAG_description": "Якщо ввімкнено (<code>0</code> вимкнено), пристрої, позначені як <b>Новий пристрій</b>, не будуть позначені, якщо ліміт часу (вказаний у годинах) перевищує їхній <b>Перший сеанс</b> час.",
|
||||
"CLEAR_NEW_FLAG_name": "Очистити новий прапор",
|
||||
"CustProps_cant_remove": "",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "Це налаштування обслуговування. Це визначає кількість днів записів про події, які зберігатимуться. Усі старіші події періодично видалятимуться. Також застосовується до історії подій плагінів.",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "Видалити події, старші за",
|
||||
"DISCOVER_PLUGINS_description": "Вимкніть цю опцію, щоб прискорити ініціалізацію та збереження налаштувань. Якщо вимкнено, плагіни не виявляються, і ви не можете додавати нові плагіни до параметра <code>LOADED_PLUGINS</code>.",
|
||||
"DISCOVER_PLUGINS_name": "Відкрийте для себе плагіни",
|
||||
"DevDetail_Copy_Device_Title": "Скопіюйте деталі з пристрою",
|
||||
"DevDetail_Copy_Device_Tooltip": "Скопіюйте деталі пристрою зі спадного списку. Усе на цій сторінці буде перезаписано",
|
||||
"DevDetail_CustomProperties_Title": "",
|
||||
"DevDetail_CustomProps_reset_info": "",
|
||||
"DevDetail_DisplayFields_Title": "Дисплей",
|
||||
"DevDetail_EveandAl_AlertAllEvents": "Повідомлення про події",
|
||||
"DevDetail_EveandAl_AlertDown": "Сповіщення вниз",
|
||||
@@ -205,6 +208,7 @@
|
||||
"Device_Shortcut_OnlineChart": "Наявність пристрою",
|
||||
"Device_TableHead_AlertDown": "Сповіщення вниз",
|
||||
"Device_TableHead_Connected_Devices": "Зв'язки",
|
||||
"Device_TableHead_CustomProps": "",
|
||||
"Device_TableHead_Favorite": "улюблений",
|
||||
"Device_TableHead_FirstSession": "Перша сесія",
|
||||
"Device_TableHead_GUID": "GUID",
|
||||
@@ -305,6 +309,7 @@
|
||||
"Gen_ReadDocs": "Детальніше читайте в документах.",
|
||||
"Gen_Remove_All": "Видалити Все",
|
||||
"Gen_Remove_Last": "Видаліть останнім",
|
||||
"Gen_Reset": "",
|
||||
"Gen_Restore": "Запустіть Restore",
|
||||
"Gen_Run": "бігти",
|
||||
"Gen_Save": "зберегти",
|
||||
|
||||
@@ -60,12 +60,15 @@
|
||||
"BackDevices_darkmode_enabled": "已启用暗黑模式",
|
||||
"CLEAR_NEW_FLAG_description": "",
|
||||
"CLEAR_NEW_FLAG_name": "",
|
||||
"CustProps_cant_remove": "",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "这是维护设置。它指定将保留的事件条目的天数。所有较旧的事件将被定期删除。也适用于插件事件历史记录。",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "删除早于",
|
||||
"DISCOVER_PLUGINS_description": "",
|
||||
"DISCOVER_PLUGINS_name": "",
|
||||
"DevDetail_Copy_Device_Title": "<i class=\"fa fa-copy\"></i> 从设备复制详细信息",
|
||||
"DevDetail_Copy_Device_Tooltip": "从下拉列表中复制设备的详细信息。此页面上的所有内容都将被覆盖",
|
||||
"DevDetail_CustomProperties_Title": "",
|
||||
"DevDetail_CustomProps_reset_info": "",
|
||||
"DevDetail_DisplayFields_Title": "",
|
||||
"DevDetail_EveandAl_AlertAllEvents": "提醒所有事件",
|
||||
"DevDetail_EveandAl_AlertDown": "警报关闭",
|
||||
@@ -205,6 +208,7 @@
|
||||
"Device_Shortcut_OnlineChart": "设备统计",
|
||||
"Device_TableHead_AlertDown": "",
|
||||
"Device_TableHead_Connected_Devices": "链接",
|
||||
"Device_TableHead_CustomProps": "",
|
||||
"Device_TableHead_Favorite": "收藏",
|
||||
"Device_TableHead_FirstSession": "加入",
|
||||
"Device_TableHead_GUID": "GUID",
|
||||
@@ -305,6 +309,7 @@
|
||||
"Gen_ReadDocs": "在文档中阅读更多内容。",
|
||||
"Gen_Remove_All": "全部删除",
|
||||
"Gen_Remove_Last": "删除最后一个",
|
||||
"Gen_Reset": "",
|
||||
"Gen_Restore": "运行恢复",
|
||||
"Gen_Run": "运行",
|
||||
"Gen_Save": "保存",
|
||||
|
||||
8
front/plugins/custom_props/README.md
Executable file
8
front/plugins/custom_props/README.md
Executable file
@@ -0,0 +1,8 @@
|
||||
## Overview
|
||||
|
||||
Settings related to the custom properties functionality on a device.
|
||||
|
||||
### Usage
|
||||
|
||||
- Head to **Settings** > **Custom Properties** to adjust the default values.
|
||||
|
||||
370
front/plugins/custom_props/config.json
Executable file
370
front/plugins/custom_props/config.json
Executable file
@@ -0,0 +1,370 @@
|
||||
{
|
||||
"code_name": "custom_props",
|
||||
"unique_prefix": "CUSTPROP",
|
||||
"plugin_type": "system",
|
||||
"enabled": true,
|
||||
"data_source": "template",
|
||||
"show_ui": false,
|
||||
"localized": ["display_name", "description", "icon"],
|
||||
"display_name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Custom properties"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Settings related to the custom properties functionality on a device."
|
||||
}
|
||||
],
|
||||
"icon": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "<i class=\"fa fa-list\"></i>"
|
||||
}
|
||||
],
|
||||
"params": [],
|
||||
"settings": [
|
||||
{
|
||||
"function": "icon",
|
||||
"type": {
|
||||
"dataType": "array",
|
||||
"elements": [
|
||||
{
|
||||
"elementType": "input",
|
||||
"elementOptions": [
|
||||
{ "placeholder": "Enter value" },
|
||||
{ "suffix": "_in" },
|
||||
{ "cssClasses": "col-sm-10" },
|
||||
{ "prefillValue": "null" }
|
||||
],
|
||||
"transformers": []
|
||||
},
|
||||
{
|
||||
"elementType": "button",
|
||||
"elementOptions": [
|
||||
{ "sourceSuffixes": ["_in"] },
|
||||
{ "separator": "" },
|
||||
{ "cssClasses": "col-xs-12" },
|
||||
{ "onClick": "addList(this,false)" },
|
||||
{ "getStringKey": "Gen_Add" }
|
||||
],
|
||||
"transformers": []
|
||||
},
|
||||
{
|
||||
"elementType": "select",
|
||||
"elementHasInputValue": 1,
|
||||
"elementOptions": [
|
||||
{ "multiple": "true" },
|
||||
{ "readonly": "true" },
|
||||
{ "editable": "true" }
|
||||
],
|
||||
"transformers": []
|
||||
},
|
||||
{
|
||||
"elementType": "button",
|
||||
"elementOptions": [
|
||||
{ "sourceSuffixes": [] },
|
||||
{ "separator": "" },
|
||||
{ "cssClasses": "col-xs-6" },
|
||||
{ "onClick": "removeAllOptions(this)" },
|
||||
{ "getStringKey": "Gen_Remove_All" }
|
||||
],
|
||||
"transformers": []
|
||||
},
|
||||
{
|
||||
"elementType": "button",
|
||||
"elementOptions": [
|
||||
{ "sourceSuffixes": [] },
|
||||
{ "separator": "" },
|
||||
{ "cssClasses": "col-xs-6" },
|
||||
{ "onClick": "removeFromList(this)" },
|
||||
{ "getStringKey": "Gen_Remove_Last" }
|
||||
],
|
||||
"transformers": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"maxLength": 50,
|
||||
"default_value": [
|
||||
"PGkgY2xhc3M9ImZhcyBmYS10cmFzaC1hbHQiPjwvaT4=",
|
||||
"PGkgY2xhc3M9ImZhcyBmYS1leHRlcm5hbC1saW5rLWFsdCI+PC9pPg==",
|
||||
"PGkgY2xhc3M9ImZhcyBmYS1hcnJvdy1yaWdodCI+PC9pPg==",
|
||||
"PGkgY2xhc3M9ImZhcyBmYS1zZWFyY2giPjwvaT4=",
|
||||
"PGkgY2xhc3M9ImZhcyBmYS1jb2dzIj48L2k+",
|
||||
"PGkgY2xhc3M9ImZhcyBmYS1leWUiPjwvaT4=",
|
||||
"PGkgY2xhc3M9ImZhcyBmYS1kYXRhYmFzZSI+PC9pPg=="
|
||||
],
|
||||
"options": [],
|
||||
"localized": ["name","description"],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Icon"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "List of icons that can be used on a custom property."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "type",
|
||||
"type": {
|
||||
"dataType": "array",
|
||||
"elements": [
|
||||
{
|
||||
"elementType": "input",
|
||||
"elementOptions": [
|
||||
{ "placeholder": "Enter value" },
|
||||
{ "suffix": "_in" },
|
||||
{ "cssClasses": "col-sm-10" },
|
||||
{ "prefillValue": "null" }
|
||||
],
|
||||
"transformers": []
|
||||
},
|
||||
{
|
||||
"elementType": "button",
|
||||
"elementOptions": [
|
||||
{ "sourceSuffixes": ["_in"] },
|
||||
{ "separator": "" },
|
||||
{ "cssClasses": "col-xs-12" },
|
||||
{ "onClick": "addList(this,false)" },
|
||||
{ "getStringKey": "Gen_Add" }
|
||||
],
|
||||
"transformers": []
|
||||
},
|
||||
{
|
||||
"elementType": "select",
|
||||
"elementHasInputValue": 1,
|
||||
"elementOptions": [
|
||||
{ "multiple": "true" },
|
||||
{ "readonly": "true" },
|
||||
{ "editable": "true" }
|
||||
],
|
||||
"transformers": []
|
||||
},
|
||||
{
|
||||
"elementType": "button",
|
||||
"elementOptions": [
|
||||
{ "sourceSuffixes": [] },
|
||||
{ "separator": "" },
|
||||
{ "cssClasses": "col-xs-6" },
|
||||
{ "onClick": "removeAllOptions(this)" },
|
||||
{ "getStringKey": "Gen_Remove_All" }
|
||||
],
|
||||
"transformers": []
|
||||
},
|
||||
{
|
||||
"elementType": "button",
|
||||
"elementOptions": [
|
||||
{ "sourceSuffixes": [] },
|
||||
{ "separator": "" },
|
||||
{ "cssClasses": "col-xs-6" },
|
||||
{ "onClick": "removeFromList(this)" },
|
||||
{ "getStringKey": "Gen_Remove_Last" }
|
||||
],
|
||||
"transformers": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"maxLength": 50,
|
||||
"default_value": [
|
||||
"none",
|
||||
"data",
|
||||
"link",
|
||||
"link_new_tab",
|
||||
"show_notes",
|
||||
"delete_dev",
|
||||
"run_plugin"
|
||||
],
|
||||
"options": [],
|
||||
"localized": ["name","description"],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Type"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "List of property types. The default ones have specific functionality associated with it."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "args",
|
||||
"type": {
|
||||
"dataType": "string",
|
||||
"elements": [
|
||||
{
|
||||
"elementType": "input",
|
||||
"elementOptions": [],
|
||||
"transformers": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"maxLength": 50,
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": ["name","description"],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Arguments"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Arguments for the property type."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "name",
|
||||
"type": {
|
||||
"dataType": "string",
|
||||
"elements": [
|
||||
{
|
||||
"elementType": "input",
|
||||
"elementOptions": [],
|
||||
"transformers": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"maxLength": 50,
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": ["name","description"],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Name"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Name of the property displayed on hover."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "notes",
|
||||
"type": {
|
||||
"dataType": "string",
|
||||
"elements": [
|
||||
{
|
||||
"elementType": "input",
|
||||
"elementOptions": [],
|
||||
"transformers": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"maxLength": 50,
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": ["name","description"],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Notes"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Additional notes."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "show",
|
||||
"type": {
|
||||
"dataType": "boolean",
|
||||
"elements": [
|
||||
{
|
||||
"elementType": "input",
|
||||
"elementOptions": [{ "type": "checkbox" }],
|
||||
"transformers": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"default_value": true,
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Show"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Show in device list."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "actions",
|
||||
"type": {
|
||||
"dataType": "none",
|
||||
"elements": [
|
||||
{
|
||||
"elementType": "span",
|
||||
"elementOptions": [
|
||||
{
|
||||
"cssClasses": "input-group-addon pointer actionIcon"
|
||||
},
|
||||
{
|
||||
"placeholder": "<i class=\"far fa-trash-alt\"></i>"
|
||||
},
|
||||
{
|
||||
"onClick": "removeDataTableRow(this)"
|
||||
}
|
||||
],
|
||||
"transformers": []
|
||||
},
|
||||
{
|
||||
"elementType": "span",
|
||||
"elementOptions": [
|
||||
{
|
||||
"cssClasses": "input-group-addon pointer actionIcon"
|
||||
},
|
||||
{
|
||||
"placeholder": "<i class=\"far fa-clone\"></i>"
|
||||
},
|
||||
{
|
||||
"onClick": "cloneDataTableRow(this)"
|
||||
}
|
||||
],
|
||||
"transformers": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"maxLength": 50,
|
||||
"default_value": [
|
||||
],
|
||||
"options": [],
|
||||
"localized": ["name","description"],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Action"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Actions on the property."
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -347,7 +347,8 @@
|
||||
"Device_TableHead_LastIP",
|
||||
"Device_TableHead_Status",
|
||||
"Device_TableHead_MAC_full",
|
||||
"Device_TableHead_SourcePlugin"
|
||||
"Device_TableHead_SourcePlugin",
|
||||
"Device_TableHead_CustomProps"
|
||||
],
|
||||
"options": [
|
||||
"Device_TableHead_Name",
|
||||
@@ -375,7 +376,8 @@
|
||||
"Device_TableHead_SSID",
|
||||
"Device_TableHead_SourcePlugin",
|
||||
"Device_TableHead_PresentLastScan",
|
||||
"Device_TableHead_AlertDown"
|
||||
"Device_TableHead_AlertDown",
|
||||
"Device_TableHead_CustomProps"
|
||||
],
|
||||
"localized": ["name", "description"],
|
||||
"name": [
|
||||
|
||||
@@ -501,7 +501,7 @@ $settingsJSON_DB = json_encode($settings, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX
|
||||
}
|
||||
|
||||
// INPUT
|
||||
inputFormHtml = generateFormHtml(set, valIn);
|
||||
inputFormHtml = generateFormHtml(settingsData, set, valIn, null, null);
|
||||
|
||||
// construct final HTML for the setting
|
||||
setHtml += inputFormHtml + overrideHtml + `
|
||||
@@ -565,13 +565,12 @@ $settingsJSON_DB = json_encode($settings, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX
|
||||
setType = set["setType"]
|
||||
setCodeName = set["setKey"]
|
||||
|
||||
console.log(prefix);
|
||||
// console.log(prefix);
|
||||
|
||||
const setTypeObject = JSON.parse(setType.replace(/'/g, '"'));
|
||||
const setTypeObject = JSON.parse(processQuotes(setType))
|
||||
// console.log(setTypeObject);
|
||||
|
||||
const dataType = setTypeObject.dataType;
|
||||
|
||||
|
||||
// get the element with the input value(s)
|
||||
let elements = setTypeObject.elements.filter(element => element.elementHasInputValue === 1);
|
||||
@@ -602,12 +601,18 @@ $settingsJSON_DB = json_encode($settings, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX
|
||||
onClick,
|
||||
onChange,
|
||||
customParams,
|
||||
customId
|
||||
customId,
|
||||
columns
|
||||
} = handleElementOptions('none', elementOptions, transformers, val = "");
|
||||
|
||||
let value;
|
||||
|
||||
if (dataType === "string" ||
|
||||
if (dataType === "string" && elementWithInputValue.elementType === "datatable" ) {
|
||||
|
||||
value = collectTableData(`#${setCodeName}_table`)
|
||||
settingsArray.push([prefix, setCodeName, dataType, btoa(JSON.stringify(value))]);
|
||||
|
||||
} else if (dataType === "string" ||
|
||||
(dataType === "integer" && (inputType === "number" || inputType === "text"))) {
|
||||
|
||||
value = $('#' + setCodeName).val();
|
||||
@@ -646,11 +651,17 @@ $settingsJSON_DB = json_encode($settings, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
value = JSON.stringify(temps);
|
||||
|
||||
settingsArray.push([prefix, setCodeName, dataType, value]);
|
||||
|
||||
|
||||
} else if (dataType === "none") {
|
||||
// no value to save
|
||||
value = ""
|
||||
settingsArray.push([prefix, setCodeName, dataType, value]);
|
||||
|
||||
} else if (dataType === "json") {
|
||||
|
||||
value = $('#' + setCodeName).val();
|
||||
@@ -675,7 +686,7 @@ $settingsJSON_DB = json_encode($settings, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX
|
||||
|
||||
console.log(settingsArray);
|
||||
console.log( JSON.stringify(settingsArray));
|
||||
// return;
|
||||
// return; // 🐛 🔺
|
||||
// trigger a save settings event in the backend
|
||||
$.ajax({
|
||||
method: "POST",
|
||||
@@ -735,12 +746,14 @@ $settingsJSON_DB = json_encode($settings, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX
|
||||
{
|
||||
// check if config file has been updated
|
||||
$.get('/php/server/query_json.php', { file: 'app_state.json', nocache: Date.now() }, function(appState) {
|
||||
|
||||
console.log("Settings: Got app_state.json");
|
||||
|
||||
fileModificationTime = <?php echo filemtime($confPath)*1000;?>;
|
||||
|
||||
// console.log(appState["settingsImported"]*1000)
|
||||
importedMiliseconds = parseInt((appState["settingsImported"]*1000));
|
||||
humanReadable = (new Date(importedMiliseconds)).toLocaleString("en-UK", { timeZone: "<?php echo $timeZone?>" });
|
||||
|
||||
|
||||
// check if displayed settings are outdated
|
||||
if(appState["showSpinner"] || fileModificationTime > importedMiliseconds)
|
||||
@@ -754,6 +767,7 @@ $settingsJSON_DB = json_encode($settings, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX
|
||||
checkInitialization();
|
||||
}
|
||||
|
||||
humanReadable = (new Date(importedMiliseconds)).toLocaleString("en-UK", { timeZone: "<?php echo $timeZone?>" });
|
||||
document.getElementById('lastImportedTime').innerHTML = humanReadable;
|
||||
})
|
||||
|
||||
|
||||
@@ -59,6 +59,7 @@ sql_devices_all = """
|
||||
IFNULL(devSSID, '') AS devSSID,
|
||||
IFNULL(devSyncHubNode, '') AS devSyncHubNode,
|
||||
IFNULL(devSourcePlugin, '') AS devSourcePlugin,
|
||||
IFNULL(devCustomProps, '') AS devCustomProps,
|
||||
CASE
|
||||
WHEN devIsNew = 1 THEN 'New'
|
||||
WHEN devPresentLastScan = 1 THEN 'On-line'
|
||||
|
||||
@@ -475,6 +475,20 @@ class DB():
|
||||
|
||||
self.sql.execute(""" DROP VIEW IF EXISTS Sessions_Devices;""")
|
||||
self.sql.execute("""CREATE VIEW Sessions_Devices AS SELECT * FROM Sessions LEFT JOIN "Devices" ON ses_MAC = devMac;""")
|
||||
|
||||
|
||||
# add fields if missing
|
||||
|
||||
# devCustomProps column
|
||||
devCustomProps_missing = self.sql.execute ("""
|
||||
SELECT COUNT(*) AS CNTREC FROM pragma_table_info('Devices') WHERE name='devCustomProps'
|
||||
""").fetchone()[0] == 0
|
||||
|
||||
if devCustomProps_missing :
|
||||
mylog('verbose', ["[upgradeDB] Adding devCustomProps to the Devices table"])
|
||||
self.sql.execute("""
|
||||
ALTER TABLE "Devices" ADD "devCustomProps" TEXT
|
||||
""")
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Settings table setup
|
||||
|
||||
@@ -226,7 +226,8 @@ def create_new_devices (db):
|
||||
devGroup,
|
||||
devComments,
|
||||
devLogEvents,
|
||||
devLocation"""
|
||||
devLocation,
|
||||
devCustomProps"""
|
||||
|
||||
newDevDefaults = f"""{get_setting_value('NEWDEV_devAlertEvents')},
|
||||
{get_setting_value('NEWDEV_devAlertDown')},
|
||||
@@ -240,7 +241,9 @@ def create_new_devices (db):
|
||||
'{sanitize_SQL_input(get_setting_value('NEWDEV_devGroup'))}',
|
||||
'{sanitize_SQL_input(get_setting_value('NEWDEV_devComments'))}',
|
||||
{get_setting_value('NEWDEV_devLogEvents')},
|
||||
'{sanitize_SQL_input(get_setting_value('NEWDEV_devLocation'))}'"""
|
||||
'{sanitize_SQL_input(get_setting_value('NEWDEV_devLocation'))}',
|
||||
'{sanitize_SQL_input(get_setting_value('NEWDEV_devCustomProps'))}'
|
||||
"""
|
||||
|
||||
# Fetch data from CurrentScan skipping ignored devices by IP and MAC
|
||||
query = f"""SELECT cur_MAC, cur_Name, cur_Vendor, cur_ScanMethod, cur_IP, cur_SyncHubNodeName, cur_NetworkNodeMAC, cur_PORT, cur_NetworkSite, cur_SSID, cur_Type
|
||||
|
||||
@@ -62,6 +62,7 @@ class Device(ObjectType):
|
||||
devSSID = String()
|
||||
devSyncHubNode = String()
|
||||
devSourcePlugin = String()
|
||||
devCustomProps = String()
|
||||
devStatus = String()
|
||||
devIsRandomMac = Int()
|
||||
devParentChildrenCount = Int()
|
||||
|
||||
@@ -202,7 +202,7 @@ def importConfigs (db, all_plugins):
|
||||
# Plugins START
|
||||
# -----------------
|
||||
|
||||
necessary_plugins = ['UI', 'DBCLNP', 'INTRNT','MAINT','NEWDEV', 'SETPWD', 'SYNC', 'VNDRPDT', 'WORKFLOWS']
|
||||
necessary_plugins = ['UI', 'CUSTPROP', 'DBCLNP', 'INTRNT','MAINT','NEWDEV', 'SETPWD', 'SYNC', 'VNDRPDT', 'WORKFLOWS']
|
||||
# make sure necessary plugins are loaded
|
||||
conf.LOADED_PLUGINS += [plugin for plugin in necessary_plugins if plugin not in conf.LOADED_PLUGINS]
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ def test_updateSubnets():
|
||||
assert len(result) == 2
|
||||
|
||||
# -------------------------------------------------------------------------------
|
||||
# Function to insert 10,000 random device entries
|
||||
# Function to insert N random device entries
|
||||
def insert_devices(db_path, num_entries=1):
|
||||
conn = sqlite3.connect(db_path)
|
||||
cursor = conn.cursor()
|
||||
@@ -85,9 +85,10 @@ def insert_devices(db_path, num_entries=1):
|
||||
devSite,
|
||||
devSSID,
|
||||
devSyncHubNode,
|
||||
devSourcePlugin
|
||||
devSourcePlugin,
|
||||
devCustomProps
|
||||
)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
|
||||
"""
|
||||
|
||||
# List of device types, vendors, groups, locations
|
||||
@@ -128,6 +129,7 @@ def insert_devices(db_path, num_entries=1):
|
||||
dev_ssid = "" # Left as NULL
|
||||
dev_sync_hub_node = "" # Left as NULL
|
||||
dev_source_plugin = "" # Left as NULL
|
||||
dev_devCustomProps = "" # Left as NULL
|
||||
|
||||
# Execute the insert query
|
||||
cursor.execute(insert_query, (
|
||||
@@ -160,7 +162,8 @@ def insert_devices(db_path, num_entries=1):
|
||||
dev_site,
|
||||
dev_ssid,
|
||||
dev_sync_hub_node,
|
||||
dev_source_plugin
|
||||
dev_source_plugin,
|
||||
dev_devCustomProps
|
||||
))
|
||||
|
||||
# Commit after every 1000 rows to improve performance
|
||||
|
||||
Reference in New Issue
Block a user