Merge pull request #1134 from jokob-sk/main

sync
This commit is contained in:
Jokob @NetAlertX
2025-08-10 20:28:10 +10:00
committed by GitHub
23 changed files with 622 additions and 203 deletions

81
.github/workflows/docker_rewrite.yml vendored Executable file
View File

@@ -0,0 +1,81 @@
name: docker
on:
push:
branches:
- rewrite
tags:
- '*.*.*'
pull_request:
branches:
- rewrite
jobs:
docker_dev:
runs-on: ubuntu-latest
timeout-minutes: 30
permissions:
contents: read
packages: write
if: >
contains(github.event.head_commit.message, 'PUSHPROD') != 'True' &&
github.repository == 'jokob-sk/NetAlertX'
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Set up dynamic build ARGs
id: getargs
run: echo "version=$(cat ./stable/VERSION)" >> $GITHUB_OUTPUT
- name: Get release version
id: get_version
run: echo "version=Dev" >> $GITHUB_OUTPUT
- name: Create .VERSION file
run: echo "${{ steps.get_version.outputs.version }}" >> .VERSION
- name: Docker meta
id: meta
uses: docker/metadata-action@v4
with:
images: |
ghcr.io/jokob-sk/netalertx-dev-rewrite
jokobsk/netalertx-dev-rewrite
tags: |
type=raw,value=latest
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=sha
- name: Log in to Github Container Registry (GHCR)
uses: docker/login-action@v3
with:
registry: ghcr.io
username: jokob-sk
password: ${{ secrets.GITHUB_TOKEN }}
- name: Log in to DockerHub
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v3
with:
context: .
platforms: linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v6
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

View File

@@ -53,6 +53,9 @@ The function `guess_device_attributes(...)` runs a series of matching functions
4. IP pattern → `match_ip()`
5. Final fallback → defaults defined in the `NEWDEV_devIcon` and `NEWDEV_devType` settings.
> [!NOTE]
> The app will try guessing the device type or icon if `devType` or `devIcon` are `""` or `"null"`.
### Use of default values
The guessing process runs for every device **as long as the current type or icon still matches the default values**. Even if earlier heuristics return a match, the system continues evaluating additional clues — like name or IP — to try and replace placeholders.

View File

@@ -1,7 +1,7 @@
<?php
require 'php/templates/header.php';
require 'php/templates/notification.php';
require 'php/templates/modals.php';
?>
<!-- ----------------------------------------------------------------------- -->

View File

@@ -1726,6 +1726,16 @@ input[readonly] {
width: 92%;
}
#modal-ok
{
z-index: 1051; /*highest priority*/
}
#modal-form-plc
{
display: grid;
}
/* ----------------------------------------------------------------- */
/* NETWORK page */
/* ----------------------------------------------------------------- */

View File

@@ -25,7 +25,7 @@
<!-- Content header--------------------------------------------------------- -->
<section class="content-header">
<?php require 'php/templates/notification.php'; ?>
<?php require 'php/templates/modals.php'; ?>
<h1 id="pageTitle">
&nbsp<small>Quering device info...</small>

View File

@@ -290,18 +290,6 @@
});
}
// ----------------------------------------
// Show the description of a setting
function showDescriptionPopup(e) {
console.log($(e).attr("my-set-key"));
showModalOK("Info", getString($(e).attr("my-set-key") + '_description'))
}
// -----------------------------------------------------------------------------
// Save device data to DB
function setDeviceData(direction = '', refreshCallback = '') {

View File

@@ -1005,8 +1005,6 @@ function initializeDatatable (status) {
}
});
}

View File

@@ -1032,6 +1032,7 @@ function getDevDataByMac(macAddress, dbColumn) {
}
}
console.error("⚠ Device with MAC not found:" + macAddress)
return "Unknown"; // Return a default value if MAC address is not found
}

View File

