mirror of
https://github.com/jokob-sk/NetAlertX.git
synced 2025-12-07 09:36:05 -08:00
Compare commits
15 Commits
1bce2e80e8
...
rewrite
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b28cd243f0 | ||
|
|
dce8c34064 | ||
|
|
9502ee0cd0 | ||
|
|
8eb4ffe3ed | ||
|
|
4be59807e5 | ||
|
|
4712a2ff29 | ||
|
|
f9179a1e89 | ||
|
|
a6df204721 | ||
|
|
101189ae7c | ||
|
|
f25c012fbe | ||
|
|
868a85d84c | ||
|
|
771dd4b176 | ||
|
|
ed4d3bf17c | ||
|
|
7c728fbe36 | ||
|
|
4ff9d01ef5 |
2
.github/FUNDING.yml
vendored
2
.github/FUNDING.yml
vendored
@@ -1,3 +1,3 @@
|
|||||||
github: jokob-sk
|
github: jokob-sk
|
||||||
patreon: 84385063
|
patreon: netalertx
|
||||||
buy_me_a_coffee: jokobsk
|
buy_me_a_coffee: jokobsk
|
||||||
|
|||||||
81
.github/workflows/docker_rewrite.yml
vendored
Executable file
81
.github/workflows/docker_rewrite.yml
vendored
Executable 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 }}
|
||||||
@@ -13,7 +13,7 @@ ENV PATH="/opt/venv/bin:$PATH"
|
|||||||
|
|
||||||
COPY . ${INSTALL_DIR}/
|
COPY . ${INSTALL_DIR}/
|
||||||
|
|
||||||
RUN pip install openwrt-luci-rpc asusrouter asyncio aiohttp graphene flask flask-cors tplink-omada-client wakeonlan pycryptodome requests paho-mqtt scapy cron-converter pytz json2table dhcp-leases pyunifi speedtest-cli chardet python-nmap dnspython librouteros yattag git+https://github.com/foreign-sub/aiofreepybox.git \
|
RUN pip install openwrt-luci-rpc asusrouter asyncio aiohttp graphene flask flask-cors unifi-sm-api tplink-omada-client wakeonlan pycryptodome requests paho-mqtt scapy cron-converter pytz json2table dhcp-leases pyunifi speedtest-cli chardet python-nmap dnspython librouteros yattag git+https://github.com/foreign-sub/aiofreepybox.git \
|
||||||
&& bash -c "find ${INSTALL_DIR} -type d -exec chmod 750 {} \;" \
|
&& bash -c "find ${INSTALL_DIR} -type d -exec chmod 750 {} \;" \
|
||||||
&& bash -c "find ${INSTALL_DIR} -type f -exec chmod 640 {} \;" \
|
&& bash -c "find ${INSTALL_DIR} -type f -exec chmod 640 {} \;" \
|
||||||
&& bash -c "find ${INSTALL_DIR} -type f \( -name '*.sh' -o -name '*.py' -o -name 'speedtest-cli' \) -exec chmod 750 {} \;"
|
&& bash -c "find ${INSTALL_DIR} -type f \( -name '*.sh' -o -name '*.py' -o -name 'speedtest-cli' \) -exec chmod 750 {} \;"
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ RUN phpenmod -v 8.2 sqlite3
|
|||||||
RUN apt-get install -y python3-venv
|
RUN apt-get install -y python3-venv
|
||||||
RUN python3 -m venv myenv
|
RUN python3 -m venv myenv
|
||||||
|
|
||||||
RUN /bin/bash -c "source myenv/bin/activate && update-alternatives --install /usr/bin/python python /usr/bin/python3 10 && pip3 install openwrt-luci-rpc asusrouter asyncio aiohttp graphene flask flask-cors tplink-omada-client wakeonlan pycryptodome requests paho-mqtt scapy cron-converter pytz json2table dhcp-leases pyunifi speedtest-cli chardet python-nmap dnspython librouteros yattag "
|
RUN /bin/bash -c "source myenv/bin/activate && update-alternatives --install /usr/bin/python python /usr/bin/python3 10 && pip3 install openwrt-luci-rpc asusrouter asyncio aiohttp graphene flask flask-cors unifi-sm-api tplink-omada-client wakeonlan pycryptodome requests paho-mqtt scapy cron-converter pytz json2table dhcp-leases pyunifi speedtest-cli chardet python-nmap dnspython librouteros yattag "
|
||||||
|
|
||||||
# Create a buildtimestamp.txt to later check if a new version was released
|
# Create a buildtimestamp.txt to later check if a new version was released
|
||||||
RUN date +%s > ${INSTALL_DIR}/front/buildtimestamp.txt
|
RUN date +%s > ${INSTALL_DIR}/front/buildtimestamp.txt
|
||||||
|
|||||||
34
docs/DEBUG_PHP.md
Executable file
34
docs/DEBUG_PHP.md
Executable file
@@ -0,0 +1,34 @@
|
|||||||
|
# Debugging backend PHP issues
|
||||||
|
|
||||||
|
## Logs in UI
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
You can view recent backend PHP errors directly in the **Maintenance > Logs** section of the UI. This provides quick access to logs without needing terminal access.
|
||||||
|
|
||||||
|
## Accessing logs directly
|
||||||
|
|
||||||
|
Sometimes, the UI might not be accessible. In that case, you can access the logs directly inside the container.
|
||||||
|
|
||||||
|
### Step-by-step:
|
||||||
|
|
||||||
|
1. **Open a shell into the container:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker exec -it netalertx /bin/sh
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Check the NGINX error log:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cat /var/log/nginx/error.log
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Check the PHP application error log:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cat /app/log/app.php_errors.log
|
||||||
|
```
|
||||||
|
|
||||||
|
These logs will help identify syntax issues, fatal errors, or startup problems when the UI fails to load properly.
|
||||||
|
|
||||||
114
docs/DEVICE_HEURISTICS.md
Executable file
114
docs/DEVICE_HEURISTICS.md
Executable file
@@ -0,0 +1,114 @@
|
|||||||
|
# Device Heuristics: Icon and Type Guessing
|
||||||
|
|
||||||
|
This module is responsible for inferring the most likely **device type** and **icon** based on minimal identifying data like MAC address, vendor, IP, or device name.
|
||||||
|
|
||||||
|
It does this using a set of heuristics defined in an external JSON rules file, which it evaluates **in priority order**.
|
||||||
|
|
||||||
|
>[!NOTE]
|
||||||
|
> You can find the full source code of the heuristics module in the `device_heuristics.py` file.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## JSON Rule Format
|
||||||
|
|
||||||
|
Rules are defined in a file called `device_heuristics_rules.json` (located under `/back`), structured like:
|
||||||
|
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"dev_type": "Phone",
|
||||||
|
"icon_html": "<i class=\"fa-brands fa-apple\"></i>",
|
||||||
|
"matching_pattern": [
|
||||||
|
{ "mac_prefix": "001A79", "vendor": "Apple" }
|
||||||
|
],
|
||||||
|
"name_pattern": ["iphone", "pixel"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
>[!NOTE]
|
||||||
|
> Feel free to raise a PR in case you'd like to add any rules into the `device_heuristics_rules.json` file. Please place new rules into the correct position and consider the priority of already available rules.
|
||||||
|
|
||||||
|
### Supported fields:
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
| ------------------ | -------------------- | --------------------------------------------------------------- |
|
||||||
|
| `dev_type` | `string` | Type to assign if rule matches (e.g. `"Gateway"`, `"Phone"`) |
|
||||||
|
| `icon_html` | `string` | Icon (HTML string) to assign if rule matches. Encoded to base64 at load time. |
|
||||||
|
| `matching_pattern` | `array` | List of `{ mac_prefix, vendor }` objects for first strict and then loose matching |
|
||||||
|
| `name_pattern` | `array` *(optional)* | List of lowercase substrings (used with regex) |
|
||||||
|
| `ip_pattern` | `array` *(optional)* | Regex patterns to match IPs |
|
||||||
|
|
||||||
|
**Order in this array defines priority** — rules are checked top-down and short-circuit on first match.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Matching Flow (in Priority Order)
|
||||||
|
|
||||||
|
The function `guess_device_attributes(...)` runs a series of matching functions in strict order:
|
||||||
|
|
||||||
|
1. MAC + Vendor → `match_mac_and_vendor()`
|
||||||
|
2. Vendor only → `match_vendor()`
|
||||||
|
3. Name pattern → `match_name()`
|
||||||
|
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.
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Still considered a match attempt if current values are defaults
|
||||||
|
if (not type_ or type_ == default_type) or (not icon or icon == default_icon):
|
||||||
|
type_, icon = match_ip(ip, default_type, default_icon)
|
||||||
|
```
|
||||||
|
|
||||||
|
In other words: if the type or icon is still `"unknown"` (or matches the default), the system assumes the match isn’t final — and keeps looking. It stops only when both values are non-default (defaults are defined in the `NEWDEV_devIcon` and `NEWDEV_devType` settings).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Match Behavior (per function)
|
||||||
|
|
||||||
|
These functions are executed in the following order:
|
||||||
|
|
||||||
|
### `match_mac_and_vendor(mac_clean, vendor, ...)`
|
||||||
|
|
||||||
|
* Looks for MAC prefix **and** vendor substring match
|
||||||
|
* Most precise
|
||||||
|
* Stops as soon as a match is found
|
||||||
|
|
||||||
|
### `match_vendor(vendor, ...)`
|
||||||
|
|
||||||
|
* Falls back to substring match on vendor only
|
||||||
|
* Ignores rules where `mac_prefix` is present (ensures this is really a fallback)
|
||||||
|
|
||||||
|
### `match_name(name, ...)`
|
||||||
|
|
||||||
|
* Lowercase name is compared against all `name_pattern` values using regex
|
||||||
|
* Good for user-assigned labels (e.g. "AP Office", "iPhone")
|
||||||
|
|
||||||
|
### `match_ip(ip, ...)`
|
||||||
|
|
||||||
|
* If IP is present and matches regex patterns under any rule, it returns that type/icon
|
||||||
|
* Usually used for gateways or local IP ranges
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Icons
|
||||||
|
|
||||||
|
* Each rule can define an `icon_html`, which is converted to a `icon_base64` on load
|
||||||
|
* If missing, it falls back to the passed-in `default_icon` (`NEWDEV_devIcon` setting)
|
||||||
|
* If a match is found but icon is still blank, default is used
|
||||||
|
|
||||||
|
**TL;DR:** Type and icon must both be matched. If only one is matched, the other falls back to the default.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Priority Mechanics
|
||||||
|
|
||||||
|
* JSON rules are evaluated **top-to-bottom**
|
||||||
|
* Matching is **first-hit wins** — no scoring, no weights
|
||||||
|
* Rules that are more specific (e.g. exact MAC prefixes) should be listed earlier
|
||||||
BIN
docs/img/DEBUG/maintenance_debug_php.png
Executable file
BIN
docs/img/DEBUG/maintenance_debug_php.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 160 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 7.0 KiB |
@@ -1,47 +1,4 @@
|
|||||||
{
|
{
|
||||||
"__inputs": [
|
|
||||||
{
|
|
||||||
"name": "DS_PROMETHEUS",
|
|
||||||
"label": "Prometheus",
|
|
||||||
"description": "",
|
|
||||||
"type": "datasource",
|
|
||||||
"pluginId": "prometheus",
|
|
||||||
"pluginName": "Prometheus"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"__elements": {},
|
|
||||||
"__requires": [
|
|
||||||
{
|
|
||||||
"type": "panel",
|
|
||||||
"id": "barchart",
|
|
||||||
"name": "Bar chart",
|
|
||||||
"version": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "grafana",
|
|
||||||
"id": "grafana",
|
|
||||||
"name": "Grafana",
|
|
||||||
"version": "12.0.0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "datasource",
|
|
||||||
"id": "prometheus",
|
|
||||||
"name": "Prometheus",
|
|
||||||
"version": "1.0.0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "panel",
|
|
||||||
"id": "stat",
|
|
||||||
"name": "Stat",
|
|
||||||
"version": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "panel",
|
|
||||||
"id": "table",
|
|
||||||
"name": "Table",
|
|
||||||
"version": ""
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"annotations": {
|
"annotations": {
|
||||||
"list": [
|
"list": [
|
||||||
{
|
{
|
||||||
@@ -61,14 +18,11 @@
|
|||||||
"editable": true,
|
"editable": true,
|
||||||
"fiscalYearStartMonth": 0,
|
"fiscalYearStartMonth": 0,
|
||||||
"graphTooltip": 0,
|
"graphTooltip": 0,
|
||||||
"id": null,
|
"id": 7,
|
||||||
"links": [],
|
"links": [],
|
||||||
"panels": [
|
"panels": [
|
||||||
{
|
{
|
||||||
"datasource": {
|
"datasource": "Prometheus",
|
||||||
"type": "prometheus",
|
|
||||||
"uid": "${DS_PROMETHEUS}"
|
|
||||||
},
|
|
||||||
"fieldConfig": {
|
"fieldConfig": {
|
||||||
"defaults": {
|
"defaults": {
|
||||||
"color": {
|
"color": {
|
||||||
@@ -77,8 +31,6 @@
|
|||||||
},
|
},
|
||||||
"decimals": 0,
|
"decimals": 0,
|
||||||
"mappings": [],
|
"mappings": [],
|
||||||
"max": 105,
|
|
||||||
"min": 0,
|
|
||||||
"thresholds": {
|
"thresholds": {
|
||||||
"mode": "absolute",
|
"mode": "absolute",
|
||||||
"steps": [
|
"steps": [
|
||||||
@@ -122,12 +74,8 @@
|
|||||||
"pluginVersion": "12.0.0",
|
"pluginVersion": "12.0.0",
|
||||||
"targets": [
|
"targets": [
|
||||||
{
|
{
|
||||||
"expr": "netalertx_total_devices",
|
"expr": "netalertx_connected_devices + netalertx_offline_devices",
|
||||||
"refId": "A",
|
"refId": "A"
|
||||||
"datasource": {
|
|
||||||
"type": "prometheus",
|
|
||||||
"uid": "${DS_PROMETHEUS}"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"title": "Total Devices",
|
"title": "Total Devices",
|
||||||
@@ -136,7 +84,7 @@
|
|||||||
{
|
{
|
||||||
"datasource": {
|
"datasource": {
|
||||||
"type": "prometheus",
|
"type": "prometheus",
|
||||||
"uid": "${DS_PROMETHEUS}"
|
"uid": "PBFA97CFB590B2093"
|
||||||
},
|
},
|
||||||
"fieldConfig": {
|
"fieldConfig": {
|
||||||
"defaults": {
|
"defaults": {
|
||||||
@@ -190,12 +138,12 @@
|
|||||||
"pluginVersion": "12.0.0",
|
"pluginVersion": "12.0.0",
|
||||||
"targets": [
|
"targets": [
|
||||||
{
|
{
|
||||||
"expr": "netalertx_connected_devices",
|
|
||||||
"refId": "A",
|
|
||||||
"datasource": {
|
"datasource": {
|
||||||
"type": "prometheus",
|
"type": "prometheus",
|
||||||
"uid": "${DS_PROMETHEUS}"
|
"uid": "PBFA97CFB590B2093"
|
||||||
}
|
},
|
||||||
|
"expr": "netalertx_connected_devices",
|
||||||
|
"refId": "A"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"title": "Connected",
|
"title": "Connected",
|
||||||
@@ -204,7 +152,7 @@
|
|||||||
{
|
{
|
||||||
"datasource": {
|
"datasource": {
|
||||||
"type": "prometheus",
|
"type": "prometheus",
|
||||||
"uid": "${DS_PROMETHEUS}"
|
"uid": "PBFA97CFB590B2093"
|
||||||
},
|
},
|
||||||
"fieldConfig": {
|
"fieldConfig": {
|
||||||
"defaults": {
|
"defaults": {
|
||||||
@@ -259,12 +207,12 @@
|
|||||||
"pluginVersion": "12.0.0",
|
"pluginVersion": "12.0.0",
|
||||||
"targets": [
|
"targets": [
|
||||||
{
|
{
|
||||||
"expr": "netalertx_favorite_devices",
|
|
||||||
"refId": "A",
|
|
||||||
"datasource": {
|
"datasource": {
|
||||||
"type": "prometheus",
|
"type": "prometheus",
|
||||||
"uid": "${DS_PROMETHEUS}"
|
"uid": "PBFA97CFB590B2093"
|
||||||
}
|
},
|
||||||
|
"expr": "netalertx_favorite_devices",
|
||||||
|
"refId": "A"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"title": "Favorites",
|
"title": "Favorites",
|
||||||
@@ -273,7 +221,7 @@
|
|||||||
{
|
{
|
||||||
"datasource": {
|
"datasource": {
|
||||||
"type": "prometheus",
|
"type": "prometheus",
|
||||||
"uid": "${DS_PROMETHEUS}"
|
"uid": "PBFA97CFB590B2093"
|
||||||
},
|
},
|
||||||
"fieldConfig": {
|
"fieldConfig": {
|
||||||
"defaults": {
|
"defaults": {
|
||||||
@@ -328,12 +276,12 @@
|
|||||||
"pluginVersion": "12.0.0",
|
"pluginVersion": "12.0.0",
|
||||||
"targets": [
|
"targets": [
|
||||||
{
|
{
|
||||||
"expr": "netalertx_new_devices",
|
|
||||||
"refId": "A",
|
|
||||||
"datasource": {
|
"datasource": {
|
||||||
"type": "prometheus",
|
"type": "prometheus",
|
||||||
"uid": "${DS_PROMETHEUS}"
|
"uid": "PBFA97CFB590B2093"
|
||||||
}
|
},
|
||||||
|
"expr": "netalertx_new_devices",
|
||||||
|
"refId": "A"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"title": "New Devices",
|
"title": "New Devices",
|
||||||
@@ -342,7 +290,7 @@
|
|||||||
{
|
{
|
||||||
"datasource": {
|
"datasource": {
|
||||||
"type": "prometheus",
|
"type": "prometheus",
|
||||||
"uid": "${DS_PROMETHEUS}"
|
"uid": "PBFA97CFB590B2093"
|
||||||
},
|
},
|
||||||
"fieldConfig": {
|
"fieldConfig": {
|
||||||
"defaults": {
|
"defaults": {
|
||||||
@@ -397,12 +345,12 @@
|
|||||||
"pluginVersion": "12.0.0",
|
"pluginVersion": "12.0.0",
|
||||||
"targets": [
|
"targets": [
|
||||||
{
|
{
|
||||||
"expr": "netalertx_down_devices",
|
|
||||||
"refId": "A",
|
|
||||||
"datasource": {
|
"datasource": {
|
||||||
"type": "prometheus",
|
"type": "prometheus",
|
||||||
"uid": "${DS_PROMETHEUS}"
|
"uid": "PBFA97CFB590B2093"
|
||||||
}
|
},
|
||||||
|
"expr": "netalertx_down_devices",
|
||||||
|
"refId": "A"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"title": "Down",
|
"title": "Down",
|
||||||
@@ -411,7 +359,7 @@
|
|||||||
{
|
{
|
||||||
"datasource": {
|
"datasource": {
|
||||||
"type": "prometheus",
|
"type": "prometheus",
|
||||||
"uid": "${DS_PROMETHEUS}"
|
"uid": "PBFA97CFB590B2093"
|
||||||
},
|
},
|
||||||
"fieldConfig": {
|
"fieldConfig": {
|
||||||
"defaults": {
|
"defaults": {
|
||||||
@@ -466,12 +414,12 @@
|
|||||||
"pluginVersion": "12.0.0",
|
"pluginVersion": "12.0.0",
|
||||||
"targets": [
|
"targets": [
|
||||||
{
|
{
|
||||||
"expr": "netalertx_archived_devices",
|
|
||||||
"refId": "A",
|
|
||||||
"datasource": {
|
"datasource": {
|
||||||
"type": "prometheus",
|
"type": "prometheus",
|
||||||
"uid": "${DS_PROMETHEUS}"
|
"uid": "PBFA97CFB590B2093"
|
||||||
}
|
},
|
||||||
|
"expr": "netalertx_archived_devices",
|
||||||
|
"refId": "A"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"title": "Archived",
|
"title": "Archived",
|
||||||
@@ -480,7 +428,7 @@
|
|||||||
{
|
{
|
||||||
"datasource": {
|
"datasource": {
|
||||||
"type": "prometheus",
|
"type": "prometheus",
|
||||||
"uid": "${DS_PROMETHEUS}"
|
"uid": "PBFA97CFB590B2093"
|
||||||
},
|
},
|
||||||
"fieldConfig": {
|
"fieldConfig": {
|
||||||
"defaults": {
|
"defaults": {
|
||||||
@@ -605,31 +553,31 @@
|
|||||||
"pluginVersion": "12.0.0",
|
"pluginVersion": "12.0.0",
|
||||||
"targets": [
|
"targets": [
|
||||||
{
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "PBFA97CFB590B2093"
|
||||||
|
},
|
||||||
"expr": "netalertx_connected_devices",
|
"expr": "netalertx_connected_devices",
|
||||||
"legendFormat": "Connected",
|
"legendFormat": "Connected",
|
||||||
"refId": "A",
|
"refId": "A"
|
||||||
"datasource": {
|
|
||||||
"type": "prometheus",
|
|
||||||
"uid": "${DS_PROMETHEUS}"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "PBFA97CFB590B2093"
|
||||||
|
},
|
||||||
"expr": "netalertx_total_devices - (netalertx_connected_devices + netalertx_down_devices)",
|
"expr": "netalertx_total_devices - (netalertx_connected_devices + netalertx_down_devices)",
|
||||||
"legendFormat": "Offline",
|
"legendFormat": "Offline",
|
||||||
"refId": "B",
|
"refId": "B"
|
||||||
"datasource": {
|
|
||||||
"type": "prometheus",
|
|
||||||
"uid": "${DS_PROMETHEUS}"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"expr": "netalertx_down_devices",
|
|
||||||
"legendFormat": "Down Devices",
|
|
||||||
"refId": "C",
|
|
||||||
"datasource": {
|
"datasource": {
|
||||||
"type": "prometheus",
|
"type": "prometheus",
|
||||||
"uid": "${DS_PROMETHEUS}"
|
"uid": "PBFA97CFB590B2093"
|
||||||
}
|
},
|
||||||
|
"expr": "netalertx_down_devices",
|
||||||
|
"legendFormat": "Down Devices",
|
||||||
|
"refId": "C"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"title": "Device Presence",
|
"title": "Device Presence",
|
||||||
@@ -638,7 +586,7 @@
|
|||||||
{
|
{
|
||||||
"datasource": {
|
"datasource": {
|
||||||
"type": "prometheus",
|
"type": "prometheus",
|
||||||
"uid": "${DS_PROMETHEUS}"
|
"uid": "PBFA97CFB590B2093"
|
||||||
},
|
},
|
||||||
"description": "Connected (Online) Devices",
|
"description": "Connected (Online) Devices",
|
||||||
"fieldConfig": {
|
"fieldConfig": {
|
||||||
@@ -826,15 +774,15 @@
|
|||||||
"pluginVersion": "12.0.0",
|
"pluginVersion": "12.0.0",
|
||||||
"targets": [
|
"targets": [
|
||||||
{
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "PBFA97CFB590B2093"
|
||||||
|
},
|
||||||
"editorMode": "code",
|
"editorMode": "code",
|
||||||
"expr": "netalertx_device_status{device_status=\"Online\"}",
|
"expr": "netalertx_device_status{device_status=\"Online\"}",
|
||||||
"format": "table",
|
"format": "table",
|
||||||
"range": true,
|
"range": true,
|
||||||
"refId": "A",
|
"refId": "A"
|
||||||
"datasource": {
|
|
||||||
"type": "prometheus",
|
|
||||||
"uid": "${DS_PROMETHEUS}"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"title": "Connected Devices",
|
"title": "Connected Devices",
|
||||||
@@ -892,7 +840,7 @@
|
|||||||
{
|
{
|
||||||
"datasource": {
|
"datasource": {
|
||||||
"type": "prometheus",
|
"type": "prometheus",
|
||||||
"uid": "${DS_PROMETHEUS}"
|
"uid": "PBFA97CFB590B2093"
|
||||||
},
|
},
|
||||||
"description": "Disconnected(Offline) Devices",
|
"description": "Disconnected(Offline) Devices",
|
||||||
"fieldConfig": {
|
"fieldConfig": {
|
||||||
@@ -1079,15 +1027,15 @@
|
|||||||
"pluginVersion": "12.0.0",
|
"pluginVersion": "12.0.0",
|
||||||
"targets": [
|
"targets": [
|
||||||
{
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "PBFA97CFB590B2093"
|
||||||
|
},
|
||||||
"editorMode": "code",
|
"editorMode": "code",
|
||||||
"expr": "netalertx_device_status{device_status=\"Offline\"}",
|
"expr": "netalertx_device_status{device_status=\"Offline\"}",
|
||||||
"format": "table",
|
"format": "table",
|
||||||
"range": true,
|
"range": true,
|
||||||
"refId": "A",
|
"refId": "A"
|
||||||
"datasource": {
|
|
||||||
"type": "prometheus",
|
|
||||||
"uid": "${DS_PROMETHEUS}"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"title": "Disconnected Devices",
|
"title": "Disconnected Devices",
|
||||||
@@ -1143,6 +1091,7 @@
|
|||||||
"type": "table"
|
"type": "table"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"preload": false,
|
||||||
"refresh": "30s",
|
"refresh": "30s",
|
||||||
"schemaVersion": 41,
|
"schemaVersion": 41,
|
||||||
"tags": [],
|
"tags": [],
|
||||||
@@ -1156,7 +1105,6 @@
|
|||||||
"timepicker": {},
|
"timepicker": {},
|
||||||
"timezone": "browser",
|
"timezone": "browser",
|
||||||
"title": "NetAlertX Overview",
|
"title": "NetAlertX Overview",
|
||||||
"uid": "netalertx-overview_7_26_2025",
|
"uid": "netalertx-overview_8_4_2025",
|
||||||
"version": 7,
|
"version": 2
|
||||||
"weekStart": ""
|
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
require 'php/templates/header.php';
|
require 'php/templates/header.php';
|
||||||
require 'php/templates/notification.php';
|
require 'php/templates/modals.php';
|
||||||
?>
|
?>
|
||||||
<!-- ----------------------------------------------------------------------- -->
|
<!-- ----------------------------------------------------------------------- -->
|
||||||
|
|
||||||
|
|||||||
@@ -387,6 +387,16 @@ body
|
|||||||
margin-bottom: 0px;
|
margin-bottom: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.plugin-content #tabs-location .nav-tabs-custom > .nav-tabs > li
|
||||||
|
{
|
||||||
|
display: contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
.plugin-content .left-nav
|
||||||
|
{
|
||||||
|
display: contents;
|
||||||
|
}
|
||||||
|
|
||||||
.pa-small-box-2 .inner h3 {
|
.pa-small-box-2 .inner h3 {
|
||||||
margin-left: 0em;
|
margin-left: 0em;
|
||||||
margin-bottom: 1.3em;
|
margin-bottom: 1.3em;
|
||||||
@@ -1411,6 +1421,7 @@ input[readonly] {
|
|||||||
.iconPreview svg{
|
.iconPreview svg{
|
||||||
min-width: 20px;
|
min-width: 20px;
|
||||||
max-width: 20px;
|
max-width: 20px;
|
||||||
|
margin-bottom: -3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1489,7 +1500,7 @@ input[readonly] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#tableDevicesBox td svg, #tableDevicesBox td i{
|
#tableDevicesBox td svg, #tableDevicesBox td i{
|
||||||
height: 1.5em !important;
|
height: 1em !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
#TileCards .tile .inner
|
#TileCards .tile .inner
|
||||||
@@ -1649,6 +1660,21 @@ input[readonly] {
|
|||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.custom-badge a
|
||||||
|
{
|
||||||
|
color: #fff !important;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.custom-badge
|
||||||
|
{
|
||||||
|
border: 1px solid #aaa;
|
||||||
|
border-radius: 4px;
|
||||||
|
border-style: solid;
|
||||||
|
padding: 0 5px;
|
||||||
|
font-size: 14px;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
#deviceDetailsEdit .form-control
|
#deviceDetailsEdit .form-control
|
||||||
{
|
{
|
||||||
min-height: 42px;
|
min-height: 42px;
|
||||||
@@ -1700,6 +1726,16 @@ input[readonly] {
|
|||||||
width: 92%;
|
width: 92%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#modal-ok
|
||||||
|
{
|
||||||
|
z-index: 1051; /*highest priority*/
|
||||||
|
}
|
||||||
|
|
||||||
|
#modal-form-plc
|
||||||
|
{
|
||||||
|
display: grid;
|
||||||
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------- */
|
/* ----------------------------------------------------------------- */
|
||||||
/* NETWORK page */
|
/* NETWORK page */
|
||||||
/* ----------------------------------------------------------------- */
|
/* ----------------------------------------------------------------- */
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
--color-yellow: #f39c12;
|
--color-yellow: #f39c12;
|
||||||
--color-red: #dd4b39;
|
--color-red: #dd4b39;
|
||||||
--color-gray: #8c8c8c;
|
--color-gray: #8c8c8c;
|
||||||
|
--color-white: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
@@ -793,5 +794,5 @@
|
|||||||
|
|
||||||
.btn:hover
|
.btn:hover
|
||||||
{
|
{
|
||||||
color: var(--color-gray);
|
color: var(--color-white);
|
||||||
}
|
}
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
<!-- Content header--------------------------------------------------------- -->
|
<!-- Content header--------------------------------------------------------- -->
|
||||||
<section class="content-header">
|
<section class="content-header">
|
||||||
<?php require 'php/templates/notification.php'; ?>
|
<?php require 'php/templates/modals.php'; ?>
|
||||||
|
|
||||||
<h1 id="pageTitle">
|
<h1 id="pageTitle">
|
||||||
 <small>Quering device info...</small>
|
 <small>Quering device info...</small>
|
||||||
|
|||||||
@@ -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
|
// Save device data to DB
|
||||||
function setDeviceData(direction = '', refreshCallback = '') {
|
function setDeviceData(direction = '', refreshCallback = '') {
|
||||||
|
|||||||
@@ -503,36 +503,36 @@ function collectFilters() {
|
|||||||
function mapColumnIndexToFieldName(index, tableColumnVisible) {
|
function mapColumnIndexToFieldName(index, tableColumnVisible) {
|
||||||
// the order is important, don't change it!
|
// the order is important, don't change it!
|
||||||
const columnNames = [
|
const columnNames = [
|
||||||
"devName",
|
"devName", // 0
|
||||||
"devOwner",
|
"devOwner", // 1
|
||||||
"devType",
|
"devType", // 2
|
||||||
"devIcon",
|
"devIcon", // 3
|
||||||
"devFavorite",
|
"devFavorite", // 4
|
||||||
"devGroup",
|
"devGroup", // 5
|
||||||
"devFirstConnection",
|
"devFirstConnection", // 6
|
||||||
"devLastConnection",
|
"devLastConnection", // 7
|
||||||
"devLastIP",
|
"devLastIP", // 8
|
||||||
"devIsRandomMac", // resolved on the fly
|
"devIsRandomMac", // 9 resolved on the fly
|
||||||
"devStatus", // resolved on the fly
|
"devStatus", // 10 resolved on the fly
|
||||||
"devMac",
|
"devMac", // 11
|
||||||
"devIpLong", //formatIPlong(device.devLastIP) || "", // IP orderable
|
"devIpLong", // 12 formatIPlong(device.devLastIP) || "", // IP orderable
|
||||||
"rowid",
|
"rowid", // 13
|
||||||
"devParentMAC",
|
"devParentMAC", // 14
|
||||||
"devParentChildrenCount", // resolved on the fly
|
"devParentChildrenCount", // 15 resolved on the fly
|
||||||
"devLocation",
|
"devLocation", // 16
|
||||||
"devVendor",
|
"devVendor", // 17
|
||||||
"devParentPort",
|
"devParentPort", // 18
|
||||||
"devGUID",
|
"devGUID", // 19
|
||||||
"devSyncHubNode",
|
"devSyncHubNode", // 20
|
||||||
"devSite",
|
"devSite", // 21
|
||||||
"devSSID",
|
"devSSID", // 22
|
||||||
"devSourcePlugin",
|
"devSourcePlugin", // 23
|
||||||
"devPresentLastScan",
|
"devPresentLastScan", // 24
|
||||||
"devAlertDown",
|
"devAlertDown", // 25
|
||||||
"devCustomProps",
|
"devCustomProps", // 26
|
||||||
"devFQDN",
|
"devFQDN", // 27
|
||||||
"devParentRelType",
|
"devParentRelType", // 28
|
||||||
"devReqNicsOnline"
|
"devReqNicsOnline" // 29
|
||||||
];
|
];
|
||||||
|
|
||||||
// console.log("OrderBy: " + columnNames[tableColumnOrder[index]]);
|
// console.log("OrderBy: " + columnNames[tableColumnOrder[index]]);
|
||||||
@@ -899,6 +899,28 @@ function initializeDatatable (status) {
|
|||||||
}
|
}
|
||||||
} },
|
} },
|
||||||
|
|
||||||
|
// Parent Mac
|
||||||
|
{targets: [mapIndx(14)],
|
||||||
|
'createdCell': function (td, cellData, rowData, row, col) {
|
||||||
|
if (!isValidMac(cellData)) {
|
||||||
|
$(td).html('');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
id: cellData, // MAC address
|
||||||
|
text: cellData // Optional display text (you could use a name or something else)
|
||||||
|
};
|
||||||
|
|
||||||
|
spanWrap = $(`<span class="custom-badge text-white"></span>`)
|
||||||
|
|
||||||
|
$(td).html(spanWrap);
|
||||||
|
|
||||||
|
const chipHtml = renderDeviceLink(data, spanWrap, true); // pass the td as container
|
||||||
|
|
||||||
|
$(spanWrap).append(chipHtml);
|
||||||
|
}
|
||||||
|
},
|
||||||
// Status color
|
// Status color
|
||||||
{targets: [mapIndx(10)],
|
{targets: [mapIndx(10)],
|
||||||
'createdCell': function (td, cellData, rowData, row, col) {
|
'createdCell': function (td, cellData, rowData, row, col) {
|
||||||
@@ -983,8 +1005,6 @@ function initializeDatatable (status) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"display": "standalone",
|
"display": "standalone",
|
||||||
"icons": [
|
"icons": [
|
||||||
{
|
{
|
||||||
"src": "",
|
"src": "/img/NetAlertX_logo.png",
|
||||||
"sizes": "180x180",
|
"sizes": "180x180",
|
||||||
"type": "image/png"
|
"type": "image/png"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
return "Unknown"; // Return a default value if MAC address is not found
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -161,6 +161,91 @@ function showModalFieldInput(
|
|||||||
$(`#${prefix}`).modal("show");
|
$(`#${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() {
|
function modalDefaultOK() {
|
||||||
// Hide modal
|
// Hide modal
|
||||||
|
|||||||
@@ -67,6 +67,15 @@ function getPluginConfig(pluginsData, prefix) {
|
|||||||
return result;
|
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
|
// Generate plugin HTML card based on prefixes in an array
|
||||||
function pluginCards(prefixesOfEnabledPlugins, includeSettings) {
|
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
|
// Add item to list
|
||||||
function addList(element, clearInput = true) {
|
function addList(element, clearInput = true) {
|
||||||
@@ -622,8 +670,6 @@ function generateOptionsOrSetOptions(
|
|||||||
// obj.push({ id: item, name: item })
|
// obj.push({ id: item, name: item })
|
||||||
options = arrayToObject(createArray(overrideOptions ? overrideOptions : getSettingOptions(setKey)))
|
options = arrayToObject(createArray(overrideOptions ? overrideOptions : getSettingOptions(setKey)))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Call to render lists
|
// Call to render lists
|
||||||
renderList(
|
renderList(
|
||||||
options,
|
options,
|
||||||
@@ -633,8 +679,6 @@ function generateOptionsOrSetOptions(
|
|||||||
targetField,
|
targetField,
|
||||||
transformers
|
transformers
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -655,6 +699,13 @@ function applyTransformers(val, transformers) {
|
|||||||
val = btoa(val);
|
val = btoa(val);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case "name|base64":
|
||||||
|
// // Implement base64 logic
|
||||||
|
// if (!isBase64(val)) {
|
||||||
|
// val = btoa(val);
|
||||||
|
// }
|
||||||
|
val = val; // probably TODO ⚠
|
||||||
|
break;
|
||||||
case "getString":
|
case "getString":
|
||||||
// no change
|
// no change
|
||||||
val = val;
|
val = val;
|
||||||
@@ -681,6 +732,13 @@ function reverseTransformers(val, transformers) {
|
|||||||
val = atob(val);
|
val = atob(val);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case "name|base64":
|
||||||
|
// // Implement base64 decoding logic
|
||||||
|
// if (isBase64(val)) {
|
||||||
|
// val = atob(val);
|
||||||
|
// }
|
||||||
|
val = val; // probably TODO ⚠
|
||||||
|
break;
|
||||||
case "getString":
|
case "getString":
|
||||||
// retrieve string
|
// retrieve string
|
||||||
val = getString(val);
|
val = getString(val);
|
||||||
@@ -721,7 +779,7 @@ const handleElementOptions = (setKey, elementOptions, transformers, val) => {
|
|||||||
let customId = "";
|
let customId = "";
|
||||||
let columns = [];
|
let columns = [];
|
||||||
let base64Regex = "";
|
let base64Regex = "";
|
||||||
|
let elementOptionsBase64 = btoa(JSON.stringify(elementOptions));
|
||||||
|
|
||||||
elementOptions.forEach((option) => {
|
elementOptions.forEach((option) => {
|
||||||
if (option.prefillValue) {
|
if (option.prefillValue) {
|
||||||
@@ -804,7 +862,8 @@ const handleElementOptions = (setKey, elementOptions, transformers, val) => {
|
|||||||
customParams,
|
customParams,
|
||||||
customId,
|
customId,
|
||||||
columns,
|
columns,
|
||||||
base64Regex
|
base64Regex,
|
||||||
|
elementOptionsBase64
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -955,6 +1014,8 @@ function generateFormHtml(settingsData, set, overrideValue, overrideOptions, ori
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
// Parse the setType JSON string
|
// Parse the setType JSON string
|
||||||
|
console.log(processQuotes(setType));
|
||||||
|
|
||||||
const setTypeObject = JSON.parse(processQuotes(setType))
|
const setTypeObject = JSON.parse(processQuotes(setType))
|
||||||
const dataType = setTypeObject.dataType;
|
const dataType = setTypeObject.dataType;
|
||||||
const elements = setTypeObject.elements || [];
|
const elements = setTypeObject.elements || [];
|
||||||
@@ -982,7 +1043,8 @@ function generateFormHtml(settingsData, set, overrideValue, overrideOptions, ori
|
|||||||
customParams,
|
customParams,
|
||||||
customId,
|
customId,
|
||||||
columns,
|
columns,
|
||||||
base64Regex
|
base64Regex,
|
||||||
|
elementOptionsBase64
|
||||||
} = handleElementOptions(setKey, elementOptions, transformers, inVal);
|
} = handleElementOptions(setKey, elementOptions, transformers, inVal);
|
||||||
|
|
||||||
// Override value
|
// Override value
|
||||||
@@ -1051,6 +1113,7 @@ function generateFormHtml(settingsData, set, overrideValue, overrideOptions, ori
|
|||||||
my-originalSetKey="${originalSetKey}"
|
my-originalSetKey="${originalSetKey}"
|
||||||
my-input-from="${sourceIds}"
|
my-input-from="${sourceIds}"
|
||||||
my-input-to="${setKey}"
|
my-input-to="${setKey}"
|
||||||
|
data-elementoptionsbase64="${elementOptionsBase64}"
|
||||||
onclick="${onClick}">
|
onclick="${onClick}">
|
||||||
${getString(getStringKey)}
|
${getString(getStringKey)}
|
||||||
</button>`;
|
</button>`;
|
||||||
|
|||||||
@@ -715,45 +715,7 @@ function initSelect2() {
|
|||||||
{
|
{
|
||||||
var selectEl = $(this).select2({
|
var selectEl = $(this).select2({
|
||||||
templateSelection: function (data, container) {
|
templateSelection: function (data, container) {
|
||||||
if (!data.id) return data.text; // default for placeholder etc.
|
return $(renderDeviceLink(data, container));
|
||||||
|
|
||||||
const device = getDevDataByMac(data.id);
|
|
||||||
|
|
||||||
const badge = getStatusBadgeParts(
|
|
||||||
device.devPresentLastScan,
|
|
||||||
device.devAlertDown,
|
|
||||||
device.devMac
|
|
||||||
)
|
|
||||||
|
|
||||||
$(container).addClass(badge.cssClass);
|
|
||||||
|
|
||||||
// Custom HTML
|
|
||||||
const html = $(`
|
|
||||||
<a href="${badge.url}" target="_blank">
|
|
||||||
<span class="custom-chip hover-node-info"
|
|
||||||
data-name="${device.devName}"
|
|
||||||
data-ip="${device.devLastIP}"
|
|
||||||
data-mac="${device.devMac}"
|
|
||||||
data-vendor="${device.devVendor}"
|
|
||||||
data-type="${device.devType}"
|
|
||||||
data-lastseen="${device.devLastConnection}"
|
|
||||||
data-firstseen="${device.devFirstConnection}"
|
|
||||||
data-relationship="${device.devParentRelType}"
|
|
||||||
data-status="${device.devStatus}"
|
|
||||||
data-present="${device.devPresentLastScan}"
|
|
||||||
data-alert="${device.devAlertDown}"
|
|
||||||
data-icon="${device.devIcon}"
|
|
||||||
>
|
|
||||||
<span class="iconPreview">${atob(device.devIcon)}</span>
|
|
||||||
${data.text}
|
|
||||||
<span>
|
|
||||||
(${badge.iconHtml})
|
|
||||||
</span
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
`);
|
|
||||||
|
|
||||||
return html;
|
|
||||||
},
|
},
|
||||||
escapeMarkup: function (m) {
|
escapeMarkup: function (m) {
|
||||||
return m; // Allow HTML
|
return m; // Allow HTML
|
||||||
@@ -817,6 +779,50 @@ function initSelect2() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// Render a device link with hover-over functionality
|
||||||
|
function renderDeviceLink(data, container, useName = false) {
|
||||||
|
if (!data.id || !isValidMac(data.id)) return data.text; // default placeholder etc.
|
||||||
|
|
||||||
|
const device = getDevDataByMac(data.id);
|
||||||
|
|
||||||
|
const badge = getStatusBadgeParts(
|
||||||
|
device.devPresentLastScan,
|
||||||
|
device.devAlertDown,
|
||||||
|
device.devMac
|
||||||
|
);
|
||||||
|
|
||||||
|
// badge class and hover-info class to container
|
||||||
|
$(container)
|
||||||
|
.addClass(`${badge.cssClass} hover-node-info`)
|
||||||
|
.attr({
|
||||||
|
'data-name': device.devName,
|
||||||
|
'data-ip': device.devLastIP,
|
||||||
|
'data-mac': device.devMac,
|
||||||
|
'data-vendor': device.devVendor,
|
||||||
|
'data-type': device.devType,
|
||||||
|
'data-lastseen': device.devLastConnection,
|
||||||
|
'data-firstseen': device.devFirstConnection,
|
||||||
|
'data-relationship': device.devParentRelType,
|
||||||
|
'data-status': device.devStatus,
|
||||||
|
'data-present': device.devPresentLastScan,
|
||||||
|
'data-alert': device.devAlertDown,
|
||||||
|
'data-icon': device.devIcon
|
||||||
|
});
|
||||||
|
|
||||||
|
return `
|
||||||
|
<a href="${badge.url}" target="_blank">
|
||||||
|
<span class="custom-chip">
|
||||||
|
<span class="iconPreview">${atob(device.devIcon)}</span>
|
||||||
|
${useName ? device.devName : data.text}
|
||||||
|
<span>
|
||||||
|
(${badge.iconHtml})
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------------------------
|
// ------------------------------------------
|
||||||
// Display device info on hover (attach only once)
|
// Display device info on hover (attach only once)
|
||||||
function initHoverNodeInfo() {
|
function initHoverNodeInfo() {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
require 'php/templates/header.php';
|
require 'php/templates/header.php';
|
||||||
require 'php/templates/notification.php';
|
require 'php/templates/modals.php';
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<!-- Page ------------------------------------------------------------------ -->
|
<!-- Page ------------------------------------------------------------------ -->
|
||||||
@@ -185,6 +185,12 @@ $db->close();
|
|||||||
</div>
|
</div>
|
||||||
<div class="db_tools_table_cell_b"><?= lang('Maintenance_Tool_del_ActHistory_text');?></div>
|
<div class="db_tools_table_cell_b"><?= lang('Maintenance_Tool_del_ActHistory_text');?></div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="db_info_table_row">
|
||||||
|
<div class="db_tools_table_cell_a" >
|
||||||
|
<button type="button" class="btn btn-default pa-btn pa-btn-delete bg-red dbtools-button" id="btnRestartServer" onclick="askRestartBackend()"><?= lang('Maint_RestartServer');?></button>
|
||||||
|
</div>
|
||||||
|
<div class="db_tools_table_cell_b"><?= lang('Maint_Restart_Server_noti_text');?></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -136,7 +136,8 @@
|
|||||||
customParams,
|
customParams,
|
||||||
customId,
|
customId,
|
||||||
columns,
|
columns,
|
||||||
base64Regex
|
base64Regex,
|
||||||
|
elementOptionsBase64
|
||||||
} = handleElementOptions('none', elementOptions, transformers, val = "");
|
} = handleElementOptions('none', elementOptions, transformers, val = "");
|
||||||
|
|
||||||
// render based on element type
|
// render based on element type
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
require 'php/templates/header.php';
|
require 'php/templates/header.php';
|
||||||
require 'php/templates/notification.php';
|
require 'php/templates/modals.php';
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
@@ -436,8 +436,24 @@
|
|||||||
</li>
|
</li>
|
||||||
|
|
||||||
<!-- system info menu item -->
|
<!-- system info menu item -->
|
||||||
<li class=" <?php if (in_array (basename($_SERVER['SCRIPT_NAME']), array('systeminfo.php') ) ){ echo 'active'; } ?>">
|
<li class=" treeview <?php if (in_array (basename($_SERVER['SCRIPT_NAME']), array('systeminfo.php') ) ){ echo 'active menu-open'; } ?>">
|
||||||
<a href="systeminfo.php"><i class="fa fa-fw fa-info-circle"></i> <span><?= lang('Navigation_SystemInfo');?></span></a>
|
<a href="#">
|
||||||
|
<i class="fa fa-fw fa-info-circle"></i> <span><?= lang('Navigation_SystemInfo');?></span>
|
||||||
|
<span class="pull-right-container">
|
||||||
|
<i class="fa fa-angle-left pull-right"></i>
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
<ul class="treeview-menu " style="display: <?php if (in_array (basename($_SERVER['SCRIPT_NAME']), array('systeminfo.php') ) ){ echo 'block'; } else {echo 'none';} ?>;">
|
||||||
|
<li>
|
||||||
|
<a href="systeminfo.php#panServer" onclick="setCache('activeSysinfoTab','tabServer');initializeTabs()"><?= lang('Systeminfo_System');?></a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="systeminfo.php#panNetwork" onclick="setCache('activeSysinfoTab','tabNetwork');initializeTabs()"><?= lang('Systeminfo_Network');?></a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="systeminfo.php#panStorage" onclick="setCache('activeSysinfoTab','tabStorage');initializeTabs()"><?= lang('Systeminfo_Storage');?></a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
@@ -450,24 +466,6 @@
|
|||||||
|
|
||||||
<script defer>
|
<script defer>
|
||||||
|
|
||||||
// Generate work-in-progress icons
|
|
||||||
function workInProgress() {
|
|
||||||
|
|
||||||
if($(".work-in-progress").length > 0 && $(".work-in-progress").html().trim() == "")
|
|
||||||
{
|
|
||||||
$(".work-in-progress").append(`
|
|
||||||
<a href="https://github.com/jokob-sk/NetAlertX/issues" target="_blank">
|
|
||||||
<b class="pointer" title="${getString("Gen_Work_In_Progress")}">🦺</b>
|
|
||||||
</a>
|
|
||||||
`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------
|
|
||||||
|
|
||||||
function toggleFullscreen() {
|
function toggleFullscreen() {
|
||||||
|
|
||||||
if (document.fullscreenElement) {
|
if (document.fullscreenElement) {
|
||||||
@@ -485,6 +483,5 @@ function workInProgress() {
|
|||||||
|
|
||||||
// Update server state in the header
|
// Update server state in the header
|
||||||
updateState()
|
updateState()
|
||||||
workInProgress()
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
0
front/php/templates/language/fr_fr.json
Normal file → Executable file
0
front/php/templates/language/fr_fr.json
Normal file → Executable file
@@ -301,7 +301,7 @@
|
|||||||
"Gen_Cancel": "Annulla",
|
"Gen_Cancel": "Annulla",
|
||||||
"Gen_Change": "Modifica",
|
"Gen_Change": "Modifica",
|
||||||
"Gen_Copy": "Esegui",
|
"Gen_Copy": "Esegui",
|
||||||
"Gen_CopyToClipboard": "",
|
"Gen_CopyToClipboard": "Copia negli appunti",
|
||||||
"Gen_DataUpdatedUITakesTime": "OK: l'aggiornamento dell'interfaccia utente potrebbe richiedere del tempo se è in esecuzione una scansione.",
|
"Gen_DataUpdatedUITakesTime": "OK: l'aggiornamento dell'interfaccia utente potrebbe richiedere del tempo se è in esecuzione una scansione.",
|
||||||
"Gen_Delete": "Elimina",
|
"Gen_Delete": "Elimina",
|
||||||
"Gen_DeleteAll": "Elimina tutti",
|
"Gen_DeleteAll": "Elimina tutti",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
require 'php/templates/notification.php';
|
require 'php/templates/modals.php';
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// check if authenticated
|
// check if authenticated
|
||||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/php/templates/security.php';
|
require_once $_SERVER['DOCUMENT_ROOT'] . '/php/templates/security.php';
|
||||||
|
|||||||
@@ -117,6 +117,29 @@
|
|||||||
</div>
|
</div>
|
||||||
</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">×</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 -->
|
<!-- Modal field input -->
|
||||||
<div class="modal modal-warning fade" id="modal-field-input" data-myparam-triggered-by="" style="display: none;">
|
<div class="modal modal-warning fade" id="modal-field-input" data-myparam-triggered-by="" style="display: none;">
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
require 'php/templates/header.php';
|
require 'php/templates/header.php';
|
||||||
require 'php/templates/notification.php';
|
require 'php/templates/modals.php';
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<!-- Page ------------------------------------------------------------------ -->
|
<!-- Page ------------------------------------------------------------------ -->
|
||||||
|
|||||||
26
front/plugins/unifi_api_import/README.md
Executable file
26
front/plugins/unifi_api_import/README.md
Executable file
@@ -0,0 +1,26 @@
|
|||||||
|
## Overview
|
||||||
|
|
||||||
|
Unifi import plugin using the Site Manager API.
|
||||||
|
|
||||||
|
> [!TIP]
|
||||||
|
> The Site Manager API doesn't seems to have feature parity with the old API yet, so certain limitations apply.
|
||||||
|
|
||||||
|
### Quick setup guide
|
||||||
|
|
||||||
|
Navigate to your UniFi Site Manager _⚙️ Settings -> Control Plane -> Integrations_.
|
||||||
|
|
||||||
|
- `api_key` : You can generate your API key under the _Your API Keys_ section.
|
||||||
|
- `base_url` : You can find your base url in the _API Request Format_ section, e.g. `https://192.168.100.1/proxy/network/integration/`
|
||||||
|
- `version` : You can find your version as part of the url in the _API Request Format_ section, e.g. `v1`
|
||||||
|
- `skip_ssl` : To skip SSL with you don't have an SSL certificate
|
||||||
|
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
- Head to **Settings** > **Plugin name** to adjust the default values.
|
||||||
|
|
||||||
|
### Notes
|
||||||
|
|
||||||
|
- Version: 1.0.0
|
||||||
|
- Author: `jokob-sk`
|
||||||
|
- Release Date: `Aug 2025`
|
||||||
743
front/plugins/unifi_api_import/config.json
Executable file
743
front/plugins/unifi_api_import/config.json
Executable file
@@ -0,0 +1,743 @@
|
|||||||
|
{
|
||||||
|
"code_name": "unifi_api_import",
|
||||||
|
"unique_prefix": "UNIFIAPI",
|
||||||
|
"plugin_type": "device_scanner",
|
||||||
|
"execution_order": "Layer_0",
|
||||||
|
"enabled": true,
|
||||||
|
"data_source": "script",
|
||||||
|
"mapped_to_table": "CurrentScan",
|
||||||
|
"data_filters": [
|
||||||
|
{
|
||||||
|
"compare_column": "Object_PrimaryID",
|
||||||
|
"compare_operator": "==",
|
||||||
|
"compare_field_id": "txtMacFilter",
|
||||||
|
"compare_js_template": "'{value}'.toString()",
|
||||||
|
"compare_use_quotes": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"show_ui": true,
|
||||||
|
"localized": [
|
||||||
|
"display_name",
|
||||||
|
"description",
|
||||||
|
"icon"
|
||||||
|
],
|
||||||
|
"display_name": [
|
||||||
|
{
|
||||||
|
"language_code": "en_us",
|
||||||
|
"string": "UniFi import (API)"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": [
|
||||||
|
{
|
||||||
|
"language_code": "en_us",
|
||||||
|
"string": "This plugin is used to import devices from an UNIFI controller via the Site Manager API."
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"icon": [
|
||||||
|
{
|
||||||
|
"language_code": "en_us",
|
||||||
|
"string": "<i class=\"fa-solid fa-shield-halved\"></i>"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"params": [],
|
||||||
|
"settings": [
|
||||||
|
{
|
||||||
|
"function": "RUN",
|
||||||
|
"events": [
|
||||||
|
"run"
|
||||||
|
],
|
||||||
|
"type": {
|
||||||
|
"dataType": "string",
|
||||||
|
"elements": [
|
||||||
|
{
|
||||||
|
"elementType": "select",
|
||||||
|
"elementOptions": [],
|
||||||
|
"transformers": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"default_value": "disabled",
|
||||||
|
"options": [
|
||||||
|
"disabled",
|
||||||
|
"once",
|
||||||
|
"schedule"
|
||||||
|
],
|
||||||
|
"localized": [
|
||||||
|
"name",
|
||||||
|
"description"
|
||||||
|
],
|
||||||
|
"name": [
|
||||||
|
{
|
||||||
|
"language_code": "en_us",
|
||||||
|
"string": "When to run"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": [
|
||||||
|
{
|
||||||
|
"language_code": "en_us",
|
||||||
|
"string": "When the plugin should run. Good options are <code>schedule</code>, <code>once</code>."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"function": "RUN_SCHD",
|
||||||
|
"type": {
|
||||||
|
"dataType": "string",
|
||||||
|
"elements": [
|
||||||
|
{
|
||||||
|
"elementType": "span",
|
||||||
|
"elementOptions": [
|
||||||
|
{
|
||||||
|
"cssClasses": "input-group-addon validityCheck"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"getStringKey": "Gen_ValidIcon"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"transformers": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"elementType": "input",
|
||||||
|
"elementOptions": [
|
||||||
|
{
|
||||||
|
"onChange": "validateRegex(this)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"base64Regex": "Xig/OlwqfCg/OlswLTldfFsxLTVdWzAtOV18WzAtOV0rLVswLTldK3xcKi9bMC05XSspKVxzKyg/OlwqfCg/OlswLTldfDFbMC05XXwyWzAtM118WzAtOV0rLVswLTldK3xcKi9bMC05XSspKVxzKyg/OlwqfCg/OlsxLTldfFsxMl1bMC05XXwzWzAxXXxbMC05XSstWzAtOV0rfFwqL1swLTldKykpXHMrKD86XCp8KD86WzEtOV18MVswLTJdfFswLTldKy1bMC05XSt8XCovWzAtOV0rKSlccysoPzpcKnwoPzpbMC02XXxbMC02XS1bMC02XXxcKi9bMC05XSspKSQ="
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"transformers": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"default_value": "*/5 * * * *",
|
||||||
|
"options": [],
|
||||||
|
"localized": [
|
||||||
|
"name",
|
||||||
|
"description"
|
||||||
|
],
|
||||||
|
"name": [
|
||||||
|
{
|
||||||
|
"language_code": "en_us",
|
||||||
|
"string": "Schedule"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": [
|
||||||
|
{
|
||||||
|
"language_code": "en_us",
|
||||||
|
"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."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"function": "CMD",
|
||||||
|
"type": {
|
||||||
|
"dataType": "string",
|
||||||
|
"elements": [
|
||||||
|
{
|
||||||
|
"elementType": "input",
|
||||||
|
"elementOptions": [
|
||||||
|
{
|
||||||
|
"readonly": "true"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"transformers": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"default_value": "python3 /app/front/plugins/unifi_api_import/unifi_api_import.py",
|
||||||
|
"options": [],
|
||||||
|
"localized": [
|
||||||
|
"name",
|
||||||
|
"description"
|
||||||
|
],
|
||||||
|
"name": [
|
||||||
|
{
|
||||||
|
"language_code": "en_us",
|
||||||
|
"string": "Command"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": [
|
||||||
|
{
|
||||||
|
"language_code": "en_us",
|
||||||
|
"string": "Command to run. This can not be changed"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"function": "RUN_TIMEOUT",
|
||||||
|
"type": {
|
||||||
|
"dataType": "integer",
|
||||||
|
"elements": [
|
||||||
|
{
|
||||||
|
"elementType": "input",
|
||||||
|
"elementOptions": [
|
||||||
|
{
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"transformers": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"default_value": 10,
|
||||||
|
"options": [],
|
||||||
|
"localized": [
|
||||||
|
"name",
|
||||||
|
"description"
|
||||||
|
],
|
||||||
|
"name": [
|
||||||
|
{
|
||||||
|
"language_code": "en_us",
|
||||||
|
"string": "Run timeout"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": [
|
||||||
|
{
|
||||||
|
"language_code": "en_us",
|
||||||
|
"string": "Maximum time in seconds to wait for the script to finish. If this time is exceeded the script is aborted."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"function": "sites",
|
||||||
|
"type": {
|
||||||
|
"dataType": "array",
|
||||||
|
"elements": [
|
||||||
|
{
|
||||||
|
"elementType": "button",
|
||||||
|
"elementOptions": [
|
||||||
|
{
|
||||||
|
"sourceSuffixes": [
|
||||||
|
"_in"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"transformers": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"default_value": "default",
|
||||||
|
"options": [],
|
||||||
|
"localized": [
|
||||||
|
"name",
|
||||||
|
"description"
|
||||||
|
],
|
||||||
|
"name": [
|
||||||
|
{
|
||||||
|
"language_code": "en_us",
|
||||||
|
"string": "Site name"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": [
|
||||||
|
{
|
||||||
|
"language_code": "en_us",
|
||||||
|
"string": "The name of your site. Use a descriptive name."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"function": "base_url",
|
||||||
|
"type": {
|
||||||
|
"dataType": "string",
|
||||||
|
"elements": [
|
||||||
|
{
|
||||||
|
"elementType": "input",
|
||||||
|
"elementOptions": [
|
||||||
|
{
|
||||||
|
"placeholder": "https://host_ip/proxy/network/integration/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"suffix": "_in"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"elementType": "select",
|
||||||
|
"elementHasInputValue": 1,
|
||||||
|
"elementOptions": [
|
||||||
|
{
|
||||||
|
"multiple": "true"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"readonly": "true"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"editable": "true"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"transformers": [
|
||||||
|
"name|base64"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"elementType": "button",
|
||||||
|
"elementOptions": [
|
||||||
|
{
|
||||||
|
"sourceSuffixes": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"separator": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cssClasses": "col-xs-6"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"onClick": "removeFromList(this)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"getStringKey": "Gen_Remove_Last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"transformers": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"elementType": "button",
|
||||||
|
"elementOptions": [
|
||||||
|
{
|
||||||
|
"sourceSuffixes": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"separator": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cssClasses": "col-xs-6"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"onClick": "removeAllOptions(this)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"getStringKey": "Gen_Remove_All"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"transformers": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"default_value": [],
|
||||||
|
"options": [],
|
||||||
|
"localized": [
|
||||||
|
"name",
|
||||||
|
"description"
|
||||||
|
],
|
||||||
|
"name": [
|
||||||
|
{
|
||||||
|
"language_code": "en_us",
|
||||||
|
"string": "Sites"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": [
|
||||||
|
{
|
||||||
|
"language_code": "en_us",
|
||||||
|
"string": "UniFi sites"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"database_column_definitions": [
|
||||||
|
{
|
||||||
|
"column": "Index",
|
||||||
|
"css_classes": "col-sm-2",
|
||||||
|
"show": true,
|
||||||
|
"type": "none",
|
||||||
|
"default_value": "",
|
||||||
|
"options": [],
|
||||||
|
"localized": [
|
||||||
|
"name"
|
||||||
|
],
|
||||||
|
"name": [
|
||||||
|
{
|
||||||
|
"language_code": "en_us",
|
||||||
|
"string": "Index"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"column": "Object_PrimaryID",
|
||||||
|
"mapped_to_column": "cur_MAC",
|
||||||
|
"css_classes": "col-sm-3",
|
||||||
|
"show": true,
|
||||||
|
"type": "device_name_mac",
|
||||||
|
"default_value": "",
|
||||||
|
"options": [],
|
||||||
|
"localized": [
|
||||||
|
"name"
|
||||||
|
],
|
||||||
|
"name": [
|
||||||
|
{
|
||||||
|
"language_code": "en_us",
|
||||||
|
"string": "MAC (name)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"column": "Object_SecondaryID",
|
||||||
|
"mapped_to_column": "cur_IP",
|
||||||
|
"css_classes": "col-sm-2",
|
||||||
|
"show": true,
|
||||||
|
"type": "device_ip",
|
||||||
|
"default_value": "",
|
||||||
|
"options": [],
|
||||||
|
"localized": [
|
||||||
|
"name"
|
||||||
|
],
|
||||||
|
"name": [
|
||||||
|
{
|
||||||
|
"language_code": "en_us",
|
||||||
|
"string": "IP"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"column": "Watched_Value1",
|
||||||
|
"mapped_to_column": "cur_Name",
|
||||||
|
"css_classes": "col-sm-2",
|
||||||
|
"show": true,
|
||||||
|
"type": "label",
|
||||||
|
"default_value": "",
|
||||||
|
"options": [],
|
||||||
|
"localized": [
|
||||||
|
"name"
|
||||||
|
],
|
||||||
|
"name": [
|
||||||
|
{
|
||||||
|
"language_code": "en_us",
|
||||||
|
"string": "Name"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"column": "Watched_Value2",
|
||||||
|
"mapped_to_column": "cur_Vendor",
|
||||||
|
"css_classes": "col-sm-2",
|
||||||
|
"show": true,
|
||||||
|
"type": "label",
|
||||||
|
"default_value": "",
|
||||||
|
"options": [],
|
||||||
|
"localized": [
|
||||||
|
"name"
|
||||||
|
],
|
||||||
|
"name": [
|
||||||
|
{
|
||||||
|
"language_code": "en_us",
|
||||||
|
"string": "Vendor"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"column": "Watched_Value3",
|
||||||
|
"mapped_to_column": "cur_Type",
|
||||||
|
"css_classes": "col-sm-2",
|
||||||
|
"show": true,
|
||||||
|
"type": "label",
|
||||||
|
"default_value": "",
|
||||||
|
"options": [],
|
||||||
|
"localized": [
|
||||||
|
"name"
|
||||||
|
],
|
||||||
|
"name": [
|
||||||
|
{
|
||||||
|
"language_code": "en_us",
|
||||||
|
"string": "Device Type"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"column": "Watched_Value4",
|
||||||
|
"css_classes": "col-sm-2",
|
||||||
|
"show": false,
|
||||||
|
"type": "label",
|
||||||
|
"default_value": "",
|
||||||
|
"options": [],
|
||||||
|
"localized": [
|
||||||
|
"name"
|
||||||
|
],
|
||||||
|
"name": [
|
||||||
|
{
|
||||||
|
"language_code": "en_us",
|
||||||
|
"string": "N/A"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"column": "Dummy",
|
||||||
|
"mapped_to_column": "cur_ScanMethod",
|
||||||
|
"mapped_to_column_data": {
|
||||||
|
"value": "Example Plugin"
|
||||||
|
},
|
||||||
|
"css_classes": "col-sm-2",
|
||||||
|
"show": false,
|
||||||
|
"type": "label",
|
||||||
|
"default_value": "",
|
||||||
|
"options": [],
|
||||||
|
"localized": [
|
||||||
|
"name"
|
||||||
|
],
|
||||||
|
"name": [
|
||||||
|
{
|
||||||
|
"language_code": "en_us",
|
||||||
|
"string": "Scan method"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"column": "DateTimeCreated",
|
||||||
|
"css_classes": "col-sm-2",
|
||||||
|
"show": true,
|
||||||
|
"type": "label",
|
||||||
|
"default_value": "",
|
||||||
|
"options": [],
|
||||||
|
"localized": [
|
||||||
|
"name"
|
||||||
|
],
|
||||||
|
"name": [
|
||||||
|
{
|
||||||
|
"language_code": "en_us",
|
||||||
|
"string": "Created"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"column": "DateTimeChanged",
|
||||||
|
"css_classes": "col-sm-2",
|
||||||
|
"show": true,
|
||||||
|
"type": "label",
|
||||||
|
"default_value": "",
|
||||||
|
"options": [],
|
||||||
|
"localized": [
|
||||||
|
"name"
|
||||||
|
],
|
||||||
|
"name": [
|
||||||
|
{
|
||||||
|
"language_code": "en_us",
|
||||||
|
"string": "Changed"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"column": "Status",
|
||||||
|
"css_classes": "col-sm-1",
|
||||||
|
"show": true,
|
||||||
|
"type": "replace",
|
||||||
|
"default_value": "",
|
||||||
|
"options": [
|
||||||
|
{
|
||||||
|
"equals": "watched-not-changed",
|
||||||
|
"replacement": "<div style='text-align:center'><i class='fa-solid fa-square-check'></i><div></div>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"equals": "watched-changed",
|
||||||
|
"replacement": "<div style='text-align:center'><i class='fa-solid fa-triangle-exclamation'></i></div>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"equals": "new",
|
||||||
|
"replacement": "<div style='text-align:center'><i class='fa-solid fa-circle-plus'></i></div>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"equals": "missing-in-last-scan",
|
||||||
|
"replacement": "<div style='text-align:center'><i class='fa-solid fa-question'></i></div>"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"localized": [
|
||||||
|
"name"
|
||||||
|
],
|
||||||
|
"name": [
|
||||||
|
{
|
||||||
|
"language_code": "en_us",
|
||||||
|
"string": "Status"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
124
front/plugins/unifi_api_import/unifi_api_import.py
Executable file
124
front/plugins/unifi_api_import/unifi_api_import.py
Executable file
@@ -0,0 +1,124 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import os
|
||||||
|
import pathlib
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
import sqlite3
|
||||||
|
from pytz import timezone
|
||||||
|
|
||||||
|
# Define the installation path and extend the system path for plugin imports
|
||||||
|
INSTALL_PATH = "/app"
|
||||||
|
sys.path.extend([f"{INSTALL_PATH}/front/plugins", f"{INSTALL_PATH}/server"])
|
||||||
|
|
||||||
|
from plugin_helper import Plugin_Object, Plugin_Objects, decodeBase64
|
||||||
|
from plugin_utils import get_plugins_configs
|
||||||
|
from logger import mylog, Logger
|
||||||
|
from const import pluginsPath, fullDbPath, logPath
|
||||||
|
from helper import timeNowTZ, get_setting_value
|
||||||
|
|
||||||
|
from messaging.in_app import write_notification
|
||||||
|
import conf
|
||||||
|
|
||||||
|
# Make sure the TIMEZONE for logging is correct
|
||||||
|
conf.tz = timezone(get_setting_value('TIMEZONE'))
|
||||||
|
|
||||||
|
# Make sure log level is initialized correctly
|
||||||
|
Logger(get_setting_value('LOG_LEVEL'))
|
||||||
|
|
||||||
|
pluginName = '<unique_prefix>'
|
||||||
|
|
||||||
|
# Define the current path and log file paths
|
||||||
|
LOG_PATH = logPath + '/plugins'
|
||||||
|
LOG_FILE = os.path.join(LOG_PATH, f'script.{pluginName}.log')
|
||||||
|
RESULT_FILE = os.path.join(LOG_PATH, f'last_result.{pluginName}.log')
|
||||||
|
|
||||||
|
# Initialize the Plugin obj output file
|
||||||
|
plugin_objects = Plugin_Objects(RESULT_FILE)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
mylog('verbose', [f'[{pluginName}] In script'])
|
||||||
|
|
||||||
|
# Retrieve configuration settings
|
||||||
|
some_setting = get_setting_value('SYNC_plugins')
|
||||||
|
|
||||||
|
mylog('verbose', [f'[{pluginName}] some_setting value {some_setting}'])
|
||||||
|
|
||||||
|
# retrieve data
|
||||||
|
device_data = get_device_data(some_setting)
|
||||||
|
|
||||||
|
# Process the data into native application tables
|
||||||
|
if len(device_data) > 0:
|
||||||
|
|
||||||
|
# insert devices into the lats_result.log
|
||||||
|
# make sure the below mapping is mapped in config.json, for example:
|
||||||
|
#"database_column_definitions": [
|
||||||
|
# {
|
||||||
|
# "column": "Object_PrimaryID", <--------- the value I save into primaryId
|
||||||
|
# "mapped_to_column": "cur_MAC", <--------- gets inserted into the CurrentScan DB table column cur_MAC
|
||||||
|
#
|
||||||
|
for device in device_data:
|
||||||
|
plugin_objects.add_object(
|
||||||
|
primaryId = device['mac_address'],
|
||||||
|
secondaryId = device['ip_address'],
|
||||||
|
watched1 = device['hostname'],
|
||||||
|
watched2 = device['vendor'],
|
||||||
|
watched3 = device['device_type'],
|
||||||
|
watched4 = device['last_seen'],
|
||||||
|
extra = '',
|
||||||
|
foreignKey = device['mac_address']
|
||||||
|
# helpVal1 = "Something1", # Optional Helper values to be passed for mapping into the app
|
||||||
|
# helpVal2 = "Something1", # If you need to use even only 1, add the remaining ones too
|
||||||
|
# helpVal3 = "Something1", # and set them to 'null'. Check the the docs for details:
|
||||||
|
# helpVal4 = "Something1", # https://github.com/jokob-sk/NetAlertX/blob/main/docs/PLUGINS_DEV.md
|
||||||
|
)
|
||||||
|
|
||||||
|
mylog('verbose', [f'[{pluginName}] New entries: "{len(device_data)}"'])
|
||||||
|
|
||||||
|
# log result
|
||||||
|
plugin_objects.write_result_file()
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
# retrieve data
|
||||||
|
def get_device_data(some_setting):
|
||||||
|
|
||||||
|
device_data = []
|
||||||
|
|
||||||
|
# do some processing, call exteranl APIs, and return a device_data list
|
||||||
|
# ...
|
||||||
|
#
|
||||||
|
# Sample data for testing purposes, you can adjust the processing in main() as needed
|
||||||
|
# ... before adding it to the plugin_objects.add_object(...)
|
||||||
|
device_data = [
|
||||||
|
{
|
||||||
|
'device_id': 'device1',
|
||||||
|
'mac_address': '00:11:22:33:44:55',
|
||||||
|
'ip_address': '192.168.1.2',
|
||||||
|
'hostname': 'iPhone 12',
|
||||||
|
'vendor': 'Apple Inc.',
|
||||||
|
'device_type': 'Smartphone',
|
||||||
|
'last_seen': '2024-06-27 10:00:00',
|
||||||
|
'port': '1',
|
||||||
|
'network_id': 'network1'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'device_id': 'device2',
|
||||||
|
'mac_address': '00:11:22:33:44:66',
|
||||||
|
'ip_address': '192.168.1.3',
|
||||||
|
'hostname': 'Moto G82',
|
||||||
|
'vendor': 'Motorola Inc.',
|
||||||
|
'device_type': 'Laptop',
|
||||||
|
'last_seen': '2024-06-27 10:05:00',
|
||||||
|
'port': '',
|
||||||
|
'network_id': 'network1'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
# Return the data to be detected by the main application
|
||||||
|
return device_data
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
require 'php/templates/header.php';
|
require 'php/templates/header.php';
|
||||||
require 'php/templates/notification.php';
|
require 'php/templates/modals.php';
|
||||||
|
|
||||||
?>
|
?>
|
||||||
|
|
||||||
|
|||||||
@@ -58,6 +58,12 @@ $settingsJSON_DB = json_encode($settings, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX
|
|||||||
|
|
||||||
<div id="settingsPage" class="content-wrapper">
|
<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--------------------------------------------------------- -->
|
<!-- Content header--------------------------------------------------------- -->
|
||||||
|
|
||||||
<section class="content-header">
|
<section class="content-header">
|
||||||
@@ -597,7 +603,8 @@ $settingsJSON_DB = json_encode($settings, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX
|
|||||||
customParams,
|
customParams,
|
||||||
customId,
|
customId,
|
||||||
columns,
|
columns,
|
||||||
base64Regex
|
base64Regex,
|
||||||
|
elementOptionsBase64
|
||||||
} = handleElementOptions('none', elementOptions, transformers, val = "");
|
} = handleElementOptions('none', elementOptions, transformers, val = "");
|
||||||
|
|
||||||
let value;
|
let value;
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
require 'php/templates/header.php';
|
require 'php/templates/header.php';
|
||||||
?>
|
?>
|
||||||
<?php require 'php/templates/notification.php'; ?>
|
<?php require 'php/templates/modals.php'; ?>
|
||||||
<!-- ----------------------------------------------------------------------- -->
|
<!-- ----------------------------------------------------------------------- -->
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -9,11 +9,33 @@
|
|||||||
|
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
function getExternalIp() {
|
||||||
|
$ch = curl_init('https://api64.ipify.org?format=json');
|
||||||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
|
||||||
|
$response = curl_exec($ch);
|
||||||
|
if (curl_errno($ch)) {
|
||||||
|
curl_close($ch);
|
||||||
|
return 'ERROR: ' . curl_error($ch);
|
||||||
|
}
|
||||||
|
curl_close($ch);
|
||||||
|
|
||||||
|
$data = json_decode($response, true);
|
||||||
|
if (isset($data['ip'])) {
|
||||||
|
return htmlspecialchars($data['ip']);
|
||||||
|
}
|
||||||
|
return 'ERROR: Invalid response';
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
||||||
// Network
|
// Network
|
||||||
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
||||||
|
|
||||||
//Network stats
|
//Network stats
|
||||||
|
// Server IP
|
||||||
|
|
||||||
|
$externalIp = getExternalIp();
|
||||||
|
|
||||||
// Check Server name
|
// Check Server name
|
||||||
if (!empty(gethostname())) { $network_NAME = gethostname(); } else { $network_NAME = lang('Systeminfo_Network_Server_Name_String'); }
|
if (!empty(gethostname())) { $network_NAME = gethostname(); } else { $network_NAME = lang('Systeminfo_Network_Server_Name_String'); }
|
||||||
// Check HTTPS
|
// Check HTTPS
|
||||||
@@ -100,7 +122,7 @@ echo '<div class="box box-solid">
|
|||||||
<div class="box-body">
|
<div class="box-body">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-3 sysinfo_network_a">' . lang('Systeminfo_Network_IP') . '</div>
|
<div class="col-sm-3 sysinfo_network_a">' . lang('Systeminfo_Network_IP') . '</div>
|
||||||
<div class="col-sm-9 sysinfo_network_b" id="external-ip">Loading...</div>
|
<div class="col-sm-9 sysinfo_network_b" id="external-ip">' .$externalIp. '</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-3 sysinfo_network_a">' . lang('Systeminfo_Network_IP_Connection') . '</div>
|
<div class="col-sm-3 sysinfo_network_a">' . lang('Systeminfo_Network_IP_Connection') . '</div>
|
||||||
@@ -242,8 +264,6 @@ function fetchUsedIps(callback) {
|
|||||||
function renderAvailableIpsTable(allIps, usedIps) {
|
function renderAvailableIpsTable(allIps, usedIps) {
|
||||||
const availableIps = allIps.filter(row => !usedIps.includes(row.ip));
|
const availableIps = allIps.filter(row => !usedIps.includes(row.ip));
|
||||||
|
|
||||||
console.log(allIps);
|
|
||||||
console.log(usedIps);
|
|
||||||
console.log(availableIps);
|
console.log(availableIps);
|
||||||
|
|
||||||
$('#availableIpsTable').DataTable({
|
$('#availableIpsTable').DataTable({
|
||||||
@@ -290,19 +310,6 @@ $(document).ready(function() {
|
|||||||
hideSpinner(); // Called after the DataTable is fully initialized
|
hideSpinner(); // Called after the DataTable is fully initialized
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// external IP
|
|
||||||
$.ajax({
|
|
||||||
url: 'https://api64.ipify.org?format=json',
|
|
||||||
method: 'GET',
|
|
||||||
timeout: 10000, // 10 seconds timeout
|
|
||||||
success: function (response) {
|
|
||||||
$('#external-ip').text(response.ip);
|
|
||||||
},
|
|
||||||
error: function() {
|
|
||||||
$('#external-ip').text('ERROR');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, 200);
|
}, 200);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
require 'php/templates/header.php';
|
require 'php/templates/header.php';
|
||||||
require 'php/templates/notification.php';
|
require 'php/templates/modals.php';
|
||||||
?>
|
?>
|
||||||
<!-- ----------------------------------------------------------------------- -->
|
<!-- ----------------------------------------------------------------------- -->
|
||||||
|
|
||||||
|
|||||||
@@ -30,5 +30,5 @@ source myenv/bin/activate
|
|||||||
update-alternatives --install /usr/bin/python python /usr/bin/python3 10
|
update-alternatives --install /usr/bin/python python /usr/bin/python3 10
|
||||||
|
|
||||||
# install packages thru pip3
|
# install packages thru pip3
|
||||||
pip3 install openwrt-luci-rpc asusrouter asyncio aiohttp graphene flask flask-cors tplink-omada-client wakeonlan pycryptodome requests paho-mqtt scapy cron-converter pytz json2table dhcp-leases pyunifi speedtest-cli chardet python-nmap dnspython librouteros yattag git+https://github.com/foreign-sub/aiofreepybox.git
|
pip3 install openwrt-luci-rpc asusrouter asyncio aiohttp graphene flask flask-cors unifi-sm-api tplink-omada-client wakeonlan pycryptodome requests paho-mqtt scapy cron-converter pytz json2table dhcp-leases pyunifi speedtest-cli chardet python-nmap dnspython librouteros yattag git+https://github.com/foreign-sub/aiofreepybox.git
|
||||||
|
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ nav:
|
|||||||
- Debugging Tips: DEBUG_TIPS.md
|
- Debugging Tips: DEBUG_TIPS.md
|
||||||
- Debugging GraphQL: DEBUG_GRAPHQL.md
|
- Debugging GraphQL: DEBUG_GRAPHQL.md
|
||||||
- Debugging Invalid JSON: DEBUG_INVALID_JSON.md
|
- Debugging Invalid JSON: DEBUG_INVALID_JSON.md
|
||||||
|
- Debugging PHP: DEBUG_PHP.md
|
||||||
- Debugging Plugins: DEBUG_PLUGINS.md
|
- Debugging Plugins: DEBUG_PLUGINS.md
|
||||||
- Debugging Web UI Port: WEB_UI_PORT_DEBUG.md
|
- Debugging Web UI Port: WEB_UI_PORT_DEBUG.md
|
||||||
- Debugging Workflows: WORKFLOWS_DEBUGGING.md
|
- Debugging Workflows: WORKFLOWS_DEBUGGING.md
|
||||||
@@ -75,6 +76,7 @@ nav:
|
|||||||
- Database: DATABASE.md
|
- Database: DATABASE.md
|
||||||
- Settings: SETTINGS_SYSTEM.md
|
- Settings: SETTINGS_SYSTEM.md
|
||||||
- Versions: VERSIONS.md
|
- Versions: VERSIONS.md
|
||||||
|
- Icon and Type guessing: DEVICE_HEURISTICS.md
|
||||||
- Integrations:
|
- Integrations:
|
||||||
- Webhook Secret: WEBHOOK_SECRET.md
|
- Webhook Secret: WEBHOOK_SECRET.md
|
||||||
- API: API.md
|
- API: API.md
|
||||||
|
|||||||
@@ -197,7 +197,7 @@ class Query(ObjectType):
|
|||||||
searchable_fields = [
|
searchable_fields = [
|
||||||
"devName", "devMac", "devOwner", "devType", "devVendor", "devLastIP",
|
"devName", "devMac", "devOwner", "devType", "devVendor", "devLastIP",
|
||||||
"devGroup", "devComments", "devLocation", "devStatus", "devSSID",
|
"devGroup", "devComments", "devLocation", "devStatus", "devSSID",
|
||||||
"devSite", "devSourcePlugin", "devSyncHubNode", "devFQDN", "devParentRelType"
|
"devSite", "devSourcePlugin", "devSyncHubNode", "devFQDN", "devParentRelType", "devParentMAC"
|
||||||
]
|
]
|
||||||
|
|
||||||
search_term = options.search.lower()
|
search_term = options.search.lower()
|
||||||
|
|||||||
@@ -667,7 +667,10 @@ def checkNewVersion():
|
|||||||
buildTimestamp = int(f.read().strip())
|
buildTimestamp = int(f.read().strip())
|
||||||
|
|
||||||
try:
|
try:
|
||||||
response = requests.get("https://api.github.com/repos/jokob-sk/NetAlertX/releases")
|
response = requests.get(
|
||||||
|
"https://api.github.com/repos/jokob-sk/NetAlertX/releases",
|
||||||
|
timeout=5
|
||||||
|
)
|
||||||
response.raise_for_status() # Raise an exception for HTTP errors
|
response.raise_for_status() # Raise an exception for HTTP errors
|
||||||
text = response.text
|
text = response.text
|
||||||
except requests.exceptions.RequestException as e:
|
except requests.exceptions.RequestException as e:
|
||||||
|
|||||||
@@ -157,7 +157,7 @@ def importConfigs (db, all_plugins):
|
|||||||
# ----------------------------------------
|
# ----------------------------------------
|
||||||
# ccd(key, default, config_dir, name, inputtype, options, group, events=[], desc = "", regex = "", setJsonMetadata = {}, overrideTemplate = {})
|
# ccd(key, default, config_dir, name, inputtype, options, group, events=[], desc = "", regex = "", setJsonMetadata = {}, overrideTemplate = {})
|
||||||
|
|
||||||
conf.LOADED_PLUGINS = ccd('LOADED_PLUGINS', [] , c_d, 'Loaded plugins', '{"dataType":"array", "elements": [{"elementType" : "select", "elementOptions" : [{"multiple":"true", "ordeable": "true"}] ,"transformers": []}]}', '[]', 'General')
|
conf.LOADED_PLUGINS = ccd('LOADED_PLUGINS', [] , c_d, 'Loaded plugins', '{"dataType":"array","elements":[{"elementType":"select","elementOptions":[{"multiple":"true","ordeable":"true"}],"transformers":[]},{"elementType":"button","elementOptions":[{"sourceSuffixes":[]},{"separator":""},{"cssClasses":"col-xs-12"},{"onClick":"selectChange(this)"},{"getStringKey":"Gen_Change"}],"transformers":[]}]}', '[]', 'General')
|
||||||
conf.DISCOVER_PLUGINS = ccd('DISCOVER_PLUGINS', True , c_d, 'Discover plugins', """{"dataType": "boolean","elements": [{"elementType": "input","elementOptions": [{ "type": "checkbox" }],"transformers": []}]}""", '[]', 'General')
|
conf.DISCOVER_PLUGINS = ccd('DISCOVER_PLUGINS', True , c_d, 'Discover plugins', """{"dataType": "boolean","elements": [{"elementType": "input","elementOptions": [{ "type": "checkbox" }],"transformers": []}]}""", '[]', 'General')
|
||||||
conf.SCAN_SUBNETS = ccd('SCAN_SUBNETS', ['192.168.1.0/24 --interface=eth1', '192.168.1.0/24 --interface=eth0'] , c_d, 'Subnets to scan', '''{"dataType": "array","elements": [{"elementType": "input","elementOptions": [{"placeholder": "192.168.1.0/24 --interface=eth1"},{"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": []}]}''', '[]', 'General')
|
conf.SCAN_SUBNETS = ccd('SCAN_SUBNETS', ['192.168.1.0/24 --interface=eth1', '192.168.1.0/24 --interface=eth0'] , c_d, 'Subnets to scan', '''{"dataType": "array","elements": [{"elementType": "input","elementOptions": [{"placeholder": "192.168.1.0/24 --interface=eth1"},{"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": []}]}''', '[]', 'General')
|
||||||
conf.LOG_LEVEL = ccd('LOG_LEVEL', 'verbose' , c_d, 'Log verboseness', '{"dataType":"string", "elements": [{"elementType" : "select", "elementOptions" : [] ,"transformers": []}]}', "['none', 'minimal', 'verbose', 'debug', 'trace']", 'General')
|
conf.LOG_LEVEL = ccd('LOG_LEVEL', 'verbose' , c_d, 'Log verboseness', '{"dataType":"string", "elements": [{"elementType" : "select", "elementOptions" : [] ,"transformers": []}]}', "['none', 'minimal', 'verbose', 'debug', 'trace']", 'General')
|
||||||
@@ -275,6 +275,15 @@ def importConfigs (db, all_plugins):
|
|||||||
# Save the user defined value into the object
|
# Save the user defined value into the object
|
||||||
set["value"] = v
|
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
|
# Collect settings related language strings
|
||||||
# Creates an entry with key, for example ARPSCAN_CMD_name
|
# Creates an entry with key, for example ARPSCAN_CMD_name
|
||||||
stringSqlParams = collect_lang_strings(set, pref + "_" + set["function"], stringSqlParams)
|
stringSqlParams = collect_lang_strings(set, pref + "_" + set["function"], stringSqlParams)
|
||||||
|
|||||||
@@ -447,8 +447,8 @@ def create_new_devices (db):
|
|||||||
cur_MAC, cur_Name, cur_Vendor, cur_ScanMethod, cur_IP, cur_SyncHubNodeName, cur_NetworkNodeMAC, cur_PORT, cur_NetworkSite, cur_SSID, cur_Type = row
|
cur_MAC, cur_Name, cur_Vendor, cur_ScanMethod, cur_IP, cur_SyncHubNodeName, cur_NetworkNodeMAC, cur_PORT, cur_NetworkSite, cur_SSID, cur_Type = row
|
||||||
|
|
||||||
# Handle NoneType
|
# Handle NoneType
|
||||||
cur_Name = cur_Name.strip() if cur_Name else '(unknown)'
|
cur_Name = str(cur_Name).strip() if cur_Name else '(unknown)'
|
||||||
cur_Type = cur_Type.strip() if cur_Type else get_setting_value("NEWDEV_devType")
|
cur_Type = str(cur_Type).strip() if cur_Type else get_setting_value("NEWDEV_devType")
|
||||||
cur_NetworkNodeMAC = cur_NetworkNodeMAC.strip() if cur_NetworkNodeMAC else ''
|
cur_NetworkNodeMAC = cur_NetworkNodeMAC.strip() if cur_NetworkNodeMAC else ''
|
||||||
cur_NetworkNodeMAC = cur_NetworkNodeMAC if cur_NetworkNodeMAC and cur_MAC != "Internet" else (get_setting_value("NEWDEV_devParentMAC") if cur_MAC != "Internet" else "null")
|
cur_NetworkNodeMAC = cur_NetworkNodeMAC if cur_NetworkNodeMAC and cur_MAC != "Internet" else (get_setting_value("NEWDEV_devParentMAC") if cur_MAC != "Internet" else "null")
|
||||||
cur_SyncHubNodeName = cur_SyncHubNodeName if cur_SyncHubNodeName and cur_SyncHubNodeName != "null" else (get_setting_value("SYNC_node_name"))
|
cur_SyncHubNodeName = cur_SyncHubNodeName if cur_SyncHubNodeName and cur_SyncHubNodeName != "null" else (get_setting_value("SYNC_node_name"))
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ def match_name(
|
|||||||
|
|
||||||
#-------------------------------------------------------------------------------
|
#-------------------------------------------------------------------------------
|
||||||
#
|
#
|
||||||
def match_ip_rule(
|
def match_ip(
|
||||||
ip: str,
|
ip: str,
|
||||||
default_type: str,
|
default_type: str,
|
||||||
default_icon: str
|
default_icon: str
|
||||||
@@ -215,7 +215,7 @@ def guess_device_attributes(
|
|||||||
|
|
||||||
# --- Loose IP-based fallback ---
|
# --- Loose IP-based fallback ---
|
||||||
if (not type_ or type_ == default_type) or (not icon or icon == default_icon):
|
if (not type_ or type_ == default_type) or (not icon or icon == default_icon):
|
||||||
type_, icon = match_ip_rule(ip, default_type, default_icon)
|
type_, icon = match_ip(ip, default_type, default_icon)
|
||||||
|
|
||||||
# Final fallbacks
|
# Final fallbacks
|
||||||
type_ = type_ or default_type
|
type_ = type_ or default_type
|
||||||
|
|||||||
Reference in New Issue
Block a user