diff --git a/.github/workflows/docker_rewrite.yml b/.github/workflows/docker_rewrite.yml new file mode 100755 index 00000000..72e0a835 --- /dev/null +++ b/.github/workflows/docker_rewrite.yml @@ -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 }} diff --git a/docs/DEVICE_HEURISTICS.md b/docs/DEVICE_HEURISTICS.md index 082e56c0..e274aefc 100755 --- a/docs/DEVICE_HEURISTICS.md +++ b/docs/DEVICE_HEURISTICS.md @@ -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. diff --git a/front/appEvents.php b/front/appEvents.php index 0f0cbed3..f3aabcdb 100755 --- a/front/appEvents.php +++ b/front/appEvents.php @@ -1,7 +1,7 @@ diff --git a/front/css/app.css b/front/css/app.css index 06339a4b..17cd98b8 100755 --- a/front/css/app.css +++ b/front/css/app.css @@ -1726,6 +1726,16 @@ input[readonly] { width: 92%; } +#modal-ok +{ + z-index: 1051; /*highest priority*/ +} + +#modal-form-plc +{ + display: grid; +} + /* ----------------------------------------------------------------- */ /* NETWORK page */ /* ----------------------------------------------------------------- */ diff --git a/front/deviceDetails.php b/front/deviceDetails.php index 3042ea3e..ecc2d72b 100755 --- a/front/deviceDetails.php +++ b/front/deviceDetails.php @@ -25,7 +25,7 @@
- +

 Quering device info... diff --git a/front/deviceDetailsEdit.php b/front/deviceDetailsEdit.php index 5ae68e4d..46c9eb99 100755 --- a/front/deviceDetailsEdit.php +++ b/front/deviceDetailsEdit.php @@ -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 = '') { diff --git a/front/devices.php b/front/devices.php index 0a7ac674..c4a03263 100755 --- a/front/devices.php +++ b/front/devices.php @@ -1004,9 +1004,7 @@ function initializeDatatable (status) { } - }); - - + }); } diff --git a/front/js/common.js b/front/js/common.js index 0d4d3745..3dc4cf15 100755 --- a/front/js/common.js +++ b/front/js/common.js @@ -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 } diff --git a/front/js/modal.js b/front/js/modal.js index 12747be9..404c06d9 100755 --- a/front/js/modal.js +++ b/front/js/modal.js @@ -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 = ` +
+ +
+ ${generateFormHtml( + null, // settingsData only required for datatables + setObj, + fieldData.toString(), + fieldOptionsOverride, + null + )} +
+
+ `; + + // 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 diff --git a/front/js/settings_utils.js b/front/js/settings_utils.js index 715af297..10340c51 100755 --- a/front/js/settings_utils.js +++ b/front/js/settings_utils.js @@ -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( + ` ${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); @@ -720,8 +778,8 @@ const handleElementOptions = (setKey, elementOptions, transformers, val) => { let customParams = ""; let customId = ""; let columns = []; - let base64Regex = ""; - + 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)} `; diff --git a/front/js/ui_components.js b/front/js/ui_components.js index 79796045..e9f7b9e7 100755 --- a/front/js/ui_components.js +++ b/front/js/ui_components.js @@ -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({ diff --git a/front/maintenance.php b/front/maintenance.php index c8643058..f97846e2 100755 --- a/front/maintenance.php +++ b/front/maintenance.php @@ -1,6 +1,6 @@ diff --git a/front/multiEditCore.php b/front/multiEditCore.php index a80992d9..67dde08c 100755 --- a/front/multiEditCore.php +++ b/front/multiEditCore.php @@ -136,7 +136,8 @@ customParams, customId, columns, - base64Regex + base64Regex, + elementOptionsBase64 } = handleElementOptions('none', elementOptions, transformers, val = ""); // render based on element type diff --git a/front/network.php b/front/network.php index 0a12bc7b..0fe3355a 100755 --- a/front/network.php +++ b/front/network.php @@ -1,6 +1,6 @@