@@ -161,6 +161,91 @@ function showModalFieldInput(
$(`#${prefix}`).modal("show");
}
// -----------------------------------------------------------------------------
function showModalPopupForm(
title,
message,
btnCancel = getString("Gen_Cancel"),
btnOK = getString("Gen_Okay"),
curValue = "",
callbackFunction = null,
triggeredBy = null,
popupFormJson = null,
parentSettingKey = null
) {
// set captions
prefix = "modal-form";
console.log(popupFormJson);
$(`#${prefix}-title`).html(title);
$(`#${prefix}-message`).html(message);
$(`#${prefix}-cancel`).html(btnCancel);
$(`#${prefix}-OK`).html(btnOK);
if (callbackFunction != null) {
modalCallbackFunction = callbackFunction;
}
if (triggeredBy != null) {
$('#'+prefix).attr("data-myparam-triggered-by", triggeredBy)
}
outputHtml = "";
if (Array.isArray(popupFormJson)) {
popupFormJson.forEach((field, index) => {
// You'll need to define these or map them from `field`
const setName = field.name?.find(n => n.language_code === "en_us")?.string || setKey;
const labelClasses = "col-sm-2"; // example, or from your obj.labelClasses
const inputClasses = "col-sm-10"; // example, or from your obj.inputClasses
const fieldData = field.default_value ?? "";
const fieldOptionsOverride = field.type?.elements[0]?.elementOptions || [];
const setKey = field.function || `field_${index}`;
const setValue = field.default_value ?? "";
const setType = JSON.stringify(field.type);
const setEvents = field.events || []; // default to empty array if missing
const setObj = { setKey, setValue, setType, setEvents };
// Generate the input field HTML
const inputFormHtml = `
<div class="form-group col-xs-12">
<label id="${setKey}_label" class="${labelClasses}"> ${setName}
<i my-set-key="${parentSettingKey}_popupform_${setKey}"
title="${getString("Settings_Show_Description")}"
class="fa fa-circle-info pointer helpIconSmallTopRight"
onclick="showDescriptionPopup(this)">
</i>
</label>
<div class="${inputClasses}">
${generateFormHtml(
null, // settingsData only required for datatables
setObj,
fieldData.toString(),
fieldOptionsOverride,
null
)}
</div>
</div>
`;
// Append to result
outputHtml += inputFormHtml;
});
}
$(`#modal-form-plc`).html(outputHtml);
// $(`#${prefix}-field`).val(curValue);
// setTimeout(function () {
// $(`#${prefix}-field`).focus();
// }, 500);
// Show modal
$(`#${prefix}`).modal("show");
}
// -----------------------------------------------------------------------------
function modalDefaultOK() {
// Hide modal

View File

@@ -67,6 +67,15 @@ function getPluginConfig(pluginsData, prefix) {
return result;
}
// ----------------------------------------
// Show the description of a setting
function showDescriptionPopup(e) {
console.log($(e).attr("my-set-key"));
showModalOK("Info", getString($(e).attr("my-set-key") + '_description'))
}
// -------------------------------------------------------------------
// Generate plugin HTML card based on prefixes in an array
function pluginCards(prefixesOfEnabledPlugins, includeSettings) {
@@ -299,6 +308,45 @@ function removeDataTableRow(el) {
}
}
// ---------------------------------------------------------
// Add item via pop up form dialog
function addViaPopupForm(element) {
console.log(element)
const fromId = $(element).attr("my-input-from");
const toId = $(element).attr("my-input-to");
const curValue = $(`#${fromId}`).val();
const triggeredBy = $(element).attr("id");
const parsed = JSON.parse(atob($(element).data("elementoptionsbase64")));
const popupFormJson = parsed.find(obj => "popupForm" in obj)?.popupForm ?? null;
console.log(`fromId | toId | triggeredBy | curValue: ${fromId} | ${toId} | ${triggeredBy} | ${curValue}`);
showModalPopupForm(
`<i class="fa fa-pen-to-square"></i> ${getString(
"Gen_Update_Value"
)}`, // title
getString("settings_update_item_warning"), // message
getString("Gen_Cancel"), // btnCancel
getString("Gen_Add"), // btnOK
curValue, // curValue
null, // callbackFunction
triggeredBy, // triggeredBy
popupFormJson, // popupform
toId // parentSettingKey
);
}
// ---------------------------------------------------------
// Add item to list via popup form
function addViaPopupFormToList(element, clearInput = true) {
// flag something changes to prevent navigating from page
settingsChanged();
}
// ---------------------------------------------------------
// Add item to list
function addList(element, clearInput = true) {
@@ -622,8 +670,6 @@ function generateOptionsOrSetOptions(
// obj.push({ id: item, name: item })
options = arrayToObject(createArray(overrideOptions ? overrideOptions : getSettingOptions(setKey)))
// Call to render lists
renderList(
options,
@@ -633,8 +679,6 @@ function generateOptionsOrSetOptions(
targetField,
transformers
);
}
@@ -655,6 +699,13 @@ function applyTransformers(val, transformers) {
val = btoa(val);
}
break;
case "name|base64":
// // Implement base64 logic
// if (!isBase64(val)) {
// val = btoa(val);
// }
val = val; // probably TODO ⚠
break;
case "getString":
// no change
val = val;
@@ -681,6 +732,13 @@ function reverseTransformers(val, transformers) {
val = atob(val);
}
break;
case "name|base64":
// // Implement base64 decoding logic
// if (isBase64(val)) {
// val = atob(val);
// }
val = val; // probably TODO ⚠
break;
case "getString":
// retrieve string
val = getString(val);
@@ -721,7 +779,7 @@ const handleElementOptions = (setKey, elementOptions, transformers, val) => {
let customId = "";
let columns = [];
let base64Regex = "";
let elementOptionsBase64 = btoa(JSON.stringify(elementOptions));
elementOptions.forEach((option) => {
if (option.prefillValue) {
@@ -804,7 +862,8 @@ const handleElementOptions = (setKey, elementOptions, transformers, val) => {
customParams,
customId,
columns,
base64Regex
base64Regex,
elementOptionsBase64
};
};
@@ -955,6 +1014,8 @@ function generateFormHtml(settingsData, set, overrideValue, overrideOptions, ori
// }
// Parse the setType JSON string
console.log(processQuotes(setType));
const setTypeObject = JSON.parse(processQuotes(setType))
const dataType = setTypeObject.dataType;
const elements = setTypeObject.elements || [];
@@ -982,7 +1043,8 @@ function generateFormHtml(settingsData, set, overrideValue, overrideOptions, ori
customParams,
customId,
columns,
base64Regex
base64Regex,
elementOptionsBase64
} = handleElementOptions(setKey, elementOptions, transformers, inVal);
// Override value
@@ -1051,6 +1113,7 @@ function generateFormHtml(settingsData, set, overrideValue, overrideOptions, ori
my-originalSetKey="${originalSetKey}"
my-input-from="${sourceIds}"
my-input-to="${setKey}"
data-elementoptionsbase64="${elementOptionsBase64}"
onclick="${onClick}">
${getString(getStringKey)}
</button>`;

View File

@@ -782,25 +782,17 @@ function initSelect2() {
// ------------------------------------------
// Render a device link with hover-over functionality
function renderDeviceLink(data, container, useName = false) {
if (!data.id) return data.text; // default placeholder etc.
if (!data.id || !isValidMac(data.id)) return data.text; // default placeholder etc.
const device = getDevDataByMac(data.id);
console.log('mac 🔽');
console.log(data.id);
console.log('mac 🔼');
console.log('device 🔽');
console.log(device);
console.log('device 🔼');
const badge = getStatusBadgeParts(
device.devPresentLastScan,
device.devAlertDown,
device.devMac
);
// Add badge class and hover-info class to container
// badge class and hover-info class to container
$(container)
.addClass(`${badge.cssClass} hover-node-info`)
.attr({

View File

@@ -1,6 +1,6 @@
<?php
require 'php/templates/header.php';
require 'php/templates/notification.php';
require 'php/templates/modals.php';
?>
<!-- Page ------------------------------------------------------------------ -->

View File

@@ -136,7 +136,8 @@
customParams,
customId,
columns,
base64Regex
base64Regex,
elementOptionsBase64
} = handleElementOptions('none', elementOptions, transformers, val = "");
// render based on element type

View File

@@ -1,6 +1,6 @@
<?php
require 'php/templates/header.php';
require 'php/templates/notification.php';
require 'php/templates/modals.php';
?>
<script>

View File

@@ -1,6 +1,6 @@
<?php
require 'php/templates/notification.php';
require 'php/templates/modals.php';
//------------------------------------------------------------------------------
// check if authenticated
require_once $_SERVER['DOCUMENT_ROOT'] . '/php/templates/security.php';

View File

@@ -117,6 +117,29 @@
</div>
</div>
<!-- Modal form input -->
<div class="modal fade" id="modal-form" data-myparam-triggered-by="" style="display: none;">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 id="modal-form-title" class="modal-title"> Modal Title </h4>
</div>
<div id="modal-form-message" class="modal-body"> Modal message </div>
<div id="modal-form-plc"></div>
<div class="modal-footer">
<button id="modal-form-cancel" type="button" class="btn btn-outline pull-left" style="min-width: 80px;" data-dismiss="modal"> Cancel </button>
<button id="modal-form-OK" type="button" class="btn btn-outline btn-modal-submit" style="min-width: 80px;" onclick="modalDefaultForm()"> OK </button>
</div>
</div>
</div>
</div>
<!-- Modal field input -->
<div class="modal modal-warning fade" id="modal-field-input" data-myparam-triggered-by="" style="display: none;">

View File

@@ -1,7 +1,7 @@
<?php
require 'php/templates/header.php';
require 'php/templates/notification.php';
require 'php/templates/modals.php';
?>
<!-- Page ------------------------------------------------------------------ -->

View File

@@ -16,17 +16,21 @@
}
],
"show_ui": true,
"localized": ["display_name", "description", "icon"],
"localized": [
"display_name",
"description",
"icon"
],
"display_name": [
{
"language_code": "en_us",
"string": "Display Name"
"string": "UniFi import (API)"
}
],
"description": [
{
"language_code": "en_us",
"string": "Plugin to ..."
"string": "This plugin is used to import devices from an UNIFI controller via the Site Manager API."
}
],
"icon": [
@@ -39,21 +43,29 @@
"settings": [
{
"function": "RUN",
"events": ["run"],
"events": [
"run"
],
"type": {
"dataType": "string",
"elements": [
{ "elementType": "select", "elementOptions": [], "transformers": [] }
{
"elementType": "select",
"elementOptions": [],
"transformers": []
}
]
},
"default_value": "disabled",
"options": [
"disabled",
"once",
"schedule"
],
"localized": ["name", "description"],
"localized": [
"name",
"description"
],
"name": [
{
"language_code": "en_us",
@@ -63,7 +75,7 @@
"description": [
{
"language_code": "en_us",
"string": "When the plugin should run. Good options are <code>always_after_scan</code>, <code>on_new_device</code>, <code>on_notification</code>"
"string": "When the plugin should run. Good options are <code>schedule</code>, <code>once</code>."
}
]
},
@@ -100,7 +112,10 @@
},
"default_value": "*/5 * * * *",
"options": [],
"localized": ["name", "description"],
"localized": [
"name",
"description"
],
"name": [
{
"language_code": "en_us",
@@ -110,7 +125,7 @@
"description": [
{
"language_code": "en_us",
"string": "Only enabled if you select <code>schedule</code> in the <a href=\"#SYNC_RUN\"><code>SYNC_RUN</code> setting</a>. Make sure you enter the schedule in the correct cron-like format (e.g. validate at <a href=\"https://crontab.guru/\" target=\"_blank\">crontab.guru</a>). For example entering <code>0 4 * * *</code> will run the scan after 4 am in the <a onclick=\"toggleAllSettings()\" href=\"#TIMEZONE\"><code>TIMEZONE</code> you set above</a>. Will be run NEXT time the time passes."
"string": "Only enabled if you select <code>schedule</code> in the <a href=\"#UNIFIAPI_RUN\"><code>UNIFIAPI_RUN</code> setting</a>. Make sure you enter the schedule in the correct cron-like format (e.g. validate at <a href=\"https://crontab.guru/\" target=\"_blank\">crontab.guru</a>). For example entering <code>0 4 * * *</code> will run the scan after 4 am in the <a onclick=\"toggleAllSettings()\" href=\"#TIMEZONE\"><code>TIMEZONE</code> you set above</a>. Will be run NEXT time the time passes."
}
]
},
@@ -121,14 +136,21 @@
"elements": [
{
"elementType": "input",
"elementOptions": [{ "readonly": "true" }],
"elementOptions": [
{
"readonly": "true"
}
],
"transformers": []
}
]
},
"default_value": "python3 /app/front/plugins/unifi_api_import/unifi_api_import.py",
"options": [],
"localized": ["name", "description"],
"localized": [
"name",
"description"
],
"name": [
{
"language_code": "en_us",
@@ -149,14 +171,21 @@
"elements": [
{
"elementType": "input",
"elementOptions": [{ "type": "number" }],
"elementOptions": [
{
"type": "number"
}
],
"transformers": []
}
]
},
"default_value": 10,
"options": [],
"localized": ["name", "description"],
"localized": [
"name",
"description"
],
"name": [
{
"language_code": "en_us",
@@ -171,28 +200,52 @@
]
},
{
"function": "devCustomProps",
"function": "sites",
"type": {
"dataType": "array",
"elements": [
{
"elementType": "popupform",
"elementHasInputValue": 1,
"elementType": "button",
"elementOptions": [
{
"fields": [
"sourceSuffixes": [
"_in"
]
},
{
"function": "hide.site.name",
"separator": ""
},
{
"cssClasses": "col-xs-12"
},
{
"onClick": "addViaPopupForm(this)"
},
{
"getStringKey": "Gen_Add"
},
{
"popupForm": [
{
"function": "name",
"type": {
"dataType": "string",
"elements": [
{
"elementType": "input",
"elementOptions": [
{ "placeholder": "Enter value" },
{ "suffix": "_in" },
{ "cssClasses": "col-sm-10" },
{ "prefillValue": "null" }
{
"placeholder": "Enter value"
},
{
"suffix": "_in"
},
{
"cssClasses": "col-sm-10"
},
{
"prefillValue": "null"
}
],
"transformers": []
}
@@ -200,7 +253,10 @@
},
"default_value": "default",
"options": [],
"localized": ["name", "description"],
"localized": [
"name",
"description"
],
"name": [
{
"language_code": "en_us",
@@ -210,27 +266,179 @@
"description": [
{
"language_code": "en_us",
"string": "The name of your site. Not used in code and only for.... "
"string": "The name of your site. Use a descriptive name."
}
]
},
{
"settingKey": "hide.site.name",
"typeOverride": {
"function": "base_url",
"type": {
"dataType": "string",
"elements": [
{
"elementType": "span",
"elementType": "input",
"elementOptions": [
{
"cssClasses": "input-group-addon iconPreview"
"placeholder": "https://host_ip/proxy/network/integration/"
},
{
"getStringKey": "Gen_SelectIcon"
"suffix": "_in"
},
{
"customId": "CUSTPROP_icon_preview"
"cssClasses": "col-sm-10"
},
{
"prefillValue": "null"
}
],
"transformers": []
}
]
},
"default_value": "default",
"options": [],
"localized": [
"name",
"description"
],
"name": [
{
"language_code": "en_us",
"string": "Base URL"
}
],
"description": [
{
"language_code": "en_us",
"string": "You can find your base url in the UniFi Site Manager in <i>Settings -> Control Plane -> Integrations</i> in the <i>API Request Format</i> section, (e.g. <code>https://host_ip/proxy/network/integration/</code>)."
}
]
},
{
"function": "version",
"type": {
"dataType": "string",
"elements": [
{
"elementType": "input",
"elementOptions": [
{
"placeholder": "v1"
},
{
"suffix": "_in"
},
{
"cssClasses": "col-sm-10"
},
{
"prefillValue": "null"
}
],
"transformers": []
}
]
},
"default_value": "default",
"options": [],
"localized": [
"name",
"description"
],
"name": [
{
"language_code": "en_us",
"string": "API version"
}
],
"description": [
{
"language_code": "en_us",
"string": "The version of the API (e.g.: <code>v1</code>)."
}
]
},
{
"function": "api_key",
"type": {
"dataType": "string",
"elements": [
{
"elementType": "input",
"elementOptions": [
{
"placeholder": "Enter value"
},
{
"suffix": "_in"
},
{
"cssClasses": "col-sm-10"
},
{
"prefillValue": "null"
}
],
"transformers": []
}
]
},
"default_value": "default",
"options": [],
"localized": [
"name",
"description"
],
"name": [
{
"language_code": "en_us",
"string": "API key"
}
],
"description": [
{
"language_code": "en_us",
"string": "You can get an API key in your UniFi Site Manager in <i>Settings -> Control Plane -> Integrations</i>."
}
]
},
{
"function": "hide.site.verify_ssl",
"type": {
"dataType": "boolean",
"elements": [
{
"elementType": "input",
"elementOptions": [
{
"type": "checkbox"
}
],
"transformers": []
}
]
},
"default_value": 1,
"options": [],
"localized": [
"name",
"description"
],
"name": [
{
"language_code": "en_us",
"string": "Verify SSL"
}
],
"description": [
{
"language_code": "en_us",
"string": "Disable if you do not have an SSL certificate set up."
}
]
}
],
"transformers": []
}
],
"transformers": []
@@ -240,44 +448,57 @@
"elementHasInputValue": 1,
"elementOptions": [
{
"cssClasses": "iconInputVal myhidden"
"multiple": "true"
},
{
"onChange": "updateIconPreview(this)"
"readonly": "true"
},
{
"customParams": "CUSTPROP_icon,CUSTPROP_icon_preview"
"editable": "true"
}
],
"transformers": [
"name|base64"
]
},
{
"elementType": "button",
"elementOptions": [
{
"sourceSuffixes": []
},
{
"separator": ""
},
{
"cssClasses": "col-xs-6"
},
{
"onClick": "removeFromList(this)"
},
{
"getStringKey": "Gen_Remove_Last"
}
],
"transformers": []
}
]
}
},
{
"settingKey": "hide.site.base_url",
"optionsOverride": "setting.CUSTPROP_type",
"typeOverride": {
"dataType": "string",
"elements": [
"elementType": "button",
"elementOptions": [
{
"elementType": "select",
"elementOptions": [],
"transformers": []
}
]
}
"sourceSuffixes": []
},
{
"settingKey": "hide.site.version"
"separator": ""
},
{
"settingKey": "hide.site.api_key"
"cssClasses": "col-xs-6"
},
{
"settingKey": "hide.site.verify_ssl"
}
]
"onClick": "removeAllOptions(this)"
},
{
"getStringKey": "Gen_Remove_All"
}
],
"transformers": []
@@ -299,92 +520,7 @@
"description": [
{
"language_code": "en_us",
"string": "Unifi sites"
}
]
},
{
"function": "sites",
"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."
"string": "UniFi sites"
}
]
}
@@ -397,7 +533,9 @@
"type": "none",
"default_value": "",
"options": [],
"localized": ["name"],
"localized": [
"name"
],
"name": [
{
"language_code": "en_us",
@@ -413,7 +551,9 @@
"type": "device_name_mac",
"default_value": "",
"options": [],
"localized": ["name"],
"localized": [
"name"
],
"name": [
{
"language_code": "en_us",
@@ -429,7 +569,9 @@
"type": "device_ip",
"default_value": "",
"options": [],
"localized": ["name"],
"localized": [
"name"
],
"name": [
{
"language_code": "en_us",
@@ -445,7 +587,9 @@
"type": "label",
"default_value": "",
"options": [],
"localized": ["name"],
"localized": [
"name"
],
"name": [
{
"language_code": "en_us",
@@ -461,7 +605,9 @@
"type": "label",
"default_value": "",
"options": [],
"localized": ["name"],
"localized": [
"name"
],
"name": [
{
"language_code": "en_us",
@@ -477,7 +623,9 @@
"type": "label",
"default_value": "",
"options": [],
"localized": ["name"],
"localized": [
"name"
],
"name": [
{
"language_code": "en_us",
@@ -492,7 +640,9 @@
"type": "label",
"default_value": "",
"options": [],
"localized": ["name"],
"localized": [
"name"
],
"name": [
{
"language_code": "en_us",
@@ -511,7 +661,9 @@
"type": "label",
"default_value": "",
"options": [],
"localized": ["name"],
"localized": [
"name"
],
"name": [
{
"language_code": "en_us",
@@ -526,7 +678,9 @@
"type": "label",
"default_value": "",
"options": [],
"localized": ["name"],
"localized": [
"name"
],
"name": [
{
"language_code": "en_us",
@@ -541,7 +695,9 @@
"type": "label",
"default_value": "",
"options": [],
"localized": ["name"],
"localized": [
"name"
],
"name": [
{
"language_code": "en_us",
@@ -573,7 +729,9 @@
"replacement": "<div style='text-align:center'><i class='fa-solid fa-question'></i></div>"
}
],
"localized": ["name"],
"localized": [
"name"
],
"name": [
{
"language_code": "en_us",

View File

@@ -1,7 +1,7 @@
<?php
require 'php/templates/header.php';
require 'php/templates/notification.php';
require 'php/templates/modals.php';
?>

View File

@@ -58,6 +58,12 @@ $settingsJSON_DB = json_encode($settings, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX
<div id="settingsPage" class="content-wrapper">
<a style="cursor:pointer">
<span>
<i id='toggleSettings' onclick="toggleAllSettings()" class="settings-expand-icon fa fa-angle-double-down"></i>
</span>
</a>
<!-- Content header--------------------------------------------------------- -->
<section class="content-header">
@@ -597,7 +603,8 @@ $settingsJSON_DB = json_encode($settings, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX
customParams,
customId,
columns,
base64Regex
base64Regex,
elementOptionsBase64
} = handleElementOptions('none', elementOptions, transformers, val = "");
let value;

View File

@@ -13,7 +13,7 @@
require 'php/templates/header.php';
?>
<?php require 'php/templates/notification.php'; ?>
<?php require 'php/templates/modals.php'; ?>
<!-- ----------------------------------------------------------------------- -->

View File

@@ -1,7 +1,7 @@
<?php
require 'php/templates/header.php';
require 'php/templates/notification.php';
require 'php/templates/modals.php';
?>
<!-- ----------------------------------------------------------------------- -->

View File

@@ -275,6 +275,15 @@ def importConfigs (db, all_plugins):
# Save the user defined value into the object
set["value"] = v
# Now check for popupForm inside elements → elementOptions
elements = set.get("type", {}).get("elements", [])
for element in elements:
for option in element.get("elementOptions", []):
if "popupForm" in option:
for popup_entry in option["popupForm"]:
popup_pref = key + "_popupform_" + popup_entry.get("function", "")
stringSqlParams = collect_lang_strings(popup_entry, popup_pref, stringSqlParams)
# Collect settings related language strings
# Creates an entry with key, for example ARPSCAN_CMD_name
stringSqlParams = collect_lang_strings(set, pref + "_" + set["function"], stringSqlParams)