mirror of
https://github.com/jokob-sk/NetAlertX.git
synced 2026-05-19 14:16:47 -04:00
Compare commits
117 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f894390dfa | ||
|
|
c19908aedc | ||
|
|
9d4df585f2 | ||
|
|
e1cf1d8ff2 | ||
|
|
61a5d7b863 | ||
|
|
9b0b43dea1 | ||
|
|
48e587f580 | ||
|
|
2fa62a2c0c | ||
|
|
604a8312ee | ||
|
|
80bb53a96a | ||
|
|
a39190cf4a | ||
|
|
cd799b1b20 | ||
|
|
90813c5f30 | ||
|
|
b6a11d79c4 | ||
|
|
f5046ff862 | ||
|
|
4408cf1a1e | ||
|
|
fbf468be2b | ||
|
|
02edb61fd4 | ||
|
|
2656af3f82 | ||
|
|
fb7dab4881 | ||
|
|
2fd7e5e700 | ||
|
|
8168bb2d5b | ||
|
|
f96bdcce6e | ||
|
|
82ff2ae376 | ||
|
|
ee69edacd1 | ||
|
|
434f85d786 | ||
|
|
a63482d43a | ||
|
|
9c5c45b528 | ||
|
|
5bce6f6276 | ||
|
|
ed1ed6bb3f | ||
|
|
6cd19b05e1 | ||
|
|
148cd93c75 | ||
|
|
b8309c123b | ||
|
|
0b076cec0e | ||
|
|
d0a7cbd876 | ||
|
|
7a931511de | ||
|
|
127ab1b495 | ||
|
|
cf2ef1795b | ||
|
|
78a2369dc0 | ||
|
|
553def362a | ||
|
|
f70c125f2c | ||
|
|
3bce0701d3 | ||
|
|
e91f5ad539 | ||
|
|
975f64353d | ||
|
|
ff73f62f9e | ||
|
|
142813963b | ||
|
|
366df94c9e | ||
|
|
11a7ac1170 | ||
|
|
a4b494bd5c | ||
|
|
a5b4f2a2d7 | ||
|
|
f9bd8f35f5 | ||
|
|
7c7beaaf96 | ||
|
|
c0462984e7 | ||
|
|
89139fed60 | ||
|
|
285bd3ec22 | ||
|
|
98a1ac1336 | ||
|
|
090b7e038a | ||
|
|
4267a5c30c | ||
|
|
3fc9ddd637 | ||
|
|
f6b4965791 | ||
|
|
f8fc7e6e91 | ||
|
|
976cbccfca | ||
|
|
03a228e31e | ||
|
|
c275bf447d | ||
|
|
8abecb7a0d | ||
|
|
79a9e9f8a3 | ||
|
|
b0c687a171 | ||
|
|
36174a8cd9 | ||
|
|
309315defc | ||
|
|
686a1c8ddb | ||
|
|
cc507f20e0 | ||
|
|
51b8cf03b5 | ||
|
|
c80dc9c36a | ||
|
|
50be56c8bb | ||
|
|
25757549f3 | ||
|
|
c40d04b2c4 | ||
|
|
ea8e2641a4 | ||
|
|
623fabd125 | ||
|
|
6044a41852 | ||
|
|
ab45f28027 | ||
|
|
03891dd78d | ||
|
|
9e605a593d | ||
|
|
8230b2380c | ||
|
|
0c6f5b223f | ||
|
|
924d70d267 | ||
|
|
33c3e2fef7 | ||
|
|
940cd503d3 | ||
|
|
0e862845f4 | ||
|
|
68e5b3c877 | ||
|
|
7827e24aae | ||
|
|
3ff128e1f5 | ||
|
|
ef0d521e2b | ||
|
|
16e2249d0d | ||
|
|
a6d3b85614 | ||
|
|
6eaa477ed3 | ||
|
|
e3a4c62d5f | ||
|
|
da8b694a49 | ||
|
|
28e6d62ccb | ||
|
|
b530a6e635 | ||
|
|
548d237c38 | ||
|
|
b96b170bed | ||
|
|
da9c5f1bc7 | ||
|
|
2e8b793b44 | ||
|
|
3c8fd72049 | ||
|
|
ae089f5ad9 | ||
|
|
4b6203a1d0 | ||
|
|
13f840b9f2 | ||
|
|
ca9a0ef5ce | ||
|
|
bc66575f91 | ||
|
|
ee42d8b56a | ||
|
|
ae2dc92318 | ||
|
|
706ef1a8a1 | ||
|
|
1d4fd09444 | ||
|
|
0648e8217c | ||
|
|
5839853f69 | ||
|
|
83de79bf94 | ||
|
|
92f1508d33 |
12
.github/skills/code-standards/SKILL.md
vendored
12
.github/skills/code-standards/SKILL.md
vendored
@@ -74,6 +74,18 @@ Use sanitizers from `server/helper.py` before storing user input. MAC addresses
|
||||
- Everything is already writable
|
||||
- If permissions needed, fix `.devcontainer/scripts/setup.sh`
|
||||
|
||||
## Test Helpers — No Duplicate Mocks
|
||||
|
||||
Reuse shared mocks and factories from `test/db_test_helpers.py`. Never redefine `DummyDB`, `make_db`, or inline DDL in individual test files.
|
||||
|
||||
```python
|
||||
import sys, os
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
|
||||
from db_test_helpers import make_db, DummyDB, insert_device, minutes_ago
|
||||
```
|
||||
|
||||
If a helper you need doesn't exist yet, add it to `db_test_helpers.py` — not locally in the test file.
|
||||
|
||||
## Path Hygiene
|
||||
|
||||
- Use environment variables for runtime paths
|
||||
|
||||
@@ -15,6 +15,22 @@ Before opening a new issue:
|
||||
- [Check Common Issues & Debug Tips](https://docs.netalertx.com/DEBUG_TIPS#common-issues)
|
||||
- [Search Closed Issues](https://github.com/netalertx/NetAlertX/issues?q=is%3Aissue+is%3Aclosed)
|
||||
|
||||
---
|
||||
|
||||
## Contributing without coding knowledge
|
||||
|
||||
Writing code is not the only way how you can contribute to the project. Here are some ideas how you can help out otherwise:
|
||||
|
||||
- Help improving the documentation (text, typos, use cases, screenshots - all this makes things better)
|
||||
- Share your favorite project on socials (see [Growth ideas](./GROWTH.md))
|
||||
- Write a blog post, or a how-to set-up guide
|
||||
- Write how it helped you to achieve something fun or interesting to simplify your personal or work life
|
||||
- Help with the translation effort
|
||||
- Running a nightly or dev build to test for bugs before they make it to the production release
|
||||
- Report bugs and features with sufficient detail and care (super important to ease everyone's maintenance burden and minimize back-and-forth)
|
||||
- running a projects test suite
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Use of AI
|
||||
|
||||
142
GROWTH.md
Normal file
142
GROWTH.md
Normal file
@@ -0,0 +1,142 @@
|
||||
# 📈 NetAlertX Growth Playbook
|
||||
|
||||
If you like NetAlertX and want to help it grow, this is how.
|
||||
|
||||
This isn’t about spam or "growth hacks." It’s just getting the tool in front of people who already have the problem (manual network docs, blind spots, messy networks).
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Who this is for
|
||||
|
||||
* **Homelabbers** → Proxmox, Unraid, Raspberry Pi setups
|
||||
* **Self-hosters** → moving away from cloud / want local-first
|
||||
* **Sysadmins / MSPs** → need visibility + fast onboarding
|
||||
|
||||
---
|
||||
|
||||
## 💬 Where to post (and how)
|
||||
|
||||
### Reddit (main channel)
|
||||
|
||||
Reddit works *if* you don’t sound like marketing.
|
||||
|
||||
**Subreddits**
|
||||
|
||||
* r/homelab
|
||||
* r/selfhosted
|
||||
* r/sysadmin
|
||||
* r/networking
|
||||
|
||||
**What works**
|
||||
|
||||
* "Show r/homelab" / "I built this"
|
||||
* Problem → solution
|
||||
* Real screenshots or short GIFs
|
||||
|
||||
**Example**
|
||||
|
||||
> Tired of keeping network diagrams up to date?
|
||||
> I deployed something that does it automatically.
|
||||
|
||||
**Avoid**
|
||||
|
||||
* Over-explaining
|
||||
* Buzzwords
|
||||
* "Check out my project!!!" energy
|
||||
|
||||
**Timing (rough guide)**
|
||||
|
||||
* Tue–Thu mornings (US time)
|
||||
|
||||
---
|
||||
|
||||
### Hacker News (Show HN)
|
||||
|
||||
Good fit because NetAlertX is:
|
||||
|
||||
* local-first
|
||||
* privacy-focused
|
||||
* actually useful
|
||||
|
||||
**Title**
|
||||
|
||||
> Show HN: NetAlertX – network documentation that updates itself
|
||||
|
||||
Be ready to answer:
|
||||
|
||||
* stack (Python / PHP / JS)
|
||||
* how discovery works
|
||||
* privacy / local scanning
|
||||
|
||||
---
|
||||
|
||||
### Awesome Lists
|
||||
|
||||
Low effort, long-term visibility.
|
||||
|
||||
Target:
|
||||
|
||||
* awesome-selfhosted
|
||||
* awesome-homelab
|
||||
|
||||
Keep it simple:
|
||||
|
||||
> NetAlertX – automated network discovery and documentation with alerting
|
||||
|
||||
---
|
||||
|
||||
## 🎥 Content / creators
|
||||
|
||||
If you or someone else makes videos, these angles work:
|
||||
|
||||
* **First 5 minutes** → "it already found everything"
|
||||
* **Before vs after** → manual vs NetAlertX
|
||||
* **Docker setup** → show how easy it is
|
||||
|
||||
No need for overproduction—real usage > polished demos.
|
||||
|
||||
---
|
||||
|
||||
## ⚖️ Positioning (keep it simple)
|
||||
|
||||
When explaining NetAlertX, this is the mental model:
|
||||
|
||||
| | Manual Docs | Basic Scanners | NetAlertX |
|
||||
| ------- | ----------------- | -------------- | ------------------------- |
|
||||
| Updates | Manual / outdated | On demand | **Automatic** |
|
||||
| Alerts | None | Limited | **New / unknown devices** |
|
||||
| History | None | None | **Device timeline** |
|
||||
| Effort | High | Medium | **Set & forget** |
|
||||
|
||||
---
|
||||
|
||||
## 🧑💻 MSP / professional angle
|
||||
|
||||
If you’re using it in real environments:
|
||||
|
||||
* Faster client onboarding
|
||||
* Better visibility
|
||||
* Less "what changed?" guessing
|
||||
|
||||
That’s the value—keep it grounded. And share your experience 🙏
|
||||
|
||||
---
|
||||
|
||||
## 🛠 Easy ways to help
|
||||
|
||||
* Star the repo
|
||||
* Post a screenshot of your network
|
||||
* Mention it when someone asks "how do you track devices?" or "how do you detect presence?"
|
||||
* Write a quick "how I use it" post
|
||||
|
||||
---
|
||||
|
||||
## Final note
|
||||
|
||||
Authenticity matters more than reach.
|
||||
|
||||
If it feels like marketing, people ignore it.
|
||||
If it feels like "this solved my problem," people pay attention.
|
||||
|
||||
Thanks a lot in advance!
|
||||
- jokob
|
||||
@@ -50,6 +50,10 @@ Manage a **single device** by its MAC address. Operations include retrieval, upd
|
||||
* **POST** `/device/<mac>`
|
||||
Create or update a device record.
|
||||
|
||||
> ⚠️ **Full-replace (PUT) semantics.** Every editable field is written on each call. Any field omitted from the payload is reset to its default (empty string or `0`). This matches how the frontend edit form works — it always sends the complete device state.
|
||||
>
|
||||
> To update a **single field** without affecting others, use [`POST /device/<mac>/update-column`](#7-update-a-single-column) instead.
|
||||
|
||||
**Request Body**:
|
||||
|
||||
```json
|
||||
@@ -62,8 +66,8 @@ Manage a **single device** by its MAC address. Operations include retrieval, upd
|
||||
|
||||
**Behavior**:
|
||||
|
||||
* If `createNew=true` → creates a new device
|
||||
* Otherwise → updates existing device fields
|
||||
* If `createNew=true` → inserts a new device row
|
||||
* Otherwise → **replaces all editable fields** on the existing device
|
||||
|
||||
**Response**:
|
||||
|
||||
@@ -163,7 +167,13 @@ Manage a **single device** by its MAC address. Operations include retrieval, upd
|
||||
## 7. Update a Single Column
|
||||
|
||||
* **POST** `/device/<mac>/update-column`
|
||||
Update one specific column for a device.
|
||||
Update exactly one field for a device without touching any other fields.
|
||||
|
||||
> ✅ **Partial-update (PATCH) semantics.** Only the specified column is written. All other fields are left unchanged. Use this for automation, integrations, and any workflow that needs to update a single attribute.
|
||||
>
|
||||
> To replace all fields at once (e.g. saving from the edit form), use [`POST /device/<mac>`](#2-update-device-fields).
|
||||
|
||||
Allowed `columnName` values: `devName`, `devOwner`, `devType`, `devVendor`, `devGroup`, `devLocation`, `devComments`, `devIcon`, `devFavorite`, `devAlertEvents`, `devAlertDown`, `devCanSleep`, `devSkipRepeated`, `devReqNicsOnline`, `devForceStatus`, `devParentMAC`, `devParentPort`, `devParentRelType`, `devSSID`, `devSite`, `devVlan`, `devStaticIP`, `devIsNew`, `devIsArchived`, `devCustomProps`.
|
||||
|
||||
**Request Body**:
|
||||
|
||||
@@ -190,6 +200,108 @@ Manage a **single device** by its MAC address. Operations include retrieval, upd
|
||||
|
||||
---
|
||||
|
||||
## 8. Lock / Unlock a Device Field
|
||||
|
||||
* **POST** `/device/<mac>/field/lock`
|
||||
Lock a field to prevent plugin overwrites, or unlock it to allow overwrites again.
|
||||
|
||||
**Request Body**:
|
||||
|
||||
```json
|
||||
{
|
||||
"fieldName": "devName",
|
||||
"lock": true
|
||||
}
|
||||
```
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|---|---|---|---|
|
||||
| `fieldName` | string | ✅ | Field to lock/unlock (e.g. `devName`, `devVendor`) |
|
||||
| `lock` | boolean | ❌ | `true` to lock, `false` to unlock (default when omitted) |
|
||||
|
||||
**Response** (success):
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"fieldName": "devName",
|
||||
"locked": true,
|
||||
"message": "Field devName locked"
|
||||
}
|
||||
```
|
||||
|
||||
**Error Responses**:
|
||||
|
||||
* Field does not support locking → HTTP 400
|
||||
* Unauthorized → HTTP 403
|
||||
|
||||
---
|
||||
|
||||
## 9. Unlock / Clear Device Fields (Bulk)
|
||||
|
||||
* **POST** `/devices/fields/unlock`
|
||||
Unlock fields (clear `LOCKED`/`USER` sources) for one device, a list of devices, or all devices.
|
||||
|
||||
**Request Body**:
|
||||
|
||||
```json
|
||||
{
|
||||
"mac": "AA:BB:CC:DD:EE:FF",
|
||||
"fields": ["devName", "devVendor"],
|
||||
"clearAll": false
|
||||
}
|
||||
```
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|---|---|---|---|
|
||||
| `mac` | string or array | ❌ | Single MAC, list of MACs, or omit for all devices |
|
||||
| `fields` | array of strings | ❌ | Fields to unlock. Omit to unlock all tracked fields |
|
||||
| `clearAll` | boolean | ❌ | `true` clears all sources; `false` (default) clears only `LOCKED`/`USER` |
|
||||
|
||||
**Response** (success):
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true
|
||||
}
|
||||
```
|
||||
|
||||
**Error Responses**:
|
||||
|
||||
* `fields` is not a list → HTTP 400
|
||||
* Unauthorized → HTTP 403
|
||||
|
||||
---
|
||||
|
||||
## 10. Set Device Alias
|
||||
|
||||
* **POST** `/device/<mac>/set-alias`
|
||||
Convenience wrapper to update the device display name (`devName`).
|
||||
|
||||
**Request Body**:
|
||||
|
||||
```json
|
||||
{
|
||||
"alias": "My Router"
|
||||
}
|
||||
```
|
||||
|
||||
**Response** (success):
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true
|
||||
}
|
||||
```
|
||||
|
||||
**Error Responses**:
|
||||
|
||||
* Missing `alias` → HTTP 400
|
||||
* Device not found → HTTP 404
|
||||
* Unauthorized → HTTP 403
|
||||
|
||||
---
|
||||
|
||||
## Example `curl` Requests
|
||||
|
||||
**Get Device Details**:
|
||||
@@ -233,3 +345,30 @@ curl -X POST "http://<server_ip>:<GRAPHQL_PORT>/device/AA:BB:CC:DD:EE:FF/update-
|
||||
--data '{"columnName":"devName","columnValue":"Updated Device"}'
|
||||
```
|
||||
|
||||
**Lock a Field**:
|
||||
|
||||
```bash
|
||||
curl -X POST "http://<server_ip>:<GRAPHQL_PORT>/device/AA:BB:CC:DD:EE:FF/field/lock" \
|
||||
-H "Authorization: Bearer <API_TOKEN>" \
|
||||
-H "Content-Type: application/json" \
|
||||
--data '{"fieldName":"devName","lock":true}'
|
||||
```
|
||||
|
||||
**Unlock Fields (all devices)**:
|
||||
|
||||
```bash
|
||||
curl -X POST "http://<server_ip>:<GRAPHQL_PORT>/devices/fields/unlock" \
|
||||
-H "Authorization: Bearer <API_TOKEN>" \
|
||||
-H "Content-Type: application/json" \
|
||||
--data '{"fields":["devName","devVendor"]}'
|
||||
```
|
||||
|
||||
**Set Device Alias**:
|
||||
|
||||
```bash
|
||||
curl -X POST "http://<server_ip>:<GRAPHQL_PORT>/device/AA:BB:CC:DD:EE:FF/set-alias" \
|
||||
-H "Authorization: Bearer <API_TOKEN>" \
|
||||
-H "Content-Type: application/json" \
|
||||
--data '{"alias":"My Router"}'
|
||||
```
|
||||
|
||||
|
||||
@@ -87,6 +87,7 @@ Frequent scans increase resource usage, network traffic, and database read/write
|
||||
* **Increase scan intervals** (`<PLUGIN>_RUN_SCHD`) on busy networks or low-end hardware.
|
||||
* **Increase timeouts** (`<PLUGIN>_RUN_TIMEOUT`) to avoid plugin failures.
|
||||
* **Reduce subnet size** – e.g., use `/24` instead of `/16` to reduce scan load.
|
||||
* **Enable the deep sleep setting** (`DEEP_SLEEP`) – Lowers CPU usage by extending idle wait times between processing cycles. When enabled, scans may be delayed by up to 1 minute and the UI might become less responsive.
|
||||
|
||||
Some plugins also include options to limit which devices are scanned. If certain plugins consistently run long, consider narrowing their scope.
|
||||
|
||||
|
||||
@@ -57,6 +57,7 @@ Device-detecting plugins insert values into the `CurrentScan` database table. T
|
||||
| `DHCPSRVS` | [dhcp_servers](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/dhcp_servers/) | ♻ | DHCP servers | | |
|
||||
| `DIGSCAN` | [dig_scan](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/dig_scan/) | 🆎 | Dig (DNS) Name resolution | | |
|
||||
| `FREEBOX` | [freebox](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/freebox/) | 🔍/♻/🆎 | Pull data and names from Freebox/Iliadbox | | |
|
||||
| `FRITZBOX` | [fritzbox](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/fritzbox/) | 🔍 | Fritz!Box device scanner via TR-064 | | |
|
||||
| `ICMP` | [icmp_scan](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/icmp_scan/) | ♻ | ICMP (ping) status checker | | |
|
||||
| `INTRNT` | [internet_ip](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/internet_ip/) | 🔍 | Internet IP scanner | | |
|
||||
| `INTRSPD` | [internet_speedtest](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/internet_speedtest/) | ♻ | Internet speed test | | |
|
||||
|
||||
@@ -33,19 +33,19 @@ VPNs use virtual interfaces (e.g., `tun0`, `tap0`) to encapsulate traffic, bypas
|
||||
|
||||
> **Possible workaround**: Configure the VPN to bridge networks instead of routing to enable ARP, though this depends on the VPN setup and security requirements.
|
||||
|
||||
# Other Workarounds
|
||||
## Other Workarounds
|
||||
|
||||
The following workarounds should work for most complex network setups.
|
||||
|
||||
## Supplementing Plugins
|
||||
### Supplementing Plugins
|
||||
|
||||
You can use supplementary plugins that employ alternate methods. Protocols used by the `SNMPDSC` or `DHCPLSS` plugins are widely supported on different routers and can be effective as workarounds. Check the [plugins list](./PLUGINS.md) to find a plugin that works with your router and network setup.
|
||||
|
||||
## Multiple NetAlertX Instances
|
||||
### Multiple NetAlertX Instances
|
||||
|
||||
If you have servers in different networks, you can set up separate NetAlertX instances on those subnets and synchronize the results into one instance using the [`SYNC` plugin](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/sync).
|
||||
|
||||
## Manual Entry
|
||||
### Manual Entry
|
||||
|
||||
If you don't need to discover new devices and only need to report on their status (`online`, `offline`, `down`), you can manually enter devices and check their status using the [`ICMP` plugin](https://github.com/netalertx/NetAlertX/blob/main/front/plugins/icmp_scan/), which uses the `ping` command internally.
|
||||
|
||||
@@ -53,7 +53,7 @@ For more information on how to add devices manually (or dummy devices), refer to
|
||||
|
||||
To create truly dummy devices, you can use a loopback IP address (e.g., `0.0.0.0` or `127.0.0.1`) or the `Force Status` field so they appear online.
|
||||
|
||||
## NMAP and Fake MAC Addresses
|
||||
### NMAP and Fake MAC Addresses
|
||||
|
||||
Scanning remote networks with NMAP is possible (via the `NMAPDEV` plugin), but since it cannot retrieve the MAC address, you need to enable the `NMAPDEV_FAKE_MAC` setting. This will generate a fake MAC address based on the IP address, allowing you to track devices. However, this can lead to inconsistencies, especially if the IP address changes or a previously logged device is rediscovered. If this setting is disabled, only the IP address will be discovered, and devices with missing MAC addresses will be skipped.
|
||||
|
||||
|
||||
@@ -8,8 +8,15 @@ You need to specify the network interface and the network mask. You can also con
|
||||
> If you don't see all expected devices run the following command in the NetAlertX container (replace the interface and ip mask):
|
||||
> `sudo arp-scan --interface=eth0 192.168.1.0/24`
|
||||
>
|
||||
> If this command returns no results, the network is not accessible due to your network or firewall restrictions (Wi-Fi Extenders, VPNs and inaccessible networks). If direct scans are not possible, check the [remote networks documentation](./REMOTE_NETWORKS.md) for workarounds.
|
||||
|
||||
> If this command returns no results:
|
||||
>
|
||||
> - ✅ If you see output like `IPv4: (none)` or `Using 0.0.0.0`:
|
||||
> - The interface was not detected correctly.
|
||||
> - Fix: explicitly set the interface using `--interface=<name>`.
|
||||
>
|
||||
> - ❌ If the scan runs correctly but still finds no devices:
|
||||
> - The network may not be accessible due to firewall, VLAN, or network restrictions (Wi-Fi extenders, VPNs, etc.).
|
||||
> - If direct scans are not possible, check the [remote networks documentation](./REMOTE_NETWORKS.md) for workarounds.
|
||||
|
||||
## Example Values
|
||||
|
||||
|
||||
@@ -1413,15 +1413,48 @@ textarea[readonly],
|
||||
|
||||
|
||||
#columnFilters {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px; /* Add spacing between items */
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(125px, 1fr));
|
||||
gap: 0.75em;
|
||||
padding: 0.5em 0;
|
||||
}
|
||||
|
||||
#columnFilters::before,
|
||||
#columnFilters::after {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.filter-group {
|
||||
box-sizing: border-box; /* Ensure padding and borders are included in the width */
|
||||
padding: 1em;
|
||||
padding-top: 0;
|
||||
box-sizing: border-box;
|
||||
padding: 0.4em;
|
||||
margin: 0;
|
||||
border-radius: 3px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
gap: 0.15em;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.filter-group label {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
border-radius: 3px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
gap: 0.15em;
|
||||
white-space: normal;
|
||||
padding-left: 15px;
|
||||
padding-right: 0px;
|
||||
}
|
||||
|
||||
.filter-dropdown {
|
||||
width: 100%;
|
||||
}
|
||||
.filter-group select {
|
||||
margin-left: 15px;
|
||||
padding-right: 0px;
|
||||
}
|
||||
|
||||
.filter-dropdown
|
||||
|
||||
@@ -31,6 +31,12 @@
|
||||
<script>
|
||||
|
||||
function loadEventsData() {
|
||||
const mac = getMac();
|
||||
if (!mac) {
|
||||
console.warn("loadEventsData: mac not set, skipping");
|
||||
return;
|
||||
}
|
||||
|
||||
const hideConnections = $('#chkHideConnectionEvents')[0].checked;
|
||||
|
||||
let period = $("#period").val();
|
||||
@@ -65,7 +71,7 @@ function loadEventsData() {
|
||||
query,
|
||||
variables: {
|
||||
options: {
|
||||
eveMac: mac,
|
||||
eveMac: mac, // local const from getMac() above
|
||||
dateFrom: start,
|
||||
dateTo: end,
|
||||
limit: 500,
|
||||
@@ -163,6 +169,11 @@ function initDeviceEventsPage()
|
||||
return; // exit early if nothing is visible
|
||||
}
|
||||
|
||||
// Only proceed if mac is available
|
||||
if (!getMac()) {
|
||||
return; // exit early if mac is not yet set
|
||||
}
|
||||
|
||||
// init page once
|
||||
if (eventsPageInitialized) return; // ENSURE ONCE
|
||||
eventsPageInitialized = true;
|
||||
|
||||
@@ -430,28 +430,40 @@ function initFilters() {
|
||||
filters: []
|
||||
};
|
||||
|
||||
// Group data by columnName
|
||||
resultJSON.forEach(entry => {
|
||||
const existingFilter = transformed.filters.find(filter => filter.column === entry.columnName);
|
||||
// Build filters in the exact order of columnFilters
|
||||
columnFilters.forEach(([columnName, headerKey]) => {
|
||||
// Get matching entries for this column
|
||||
const entries = resultJSON.filter(e => e.columnName === columnName);
|
||||
|
||||
if (existingFilter) {
|
||||
// Add the unique columnValue to options if not already present
|
||||
if (!existingFilter.options.includes(entry.columnValue)) {
|
||||
existingFilter.options.push(entry.columnValue);
|
||||
if (entries.length === 0) return;
|
||||
|
||||
// Build options (unique)
|
||||
const optionsMap = new Map();
|
||||
|
||||
entries.forEach(entry => {
|
||||
const value = entry.columnValue;
|
||||
const label = entry.columnLabel || value;
|
||||
|
||||
if (!optionsMap.has(value)) {
|
||||
optionsMap.set(value, { value, label });
|
||||
}
|
||||
} else {
|
||||
// Create a new filter entry
|
||||
transformed.filters.push({
|
||||
column: entry.columnName,
|
||||
headerKey: entry.columnHeaderStringKey,
|
||||
options: [entry.columnValue]
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const options = Array.from(optionsMap.values());
|
||||
|
||||
// Sort options alphabetically
|
||||
options.sort((a, b) => a.label.localeCompare(b.label));
|
||||
|
||||
transformed.filters.push({
|
||||
column: columnName,
|
||||
headerKey: headerKey,
|
||||
options: options
|
||||
});
|
||||
});
|
||||
|
||||
// Sort options alphabetically for better readability
|
||||
// Sort options alphabetically by label for better readability
|
||||
transformed.filters.forEach(filter => {
|
||||
filter.options.sort();
|
||||
filter.options.sort((a, b) => a.label.localeCompare(b.label));
|
||||
});
|
||||
|
||||
// Output the result
|
||||
|
||||
@@ -126,7 +126,7 @@ function isAppInitialized() {
|
||||
|
||||
lang_shouldBeCompletedCalls = getLangCode() == 'en_us' ? 1 : 2;
|
||||
|
||||
// check if each ajax call completed succesfully
|
||||
// check if each ajax call completed successfully
|
||||
for (const call_name of completedCalls_final) {
|
||||
if (getCache(CACHE_KEYS.initFlag(call_name)) != "true") {
|
||||
_isAppInitLog(`[isAppInitialized] waiting on ${call_name} (value: ${getCache(CACHE_KEYS.initFlag(call_name))})`);
|
||||
@@ -268,7 +268,7 @@ setTimeout(() => {
|
||||
// page refresh if configured
|
||||
const refreshTime = getSetting("UI_REFRESH");
|
||||
if (refreshTime && refreshTime !== "0" && refreshTime !== "") {
|
||||
console.log("Refreshing page becasue UI_REFRESH setting enabled.");
|
||||
console.log("Refreshing page because UI_REFRESH setting enabled.");
|
||||
newTimerRefreshData(clearCache, parseInt(refreshTime)*1000);
|
||||
}
|
||||
|
||||
|
||||
@@ -156,7 +156,15 @@ function loadDeviceTable({ sql, containerSelector, tableId, wrapperHtml = null,
|
||||
{
|
||||
title: getString('Network_Table_IP'),
|
||||
data: 'devLastIP',
|
||||
width: '5%'
|
||||
width: '5%',
|
||||
render: function (ip, type) {
|
||||
if (type === 'sort') {
|
||||
// Convert each octet to a zero-padded 3-digit string for correct numeric sort
|
||||
if (!ip) return '';
|
||||
return ip.split('.').map(o => o.padStart(3, '0')).join('.');
|
||||
}
|
||||
return ip || '';
|
||||
}
|
||||
},
|
||||
{
|
||||
title: getString('Device_TableHead_Port'),
|
||||
|
||||
@@ -590,6 +590,7 @@ function addOptionFromModalInput() {
|
||||
* A MAC is considered fake if it starts with:
|
||||
* - "FA:CE" (new synthetic devices)
|
||||
* - "00:1A" (legacy placeholder devices)
|
||||
* - "02:" (legacy placeholder devices)
|
||||
*
|
||||
* The check is case-insensitive.
|
||||
*
|
||||
@@ -600,8 +601,8 @@ function isFakeMac(macAddress) {
|
||||
// Normalize to lowercase for consistent comparison
|
||||
macAddress = macAddress.toLowerCase();
|
||||
|
||||
// Check if MAC starts with FA:CE or 00:1a
|
||||
return macAddress.startsWith("fa:ce") || macAddress.startsWith("00:1a");
|
||||
// Check if MAC starts with FA:CE or 00:1a or 02:
|
||||
return macAddress.startsWith("fa:ce") || macAddress.startsWith("00:1a") || macAddress.startsWith("02:");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -10,9 +10,18 @@ require_once $_SERVER['DOCUMENT_ROOT'] . '/php/templates/language/lang.php';
|
||||
function renderFilterDropdown($headerKey, $columnName, $values) {
|
||||
// Generate dropdown options
|
||||
$optionsHtml = '<option value="" selected>All</option>'; // Default "All" option
|
||||
foreach ($values as $value) {
|
||||
$escapedValue = htmlspecialchars($value);
|
||||
$optionsHtml .= '<option value="' . $escapedValue . '">' . $escapedValue . '</option>';
|
||||
foreach ($values as $item) {
|
||||
// Support both {value, label} objects and plain strings (backward compat)
|
||||
if (is_array($item)) {
|
||||
$val = $item['value'] ?? '';
|
||||
$label = $item['label'] ?? $val;
|
||||
} else {
|
||||
$val = $item;
|
||||
$label = $item;
|
||||
}
|
||||
$escapedValue = htmlspecialchars($val);
|
||||
$escapedLabel = htmlspecialchars($label);
|
||||
$optionsHtml .= '<option value="' . $escapedValue . '">' . $escapedLabel . '</option>';
|
||||
}
|
||||
|
||||
// Generate the dropdown HTML
|
||||
|
||||
@@ -66,6 +66,8 @@
|
||||
"CustProps_cant_remove": "لا يمكن إزالة الخاصية المخصصة",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "عدد الأيام للاحتفاظ بسجلات الأحداث",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "مدة الاحتفاظ بالأحداث",
|
||||
"DEEP_SLEEP_description": "",
|
||||
"DEEP_SLEEP_name": "",
|
||||
"DISCOVER_PLUGINS_description": "اكتشاف المكونات الإضافية المتاحة",
|
||||
"DISCOVER_PLUGINS_name": "اكتشاف المكونات الإضافية",
|
||||
"DevDetail_Children_Title": "علاقات الأطفال",
|
||||
@@ -344,6 +346,7 @@
|
||||
"Gen_LockedDB": "قاعدة البيانات مقفلة",
|
||||
"Gen_NetworkMask": "قناع الشبكة",
|
||||
"Gen_New": "",
|
||||
"Gen_No_Data": "",
|
||||
"Gen_Offline": "غير متصل",
|
||||
"Gen_Okay": "موافق",
|
||||
"Gen_Online": "متصل",
|
||||
|
||||
@@ -66,6 +66,8 @@
|
||||
"CustProps_cant_remove": "No es pot eliminar, es necessita una propietat mínim.",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "Això és una configuració de manteniment. Especifica el nombre de dies que es conservaran els esdeveniments. Els esdeveniments antics s'esborraran periòdicament. També aplica als esdeveniments dels Connectors (Plugins).",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "Esborrar esdeveniments més vells de",
|
||||
"DEEP_SLEEP_description": "",
|
||||
"DEEP_SLEEP_name": "",
|
||||
"DISCOVER_PLUGINS_description": "Desactiva aquesta opció per accelerar la inicialització i l'estalvi de configuració. Quan està desactivat, els connectors no es descobreixen, i no podeu afegir nous connectors a la configuració <code>LOADED_PLUGINS</code>.",
|
||||
"DISCOVER_PLUGINS_name": "Descobreix els plugins",
|
||||
"DevDetail_Children_Title": "Relacions filles",
|
||||
@@ -203,17 +205,17 @@
|
||||
"Device_MultiEdit_MassActions": "Accions massives:",
|
||||
"Device_MultiEdit_No_Devices": "Cap dispositiu seleccionat.",
|
||||
"Device_MultiEdit_Tooltip": "Atenció. Si feu clic a això s'aplicarà el valor de l'esquerra a tots els dispositius seleccionats a dalt.",
|
||||
"Device_NextScan_Imminent": "",
|
||||
"Device_NextScan_In": "",
|
||||
"Device_NoData_Help": "",
|
||||
"Device_NoData_Scanning": "",
|
||||
"Device_NoData_Title": "",
|
||||
"Device_NoMatch_Title": "",
|
||||
"Device_NextScan_Imminent": "Imminent...",
|
||||
"Device_NextScan_In": "Proper scan en prop de ",
|
||||
"Device_NoData_Help": "Si no surten dispositius desprès del scan, comproveu la configuracio de SCAN_SUBNETS i <a href=\"https://docs.netalertx.com/SUBNETS\" target=\"_blank\">documentacio</a>.",
|
||||
"Device_NoData_Scanning": "Esperant el primer scan - això pot trigar alguns minuts desprès de la configuració inicial.",
|
||||
"Device_NoData_Title": "Encara no s'han trobat dispositius",
|
||||
"Device_NoMatch_Title": "No hi ha cap dispositiu que compleixi el filtre",
|
||||
"Device_Save_Failed": "Problemes guardant el dispositiu",
|
||||
"Device_Save_Unauthorized": "Token invàlid - No autoritzat",
|
||||
"Device_Saved_Success": "S'ha guardat el dispositiu",
|
||||
"Device_Saved_Unexpected": "Actualització de dispositiu ha retornat una resposta no esperada",
|
||||
"Device_Scanning": "",
|
||||
"Device_Scanning": "Escanejant...",
|
||||
"Device_Searchbox": "Cerca",
|
||||
"Device_Shortcut_AllDevices": "Els meus dispositius",
|
||||
"Device_Shortcut_AllNodes": "Tots els nodes",
|
||||
@@ -232,7 +234,7 @@
|
||||
"Device_TableHead_FQDN": "FQDN",
|
||||
"Device_TableHead_Favorite": "Favorit",
|
||||
"Device_TableHead_FirstSession": "Primera Sessió",
|
||||
"Device_TableHead_Flapping": "",
|
||||
"Device_TableHead_Flapping": "Flapping",
|
||||
"Device_TableHead_GUID": "GUID",
|
||||
"Device_TableHead_Group": "Grup",
|
||||
"Device_TableHead_IPv4": "IPv4",
|
||||
@@ -323,7 +325,7 @@
|
||||
"Gen_AddDevice": "Afegir dispositiu",
|
||||
"Gen_Add_All": "Afegeix tot",
|
||||
"Gen_All_Devices": "Tots els dispositius",
|
||||
"Gen_Archived": "",
|
||||
"Gen_Archived": "Arxivat",
|
||||
"Gen_AreYouSure": "Estàs segur?",
|
||||
"Gen_Backup": "Executar Backup",
|
||||
"Gen_Cancel": "Cancel·lar",
|
||||
@@ -334,16 +336,17 @@
|
||||
"Gen_Delete": "Esborrar",
|
||||
"Gen_DeleteAll": "Esborrar tot",
|
||||
"Gen_Description": "Descripció",
|
||||
"Gen_Down": "",
|
||||
"Gen_Down": "Baix",
|
||||
"Gen_Error": "Error",
|
||||
"Gen_Filter": "Filtrar",
|
||||
"Gen_Flapping": "",
|
||||
"Gen_Flapping": "Flapping",
|
||||
"Gen_Generate": "Generar",
|
||||
"Gen_InvalidMac": "Mac address invàlida.",
|
||||
"Gen_Invalid_Value": "S'ha introduït un valor incorrecte",
|
||||
"Gen_LockedDB": "ERROR - DB podria estar bloquejada - Fes servir F12 Eines desenvolupament -> Consola o provar-ho més tard.",
|
||||
"Gen_NetworkMask": "Màscara de xarxa",
|
||||
"Gen_New": "",
|
||||
"Gen_New": "Nou",
|
||||
"Gen_No_Data": "",
|
||||
"Gen_Offline": "Fora de línia",
|
||||
"Gen_Okay": "Ok",
|
||||
"Gen_Online": "En línia",
|
||||
@@ -361,7 +364,7 @@
|
||||
"Gen_SelectIcon": "<i class=\"fa-solid fa-chevron-down fa-fade\"></i>",
|
||||
"Gen_SelectToPreview": "Seleccioneu la vista prèvia",
|
||||
"Gen_Selected_Devices": "Dispositius seleccionats:",
|
||||
"Gen_Sleeping": "",
|
||||
"Gen_Sleeping": "Dormint",
|
||||
"Gen_Subnet": "Subxarxa",
|
||||
"Gen_Switch": "Switch",
|
||||
"Gen_Upd": "Actualitzat correctament",
|
||||
@@ -591,8 +594,8 @@
|
||||
"PIALERT_WEB_PROTECTION_name": "Activa l'accés",
|
||||
"PLUGINS_KEEP_HIST_description": "Quantes entrades de Plugins s'han de mantenir a la història (per Plugin, no per dispositiu).",
|
||||
"PLUGINS_KEEP_HIST_name": "Història dels Plugins",
|
||||
"PRAGMA_JOURNAL_SIZE_LIMIT_description": "",
|
||||
"PRAGMA_JOURNAL_SIZE_LIMIT_name": "",
|
||||
"PRAGMA_JOURNAL_SIZE_LIMIT_description": "SQLite WAL (Write-Ahead Log) mida màxima en MB abans de desencadenar punts de verificació automàtics. Els valors més baixos (10-20 MB) redueixen l'ús del disc / emmagatzematge, però augmenten l'ús de la CPU durant les exploracions. Els valors més alts (50-100 MB) redueixen els pics de CPU durant les operacions, però poden utilitzar més memòria RAM i espai de disc. Default <code>50 MB</code> saldos ambdós. Útil per a sistemes formats per recursos com dispositius NAS amb targetes SD. Preguntes Freqüents - FAQ.",
|
||||
"PRAGMA_JOURNAL_SIZE_LIMIT_name": "Límit de mida WAL (MB)",
|
||||
"Plugins_DeleteAll": "Elimina tot (s'ignoraran els filtres)",
|
||||
"Plugins_Filters_Mac": "Filtre de MAC",
|
||||
"Plugins_History": "Historial d'Esdeveniments",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"API_CUSTOM_SQL_description": "",
|
||||
"API_CUSTOM_SQL_name": "",
|
||||
"API_TOKEN_description": "",
|
||||
"API_CUSTOM_SQL_description": "Můžete specifikovat vlastní SQL dotaz, který vygeneruje JSON soubor a následně ho vystaví přes <a href=\"/php/server/query_json.php?file=table_custom_endpoint.json\" target=\"_blank\"><code>table_custom_endpoint.json</code> souborový endpoint</a>.",
|
||||
"API_CUSTOM_SQL_name": "Vlastní endpoint",
|
||||
"API_TOKEN_description": "API token pro zabezpečenou komunikaci. Vygenerujte ho, nebo zadejte jakoukoliv hodnotu. Je odesílán v hlavičce requestu a použit v <code>SYNC</code> pluginu, GraphQL serveru a dalších API endpointech. Můžete použít API endpointy pro vytvoření vlastních integrací, jak je popsáno v <a href=\"https://docs.netalertx.com/API\" target=\"_blank\">API dokumentaci</a>.",
|
||||
"API_TOKEN_name": "API token",
|
||||
"API_display_name": "API",
|
||||
"API_icon": "<i class=\"fa fa-arrow-down-up-across-line\"></i>",
|
||||
@@ -9,341 +9,344 @@
|
||||
"About_Exit": "Odhlásit",
|
||||
"About_Title": "Scanner síťové bezpečnosti a framework pro upozornění",
|
||||
"AppEvents_AppEventProcessed": "Zpracováno",
|
||||
"AppEvents_DateTimeCreated": "Zaznamenáno",
|
||||
"AppEvents_DateTimeCreated": "Zalogováno",
|
||||
"AppEvents_Extra": "Extra",
|
||||
"AppEvents_GUID": "",
|
||||
"AppEvents_Helper1": "",
|
||||
"AppEvents_Helper2": "",
|
||||
"AppEvents_Helper3": "",
|
||||
"AppEvents_GUID": "GUID aplikační události",
|
||||
"AppEvents_Helper1": "Pomocník 1",
|
||||
"AppEvents_Helper2": "Pomocník 2",
|
||||
"AppEvents_Helper3": "Pomocník 3",
|
||||
"AppEvents_ObjectForeignKey": "Cizí klíč",
|
||||
"AppEvents_ObjectIndex": "Index",
|
||||
"AppEvents_ObjectIsArchived": "",
|
||||
"AppEvents_ObjectIsNew": "",
|
||||
"AppEvents_ObjectPlugin": "",
|
||||
"AppEvents_ObjectIsArchived": "Archivováno (dlouhodobě)",
|
||||
"AppEvents_ObjectIsNew": "Nové (dlouhodobě)",
|
||||
"AppEvents_ObjectPlugin": "Navázaný Plugin",
|
||||
"AppEvents_ObjectPrimaryID": "Primární ID",
|
||||
"AppEvents_ObjectSecondaryID": "Sekundární ID",
|
||||
"AppEvents_ObjectStatus": "",
|
||||
"AppEvents_ObjectStatusColumn": "",
|
||||
"AppEvents_ObjectType": "",
|
||||
"AppEvents_Plugin": "Zásuvný modul",
|
||||
"AppEvents_ObjectStatus": "Logovaný stav",
|
||||
"AppEvents_ObjectStatusColumn": "Stavový sloupec",
|
||||
"AppEvents_ObjectType": "Typ Objektu",
|
||||
"AppEvents_Plugin": "Plugin",
|
||||
"AppEvents_Type": "Typ",
|
||||
"BACKEND_API_URL_description": "",
|
||||
"BACKEND_API_URL_name": "",
|
||||
"BackDevDetail_Actions_Ask_Run": "",
|
||||
"BackDevDetail_Actions_Not_Registered": "",
|
||||
"BACKEND_API_URL_description": "Použito pro umožnění komunikace frontendu s backendem. Výchozí hodnota je <code>/server</code> , která by neměla být měněna.",
|
||||
"BACKEND_API_URL_name": "URL API backendu",
|
||||
"BackDevDetail_Actions_Ask_Run": "Chcete akci spustit?",
|
||||
"BackDevDetail_Actions_Not_Registered": "Akce není zaregistrována: ",
|
||||
"BackDevDetail_Actions_Title_Run": "Spustit akci",
|
||||
"BackDevDetail_Copy_Ask": "",
|
||||
"BackDevDetail_Copy_Title": "",
|
||||
"BackDevDetail_Tools_WOL_error": "",
|
||||
"BackDevDetail_Tools_WOL_okay": "",
|
||||
"BackDevices_Arpscan_disabled": "",
|
||||
"BackDevices_Arpscan_enabled": "",
|
||||
"BackDevices_Backup_CopError": "",
|
||||
"BackDevices_Backup_Failed": "",
|
||||
"BackDevices_Backup_okay": "",
|
||||
"BackDevices_DBTools_DelDevError_a": "",
|
||||
"BackDevices_DBTools_DelDevError_b": "",
|
||||
"BackDevices_DBTools_DelDev_a": "",
|
||||
"BackDevices_DBTools_DelDev_b": "",
|
||||
"BackDevices_DBTools_DelEvents": "",
|
||||
"BackDevices_DBTools_DelEventsError": "",
|
||||
"BackDevices_DBTools_ImportCSV": "",
|
||||
"BackDevices_DBTools_ImportCSVError": "",
|
||||
"BackDevices_DBTools_ImportCSVMissing": "",
|
||||
"BackDevices_DBTools_Purge": "",
|
||||
"BackDevices_DBTools_UpdDev": "",
|
||||
"BackDevices_DBTools_UpdDevError": "",
|
||||
"BackDevices_DBTools_Upgrade": "",
|
||||
"BackDevices_DBTools_UpgradeError": "",
|
||||
"BackDevices_Device_UpdDevError": "",
|
||||
"BackDevices_Restore_CopError": "",
|
||||
"BackDevices_Restore_Failed": "",
|
||||
"BackDevices_Restore_okay": "",
|
||||
"BackDevices_darkmode_disabled": "",
|
||||
"BackDevices_darkmode_enabled": "",
|
||||
"CLEAR_NEW_FLAG_description": "",
|
||||
"CLEAR_NEW_FLAG_name": "",
|
||||
"CustProps_cant_remove": "",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "",
|
||||
"DISCOVER_PLUGINS_description": "",
|
||||
"DISCOVER_PLUGINS_name": "",
|
||||
"DevDetail_Children_Title": "",
|
||||
"DevDetail_Copy_Device_Title": "",
|
||||
"DevDetail_Copy_Device_Tooltip": "",
|
||||
"DevDetail_CustomProperties_Title": "",
|
||||
"DevDetail_CustomProps_reset_info": "",
|
||||
"DevDetail_DisplayFields_Title": "",
|
||||
"DevDetail_EveandAl_AlertAllEvents": "",
|
||||
"DevDetail_EveandAl_AlertDown": "",
|
||||
"BackDevDetail_Copy_Ask": "Zkopírovat detaily zařízení z výběru (vše na této stránce bude přepsáno)?",
|
||||
"BackDevDetail_Copy_Title": "Zkopírovat detaily",
|
||||
"BackDevDetail_Tools_WOL_error": "Příkaz NEBYL proveden.",
|
||||
"BackDevDetail_Tools_WOL_okay": "Příkaz byl proveden.",
|
||||
"BackDevices_Arpscan_disabled": "ARP-Scan zakázán",
|
||||
"BackDevices_Arpscan_enabled": "ARP-Scan povolen",
|
||||
"BackDevices_Backup_CopError": "Původní databázi se nepodařilo uložit.",
|
||||
"BackDevices_Backup_Failed": "Záloha byla privedena částečně úspěšně. Archiv nemohl být vytvořen nebo je prázdný.",
|
||||
"BackDevices_Backup_okay": "Záloha byla provedena úspěšně s novým archivem",
|
||||
"BackDevices_DBTools_DelDevError_a": "Chyba při odstranění zařízení",
|
||||
"BackDevices_DBTools_DelDevError_b": "Chyba při odstranění zařízení",
|
||||
"BackDevices_DBTools_DelDev_a": "Zařízení odstraněno",
|
||||
"BackDevices_DBTools_DelDev_b": "Zařízení odstraněna",
|
||||
"BackDevices_DBTools_DelEvents": "Události odstraněny",
|
||||
"BackDevices_DBTools_DelEventsError": "Chyba při odstraňování událostí",
|
||||
"BackDevices_DBTools_ImportCSV": "Zařízení z CSV souboru byla úspěšně importována.",
|
||||
"BackDevices_DBTools_ImportCSVError": "CSV soubor nemohl být importován. Ujistěte se, že je formát správný.",
|
||||
"BackDevices_DBTools_ImportCSVMissing": "CSV soubor <b>/config/devices.csv</b> nebyl nalezen.",
|
||||
"BackDevices_DBTools_Purge": "Nejstarší zálohy byly odstraněny",
|
||||
"BackDevices_DBTools_UpdDev": "Zařízení úspěšně aktualizováno. Hlavní seznam zařízení vyžaduje nějaký čas k obnovení, pokud probíhá scan.",
|
||||
"BackDevices_DBTools_UpdDevError": "Chyba aktualizace zařízení",
|
||||
"BackDevices_DBTools_Upgrade": "Databáze byla úspěšně upgradována",
|
||||
"BackDevices_DBTools_UpgradeError": "Chyba při upgradu databáze",
|
||||
"BackDevices_Device_UpdDevError": "Chyba při aktualizaci zařízení, zkuste to později. Databáze je pravděpodobně uzamčena z důvodu jiné probíhající úlohy.",
|
||||
"BackDevices_Restore_CopError": "Původní databázi se nepodařilo uložit.",
|
||||
"BackDevices_Restore_Failed": "Obnova selhala. Prosím, obnovte zálohu ručně.",
|
||||
"BackDevices_Restore_okay": "Obnova úspěšně provedena.",
|
||||
"BackDevices_darkmode_disabled": "Tmavý režim zakázán",
|
||||
"BackDevices_darkmode_enabled": "Tmavý režim povolen",
|
||||
"CLEAR_NEW_FLAG_description": "Pokud je povoleno (<code>0</code> je zakázáno), zařízením označeným jako <b>Nové Zařízení</b> bude tento příznak odebrán, pokud časový limit (udaný v hodinách) překročí jejich čas <b>První Session</b>.",
|
||||
"CLEAR_NEW_FLAG_name": "Odebrat příznak nového",
|
||||
"CustProps_cant_remove": "Nelze odebrat, je vyžadována alespoň jedna položka.",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "Toto je nastavení údržby. Určuje počet dní, po které budou záznamy události uchovávány. Všechny starší události budou periodicky odstraněny. Platí také pro Historii Událostí Pluginů.",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "Odstranit události starší než",
|
||||
"DEEP_SLEEP_description": "Snižuje využití CPU prodloužením čekacích časů mezi cykly zpracování. Pokud je povoleno, skeny mohou být opožděny až o 1 minutu a UI může být méně responzivní.",
|
||||
"DEEP_SLEEP_name": "Hluboký spánek",
|
||||
"DISCOVER_PLUGINS_description": "Zakažte tuto volbu pro urychlení inicializace a ukládání nastavení. Když je volba zakázána, pluginy nejsou vyhledávány a nemůžete tak přidávat nové pluginy do nastavení <code>LOADED_PLUGINS</code>.",
|
||||
"DISCOVER_PLUGINS_name": "Vyhledat pluginy",
|
||||
"DevDetail_Children_Title": "Podřízené vazby",
|
||||
"DevDetail_Copy_Device_Title": "Zkopírovat detaily ze zařízení",
|
||||
"DevDetail_Copy_Device_Tooltip": "Zkopírovat detaily z vybraného zařízení. Všechno na této stránce bude přepsáno",
|
||||
"DevDetail_CustomProperties_Title": "Vlastní položky",
|
||||
"DevDetail_CustomProps_reset_info": "Tímto budou odebrány vlastní položky na tomto zařízení a dojde k resetu na výchozí hodnotu.",
|
||||
"DevDetail_DisplayFields_Title": "Zobrazit",
|
||||
"DevDetail_EveandAl_AlertAllEvents": "Hlásit události",
|
||||
"DevDetail_EveandAl_AlertDown": "Hlásit down",
|
||||
"DevDetail_EveandAl_Archived": "Archivováno",
|
||||
"DevDetail_EveandAl_NewDevice": "",
|
||||
"DevDetail_EveandAl_NewDevice_Tooltip": "",
|
||||
"DevDetail_EveandAl_RandomMAC": "",
|
||||
"DevDetail_EveandAl_ScanCycle": "",
|
||||
"DevDetail_EveandAl_ScanCycle_a": "",
|
||||
"DevDetail_EveandAl_ScanCycle_z": "",
|
||||
"DevDetail_EveandAl_Skip": "",
|
||||
"DevDetail_EveandAl_Title": "",
|
||||
"DevDetail_Events_CheckBox": "",
|
||||
"DevDetail_GoToNetworkNode": "",
|
||||
"DevDetail_EveandAl_NewDevice": "Nové zařízení",
|
||||
"DevDetail_EveandAl_NewDevice_Tooltip": "Zobrazí status Nový pro nové zařízení a zahrne je do seznamu s filtrem Nová zařízení. Nemá vliv na notifikace.",
|
||||
"DevDetail_EveandAl_RandomMAC": "Náhodná MAC",
|
||||
"DevDetail_EveandAl_ScanCycle": "Skenovat zařízení",
|
||||
"DevDetail_EveandAl_ScanCycle_a": "Skenovat zařízení",
|
||||
"DevDetail_EveandAl_ScanCycle_z": "Neskenovat zařízení",
|
||||
"DevDetail_EveandAl_Skip": "Vynechat opakování notifikací během",
|
||||
"DevDetail_EveandAl_Title": "Konfigurace notifikací",
|
||||
"DevDetail_Events_CheckBox": "Skrýt události připojení",
|
||||
"DevDetail_GoToNetworkNode": "Navigovat na Síťovou stránku uvedeného node.",
|
||||
"DevDetail_Icon": "Ikona",
|
||||
"DevDetail_Icon_Descr": "",
|
||||
"DevDetail_Icon_Descr": "Zadejte název ikony z Font Awesome bez prefixu \"fa-\", nebo s celou class, např. \"fa-brands\", \"fa-apple\", ...",
|
||||
"DevDetail_Loading": "Načítání…",
|
||||
"DevDetail_MainInfo_Comments": "Komentáře",
|
||||
"DevDetail_MainInfo_Favorite": "",
|
||||
"DevDetail_MainInfo_Group": "",
|
||||
"DevDetail_MainInfo_Location": "",
|
||||
"DevDetail_MainInfo_Name": "",
|
||||
"DevDetail_MainInfo_Network": "",
|
||||
"DevDetail_MainInfo_Network_Port": "",
|
||||
"DevDetail_MainInfo_Network_Site": "",
|
||||
"DevDetail_MainInfo_Network_Title": "",
|
||||
"DevDetail_MainInfo_Owner": "",
|
||||
"DevDetail_MainInfo_SSID": "",
|
||||
"DevDetail_MainInfo_Title": "",
|
||||
"DevDetail_MainInfo_Type": "",
|
||||
"DevDetail_MainInfo_Vendor": "",
|
||||
"DevDetail_MainInfo_mac": "",
|
||||
"DevDetail_NavToChildNode": "",
|
||||
"DevDetail_Network_Node_hover": "",
|
||||
"DevDetail_Network_Port_hover": "",
|
||||
"DevDetail_Nmap_Scans": "",
|
||||
"DevDetail_Nmap_Scans_desc": "",
|
||||
"DevDetail_Nmap_buttonDefault": "",
|
||||
"DevDetail_Nmap_buttonDefault_text": "",
|
||||
"DevDetail_Nmap_buttonDetail": "",
|
||||
"DevDetail_Nmap_buttonDetail_text": "",
|
||||
"DevDetail_Nmap_buttonFast": "",
|
||||
"DevDetail_Nmap_buttonFast_text": "",
|
||||
"DevDetail_Nmap_buttonSkipDiscovery": "",
|
||||
"DevDetail_Nmap_buttonSkipDiscovery_text": "",
|
||||
"DevDetail_Nmap_resultsLink": "",
|
||||
"DevDetail_Owner_hover": "",
|
||||
"DevDetail_Periodselect_All": "",
|
||||
"DevDetail_Periodselect_LastMonth": "",
|
||||
"DevDetail_Periodselect_LastWeek": "",
|
||||
"DevDetail_Periodselect_LastYear": "",
|
||||
"DevDetail_Periodselect_today": "",
|
||||
"DevDetail_Run_Actions_Title": "",
|
||||
"DevDetail_Run_Actions_Tooltip": "",
|
||||
"DevDetail_SessionInfo_FirstSession": "",
|
||||
"DevDetail_SessionInfo_LastIP": "",
|
||||
"DevDetail_SessionInfo_LastSession": "",
|
||||
"DevDetail_SessionInfo_StaticIP": "",
|
||||
"DevDetail_SessionInfo_Status": "",
|
||||
"DevDetail_SessionInfo_Title": "",
|
||||
"DevDetail_SessionTable_Additionalinfo": "",
|
||||
"DevDetail_SessionTable_Connection": "",
|
||||
"DevDetail_SessionTable_Disconnection": "",
|
||||
"DevDetail_SessionTable_Duration": "",
|
||||
"DevDetail_SessionTable_IP": "",
|
||||
"DevDetail_SessionTable_Order": "",
|
||||
"DevDetail_Shortcut_CurrentStatus": "",
|
||||
"DevDetail_Shortcut_DownAlerts": "",
|
||||
"DevDetail_Shortcut_Presence": "",
|
||||
"DevDetail_Shortcut_Sessions": "",
|
||||
"DevDetail_Tab_Details": "",
|
||||
"DevDetail_Tab_Events": "",
|
||||
"DevDetail_Tab_EventsTableDate": "",
|
||||
"DevDetail_Tab_EventsTableEvent": "",
|
||||
"DevDetail_Tab_EventsTableIP": "",
|
||||
"DevDetail_Tab_EventsTableInfo": "",
|
||||
"DevDetail_Tab_Nmap": "",
|
||||
"DevDetail_Tab_NmapEmpty": "",
|
||||
"DevDetail_Tab_NmapTableExtra": "",
|
||||
"DevDetail_Tab_NmapTableHeader": "",
|
||||
"DevDetail_Tab_NmapTableIndex": "",
|
||||
"DevDetail_Tab_NmapTablePort": "",
|
||||
"DevDetail_Tab_NmapTableService": "",
|
||||
"DevDetail_Tab_NmapTableState": "",
|
||||
"DevDetail_Tab_NmapTableText": "",
|
||||
"DevDetail_Tab_NmapTableTime": "",
|
||||
"DevDetail_Tab_Plugins": "",
|
||||
"DevDetail_Tab_Presence": "",
|
||||
"DevDetail_Tab_Sessions": "",
|
||||
"DevDetail_Tab_Tools": "",
|
||||
"DevDetail_Tab_Tools_Internet_Info_Description": "",
|
||||
"DevDetail_Tab_Tools_Internet_Info_Error": "",
|
||||
"DevDetail_Tab_Tools_Internet_Info_Start": "",
|
||||
"DevDetail_Tab_Tools_Internet_Info_Title": "",
|
||||
"DevDetail_Tab_Tools_Nslookup_Description": "",
|
||||
"DevDetail_Tab_Tools_Nslookup_Error": "",
|
||||
"DevDetail_Tab_Tools_Nslookup_Start": "",
|
||||
"DevDetail_Tab_Tools_Nslookup_Title": "",
|
||||
"DevDetail_Tab_Tools_Speedtest_Description": "",
|
||||
"DevDetail_Tab_Tools_Speedtest_Start": "",
|
||||
"DevDetail_Tab_Tools_Speedtest_Title": "",
|
||||
"DevDetail_Tab_Tools_Traceroute_Description": "",
|
||||
"DevDetail_Tab_Tools_Traceroute_Error": "",
|
||||
"DevDetail_Tab_Tools_Traceroute_Start": "",
|
||||
"DevDetail_Tab_Tools_Traceroute_Title": "",
|
||||
"DevDetail_Tools_WOL": "",
|
||||
"DevDetail_Tools_WOL_noti": "",
|
||||
"DevDetail_Tools_WOL_noti_text": "",
|
||||
"DevDetail_Type_hover": "",
|
||||
"DevDetail_Vendor_hover": "",
|
||||
"DevDetail_WOL_Title": "",
|
||||
"DevDetail_button_AddIcon": "",
|
||||
"DevDetail_button_AddIcon_Help": "",
|
||||
"DevDetail_button_AddIcon_Tooltip": "",
|
||||
"DevDetail_button_Delete": "",
|
||||
"DevDetail_button_DeleteEvents": "",
|
||||
"DevDetail_button_DeleteEvents_Warning": "",
|
||||
"DevDetail_button_Delete_ask": "",
|
||||
"DevDetail_button_OverwriteIcons": "",
|
||||
"DevDetail_button_OverwriteIcons_Tooltip": "",
|
||||
"DevDetail_button_OverwriteIcons_Warning": "",
|
||||
"DevDetail_button_Reset": "",
|
||||
"DevDetail_button_Save": "",
|
||||
"DeviceEdit_ValidMacIp": "",
|
||||
"Device_MultiEdit": "",
|
||||
"Device_MultiEdit_Backup": "",
|
||||
"Device_MultiEdit_Fields": "",
|
||||
"Device_MultiEdit_MassActions": "",
|
||||
"Device_MultiEdit_No_Devices": "",
|
||||
"Device_MultiEdit_Tooltip": "",
|
||||
"Device_NextScan_Imminent": "",
|
||||
"Device_NextScan_In": "",
|
||||
"Device_NoData_Help": "",
|
||||
"Device_NoData_Scanning": "",
|
||||
"Device_NoData_Title": "",
|
||||
"Device_NoMatch_Title": "",
|
||||
"Device_Save_Failed": "",
|
||||
"Device_Save_Unauthorized": "",
|
||||
"Device_Saved_Success": "",
|
||||
"Device_Saved_Unexpected": "",
|
||||
"Device_Scanning": "",
|
||||
"Device_Searchbox": "",
|
||||
"Device_Shortcut_AllDevices": "",
|
||||
"Device_Shortcut_AllNodes": "",
|
||||
"Device_Shortcut_Archived": "",
|
||||
"Device_Shortcut_Connected": "",
|
||||
"Device_Shortcut_Devices": "",
|
||||
"Device_Shortcut_DownAlerts": "",
|
||||
"Device_Shortcut_DownOnly": "",
|
||||
"Device_Shortcut_Favorites": "",
|
||||
"Device_Shortcut_NewDevices": "",
|
||||
"Device_Shortcut_OnlineChart": "",
|
||||
"Device_Shortcut_Unstable": "",
|
||||
"Device_TableHead_AlertDown": "",
|
||||
"Device_TableHead_Connected_Devices": "",
|
||||
"Device_TableHead_CustomProps": "",
|
||||
"Device_TableHead_FQDN": "",
|
||||
"Device_TableHead_Favorite": "",
|
||||
"Device_TableHead_FirstSession": "",
|
||||
"Device_TableHead_Flapping": "",
|
||||
"Device_TableHead_GUID": "",
|
||||
"Device_TableHead_Group": "",
|
||||
"Device_TableHead_IPv4": "",
|
||||
"Device_TableHead_IPv6": "",
|
||||
"Device_TableHead_Icon": "",
|
||||
"Device_TableHead_LastIP": "",
|
||||
"Device_TableHead_LastIPOrder": "",
|
||||
"Device_TableHead_LastSession": "",
|
||||
"Device_TableHead_Location": "",
|
||||
"Device_TableHead_MAC": "",
|
||||
"Device_TableHead_MAC_full": "",
|
||||
"Device_TableHead_Name": "",
|
||||
"Device_TableHead_NetworkSite": "",
|
||||
"Device_TableHead_Owner": "",
|
||||
"Device_TableHead_ParentRelType": "",
|
||||
"Device_TableHead_Parent_MAC": "",
|
||||
"Device_TableHead_Port": "",
|
||||
"Device_TableHead_PresentLastScan": "",
|
||||
"Device_TableHead_ReqNicsOnline": "",
|
||||
"Device_TableHead_RowID": "",
|
||||
"Device_TableHead_Rowid": "",
|
||||
"Device_TableHead_SSID": "",
|
||||
"Device_TableHead_SourcePlugin": "",
|
||||
"Device_TableHead_Status": "",
|
||||
"Device_TableHead_SyncHubNodeName": "",
|
||||
"Device_TableHead_Type": "",
|
||||
"Device_TableHead_Vendor": "",
|
||||
"Device_TableHead_Vlan": "",
|
||||
"Device_Table_Not_Network_Device": "",
|
||||
"Device_Table_info": "",
|
||||
"Device_Table_nav_next": "",
|
||||
"Device_Table_nav_prev": "",
|
||||
"Device_Tablelenght": "",
|
||||
"Device_Tablelenght_all": "",
|
||||
"Device_Title": "",
|
||||
"Devices_Filters": "",
|
||||
"ENABLE_PLUGINS_description": "",
|
||||
"ENABLE_PLUGINS_name": "",
|
||||
"ENCRYPTION_KEY_description": "",
|
||||
"ENCRYPTION_KEY_name": "",
|
||||
"Email_display_name": "",
|
||||
"Email_icon": "",
|
||||
"Events_Loading": "",
|
||||
"Events_Periodselect_All": "",
|
||||
"Events_Periodselect_LastMonth": "",
|
||||
"Events_Periodselect_LastWeek": "",
|
||||
"Events_Periodselect_LastYear": "",
|
||||
"Events_Periodselect_today": "",
|
||||
"Events_Searchbox": "",
|
||||
"Events_Shortcut_AllEvents": "",
|
||||
"Events_Shortcut_DownAlerts": "",
|
||||
"Events_Shortcut_Events": "",
|
||||
"Events_Shortcut_MissSessions": "",
|
||||
"Events_Shortcut_NewDevices": "",
|
||||
"Events_Shortcut_Sessions": "",
|
||||
"Events_Shortcut_VoidSessions": "",
|
||||
"Events_TableHead_AdditionalInfo": "",
|
||||
"Events_TableHead_Connection": "",
|
||||
"Events_TableHead_Date": "",
|
||||
"Events_TableHead_Device": "",
|
||||
"Events_TableHead_Disconnection": "",
|
||||
"Events_TableHead_Duration": "",
|
||||
"Events_TableHead_DurationOrder": "",
|
||||
"Events_TableHead_EventType": "",
|
||||
"Events_TableHead_IP": "",
|
||||
"Events_TableHead_IPOrder": "",
|
||||
"Events_TableHead_Order": "",
|
||||
"Events_TableHead_Owner": "",
|
||||
"Events_TableHead_PendingAlert": "",
|
||||
"Events_Table_info": "",
|
||||
"Events_Table_nav_next": "",
|
||||
"Events_Table_nav_prev": "",
|
||||
"Events_Tablelenght": "",
|
||||
"Events_Tablelenght_all": "",
|
||||
"Events_Title": "",
|
||||
"FakeMAC_hover": "",
|
||||
"FieldLock_Error": "",
|
||||
"FieldLock_Lock_Tooltip": "",
|
||||
"FieldLock_Locked": "",
|
||||
"FieldLock_SaveBeforeLocking": "",
|
||||
"FieldLock_Source_Label": "",
|
||||
"FieldLock_Unlock_Tooltip": "",
|
||||
"FieldLock_Unlocked": "",
|
||||
"GRAPHQL_PORT_description": "",
|
||||
"GRAPHQL_PORT_name": "",
|
||||
"Gen_Action": "",
|
||||
"Gen_Add": "",
|
||||
"Gen_AddDevice": "",
|
||||
"DevDetail_MainInfo_Favorite": "Oblíbené",
|
||||
"DevDetail_MainInfo_Group": "Skupina",
|
||||
"DevDetail_MainInfo_Location": "Umístění",
|
||||
"DevDetail_MainInfo_Name": "Název",
|
||||
"DevDetail_MainInfo_Network": "<i class=\"fa fa-server\"></i> Node (MAC)",
|
||||
"DevDetail_MainInfo_Network_Port": "<i class=\"fa fa-ethernet\"></i> Port",
|
||||
"DevDetail_MainInfo_Network_Site": "Site",
|
||||
"DevDetail_MainInfo_Network_Title": "Síťové detaily",
|
||||
"DevDetail_MainInfo_Owner": "Vlastník",
|
||||
"DevDetail_MainInfo_SSID": "SSID",
|
||||
"DevDetail_MainInfo_Title": "Informace o zařízení",
|
||||
"DevDetail_MainInfo_Type": "Typ",
|
||||
"DevDetail_MainInfo_Vendor": "Výrobce",
|
||||
"DevDetail_MainInfo_mac": "MAC",
|
||||
"DevDetail_NavToChildNode": "Otevřít podřízený node",
|
||||
"DevDetail_Network_Node_hover": "Vyberte nadřazené síťové zařízení, ke kterému je toto zařízení připojeno, pro sestavení Síťového stromu.",
|
||||
"DevDetail_Network_Port_hover": "Port nadřazeného síťového zařízení, ke kterému je toto zařízení připojeno. Pokud je ponechán prázdný, zobrazí se u zařízení WiFi ikona v Síťovém stromu.",
|
||||
"DevDetail_Nmap_Scans": "Manuální NMAP scany",
|
||||
"DevDetail_Nmap_Scans_desc": "Tady můžete spustit manuální NMAP scany. Můžete také naplánovat pravidelné automatické NMAP scany přes plugin Služby & Porty (NMAP). Podívejte se do <a href=\"https://github.com/netalertx/NetAlertX/tree/main/front/plugins/nmap_scan\" target=\"_blank\">Dokumentace</a> pro více informací",
|
||||
"DevDetail_Nmap_buttonDefault": "Výchozí scan",
|
||||
"DevDetail_Nmap_buttonDefault_text": "Výchozí scan: NAMP scanuje prvních 1000 portů pro každý požadovaný protokol. Toto zahrnuje 93 % TCP portů a 49 % UDP portů. (přibližně 5 sekund)",
|
||||
"DevDetail_Nmap_buttonDetail": "Podrobný scan",
|
||||
"DevDetail_Nmap_buttonDetail_text": "Podrobný scan: Výchozí scan s povolenou detekcí OS, detekcí verze, scanování skriptů a traceroute (až 30 sekund nebo déle)",
|
||||
"DevDetail_Nmap_buttonFast": "Rychlý scan",
|
||||
"DevDetail_Nmap_buttonFast_text": "Rychlý scan: Scanovat pár portů (100) oproti výchozímu scanu (pár sekund)",
|
||||
"DevDetail_Nmap_buttonSkipDiscovery": "Přeskočit prohledání hostitele",
|
||||
"DevDetail_Nmap_buttonSkipDiscovery_text": "Přeskočit vyhledávání hostitelů (parametr \"-Pn\"): Výchozí scan bez prohledání hostitele",
|
||||
"DevDetail_Nmap_resultsLink": "Tuto stránku můžete opustit po spuštění scanu. Výsledky budou k dispozici také v souboru <code>app_front.log</code> .",
|
||||
"DevDetail_Owner_hover": "Kdo vlastní toto zařízení. Nepovinná textová položka.",
|
||||
"DevDetail_Periodselect_All": "Všechny informace",
|
||||
"DevDetail_Periodselect_LastMonth": "Minulý měsíc",
|
||||
"DevDetail_Periodselect_LastWeek": "Minulý týden",
|
||||
"DevDetail_Periodselect_LastYear": "Minulý rok",
|
||||
"DevDetail_Periodselect_today": "Dnes",
|
||||
"DevDetail_Run_Actions_Title": "<i class=\"fa fa-play\"></i> Spustit akci na zařízení",
|
||||
"DevDetail_Run_Actions_Tooltip": "Spustit akci na vybraném zařízení.",
|
||||
"DevDetail_SessionInfo_FirstSession": "Prví sezení",
|
||||
"DevDetail_SessionInfo_LastIP": "Poslední IP",
|
||||
"DevDetail_SessionInfo_LastSession": "Naposledy offline",
|
||||
"DevDetail_SessionInfo_StaticIP": "Statická IP",
|
||||
"DevDetail_SessionInfo_Status": "Stav",
|
||||
"DevDetail_SessionInfo_Title": "Informace o sezení",
|
||||
"DevDetail_SessionTable_Additionalinfo": "Další informace",
|
||||
"DevDetail_SessionTable_Connection": "Připojení",
|
||||
"DevDetail_SessionTable_Disconnection": "Odpojení",
|
||||
"DevDetail_SessionTable_Duration": "Trvání",
|
||||
"DevDetail_SessionTable_IP": "IP",
|
||||
"DevDetail_SessionTable_Order": "Pořadí",
|
||||
"DevDetail_Shortcut_CurrentStatus": "Stav",
|
||||
"DevDetail_Shortcut_DownAlerts": "Down alerty",
|
||||
"DevDetail_Shortcut_Presence": "Výskyt",
|
||||
"DevDetail_Shortcut_Sessions": "Sezení",
|
||||
"DevDetail_Tab_Details": "Detaily",
|
||||
"DevDetail_Tab_Events": "Události",
|
||||
"DevDetail_Tab_EventsTableDate": "Datum",
|
||||
"DevDetail_Tab_EventsTableEvent": "Druh události",
|
||||
"DevDetail_Tab_EventsTableIP": "IP",
|
||||
"DevDetail_Tab_EventsTableInfo": "Další informace",
|
||||
"DevDetail_Tab_Nmap": "<i class=\"fa fa-ethernet\"></i> NMAP",
|
||||
"DevDetail_Tab_NmapEmpty": "Pomocí NMAP nebyly na tomto zařízení nalezeny žádné porty.",
|
||||
"DevDetail_Tab_NmapTableExtra": "Extra",
|
||||
"DevDetail_Tab_NmapTableHeader": "Výsledky naplánovaných scanů",
|
||||
"DevDetail_Tab_NmapTableIndex": "Index",
|
||||
"DevDetail_Tab_NmapTablePort": "Port",
|
||||
"DevDetail_Tab_NmapTableService": "Služba",
|
||||
"DevDetail_Tab_NmapTableState": "Stav",
|
||||
"DevDetail_Tab_NmapTableText": "Nastavte plán v <a href=\"/settings.php#NMAP_ACTIVE\">Nastavení</a>",
|
||||
"DevDetail_Tab_NmapTableTime": "Čas",
|
||||
"DevDetail_Tab_Plugins": "Pluginy",
|
||||
"DevDetail_Tab_Presence": "Výskyt",
|
||||
"DevDetail_Tab_Sessions": "Sezení",
|
||||
"DevDetail_Tab_Tools": "Nástroje",
|
||||
"DevDetail_Tab_Tools_Internet_Info_Description": "Nástroj Internetové informace zobrazuje informace o internetovém připojení jako je IP adresa, město, stát, kód oblasti a časovou zónu.",
|
||||
"DevDetail_Tab_Tools_Internet_Info_Error": "Vyskytla se chyba",
|
||||
"DevDetail_Tab_Tools_Internet_Info_Start": "Spustit Internetové informace",
|
||||
"DevDetail_Tab_Tools_Internet_Info_Title": "Internetové informace",
|
||||
"DevDetail_Tab_Tools_Nslookup_Description": "Nslookup je nástroj příkazové řádky používaný pro dotazování doménového jmenného systému (DNS). DNS je systém, který překládá doménové názvy, třeba www.google.com, na IP adresy, třeba na 172.217.0.142.",
|
||||
"DevDetail_Tab_Tools_Nslookup_Error": "Chyba: IP adresa není platná",
|
||||
"DevDetail_Tab_Tools_Nslookup_Start": "Spustit Nslookup",
|
||||
"DevDetail_Tab_Tools_Nslookup_Title": "Nslookup",
|
||||
"DevDetail_Tab_Tools_Speedtest_Description": "Nástroj Sppedtest měří rychlost stahování, rychlost nahrávání a latenci internetového připojení.",
|
||||
"DevDetail_Tab_Tools_Speedtest_Start": "Spustit Speedtest",
|
||||
"DevDetail_Tab_Tools_Speedtest_Title": "Online Speedtest",
|
||||
"DevDetail_Tab_Tools_Traceroute_Description": "Traceroute je sířový diagnostický příklad používaný pro trasování cesty, kterou datové packety putují od jednoho hostitele k druhému.<br><br>Příkaz používá Internet Control Message Protocol (ICMP) pro posílání packetů procházejícím nodů na cestě, kde každý takový node odpovídá pomocí ICMP time-out (TTL timed out) packetu.<br><br>Výstup traceroute příkazu může být použit pro diagnostiku síťových problémů, jako třeba prodlevy, packetové ztráty a blokované trasy.<br><br>Může být také použít k identifikaci umístění procházejícího node v síti.",
|
||||
"DevDetail_Tab_Tools_Traceroute_Error": "Chyba: IP adresa není platná",
|
||||
"DevDetail_Tab_Tools_Traceroute_Start": "Spustit Traceroute",
|
||||
"DevDetail_Tab_Tools_Traceroute_Title": "Traceroute",
|
||||
"DevDetail_Tools_WOL": "Odeslat WOL příkaz na ",
|
||||
"DevDetail_Tools_WOL_noti": "Wake-On-LAN",
|
||||
"DevDetail_Tools_WOL_noti_text": "Příkaz Wake-On-LAN je odelsán na broadcastovou adresu. Pokud není cíl ve stejném subnetu/VLAN jako NetAlertX, cílové zařízení neodpoví.",
|
||||
"DevDetail_Type_hover": "Typ zařízení. Pokud vyberete jakýkoliv typ předdefinovaných zařízení (např. AP, Firewall, Router, Switch, ...), zobrazí se v Síťovém stromu jako nadřazený síťový nod.",
|
||||
"DevDetail_Vendor_hover": "Výrobce by měl být auto-detekován. Můžete ho přepsat, nebo přidat vlastní hodnotu.",
|
||||
"DevDetail_WOL_Title": "<i class=\"fa fa-power-off\"></i> Wake-On-LAN",
|
||||
"DevDetail_button_AddIcon": "Přidat novou ikonu",
|
||||
"DevDetail_button_AddIcon_Help": "Vložte SVG HTML tag, nebo HTML tag ikony z Font Awesome. Přečtěte si <a href=\"https://docs.netalertx.com/ICONS\" target=\"_blank\">Dokumentaci k ikonám</a> pro více informací.",
|
||||
"DevDetail_button_AddIcon_Tooltip": "Přidat novou ikonu k tomuto zařízení, která není mezi dostupnými ikonami ve výběru.",
|
||||
"DevDetail_button_Delete": "Odstranit zařízení",
|
||||
"DevDetail_button_DeleteEvents": "Odstranit události",
|
||||
"DevDetail_button_DeleteEvents_Warning": "Opravdu chcete odstranit všechny události tohoto zařízení?<br><br>(toto odstraní všechno ze záložky <b>Historie událostí</b> a také ze záložky <b>Sezení</b> a může pomoci se stálými (trvalými) notifikacemi)",
|
||||
"DevDetail_button_Delete_ask": "Opravdu chcete odstranit toto zařízení? Místo toho ho můžete archivovat.",
|
||||
"DevDetail_button_OverwriteIcons": "Přepsat ikony",
|
||||
"DevDetail_button_OverwriteIcons_Tooltip": "Přepsat ikony všech zařízení stejného typu zařízení",
|
||||
"DevDetail_button_OverwriteIcons_Warning": "Opravdu chcete přepsat všechny ikony zařízení se stejným typem zařízení ikonou tohoto zařízení?",
|
||||
"DevDetail_button_Reset": "Resetovat změny",
|
||||
"DevDetail_button_Save": "Uložit",
|
||||
"DeviceEdit_ValidMacIp": "Zadejte platnou <b>MAC</b> a <b>IP</b> adresu.",
|
||||
"Device_MultiEdit": "Multi-editace",
|
||||
"Device_MultiEdit_Backup": "Opatrně, zadání nesprávných hodnot níže poškodí vaše nastavení. Zálohujte si prosím nejdřív vaši databázi nebo Seznam zařízení (<a href=\"#\" onclick=\"ExportCSV()\">kliknutím stáhnout <i class=\"fa-solid fa-download fa-bounce\"></i></a>). Přečtěte si, jak obnovit Zařízení z tohoto souboru v <a href=\"https://docs.netalertx.com/BACKUPS#scenario-2-corrupted-database\" target=\"_blank\">Dokumentaci zálohování</a>. Pro pokračování uložení změn kliknéte na ikonu <b>Uložit<i class=\"fa-solid fa-save\"></i></b> u každé položky, kterou chcete aktualizovat.",
|
||||
"Device_MultiEdit_Fields": "Upravit položky:",
|
||||
"Device_MultiEdit_MassActions": "Hromadné akce:",
|
||||
"Device_MultiEdit_No_Devices": "Zařízení nevybráno.",
|
||||
"Device_MultiEdit_Tooltip": "Opatrně. Kliknutím na toto se použije hodnota vlevo všem zařízení dole.",
|
||||
"Device_NextScan_Imminent": "Bezprostřední...",
|
||||
"Device_NextScan_In": "Další scan za ",
|
||||
"Device_NoData_Help": "Pokud se zařízení po skenování nezobrazí, zkontrolujte nastavení SCAN_SUBNETS a <a href=\"https://docs.netalertx.com/SUBNETS\" target=\"_blank\">dokumentaci</a>.",
|
||||
"Device_NoData_Scanning": "Čekání na první sken - toto může trvat několik minut po počátečním nastavení.",
|
||||
"Device_NoData_Title": "Žádná zařízení zatím nenalezena",
|
||||
"Device_NoMatch_Title": "Žádná zařízení neodpovídají aktuálnímu fultru",
|
||||
"Device_Save_Failed": "Chyba při uložení zařízení",
|
||||
"Device_Save_Unauthorized": "Neautorizováno - neplatný API token",
|
||||
"Device_Saved_Success": "Zařízení úspěšně uloženo",
|
||||
"Device_Saved_Unexpected": "Aktualizace zařízení vrátila neočekávanou odpověď",
|
||||
"Device_Scanning": "Skenování...",
|
||||
"Device_Searchbox": "Hledat",
|
||||
"Device_Shortcut_AllDevices": "Moje zařízení",
|
||||
"Device_Shortcut_AllNodes": "Všechny nody",
|
||||
"Device_Shortcut_Archived": "Archivované",
|
||||
"Device_Shortcut_Connected": "Připojené",
|
||||
"Device_Shortcut_Devices": "Zařízení",
|
||||
"Device_Shortcut_DownAlerts": "Nedostupné & Offline",
|
||||
"Device_Shortcut_DownOnly": "Nedostupné",
|
||||
"Device_Shortcut_Favorites": "Oblíbené",
|
||||
"Device_Shortcut_NewDevices": "Nová zařízení",
|
||||
"Device_Shortcut_OnlineChart": "Výskyt zařízení",
|
||||
"Device_Shortcut_Unstable": "Nestabilní",
|
||||
"Device_TableHead_AlertDown": "Upozornění nedostupnosti",
|
||||
"Device_TableHead_Connected_Devices": "Spojení",
|
||||
"Device_TableHead_CustomProps": "Vlastnosti / Akce",
|
||||
"Device_TableHead_FQDN": "FQDN",
|
||||
"Device_TableHead_Favorite": "Oblíbené",
|
||||
"Device_TableHead_FirstSession": "První session",
|
||||
"Device_TableHead_Flapping": "Nestálé",
|
||||
"Device_TableHead_GUID": "GUID",
|
||||
"Device_TableHead_Group": "Skupina",
|
||||
"Device_TableHead_IPv4": "IPv4",
|
||||
"Device_TableHead_IPv6": "IPv6",
|
||||
"Device_TableHead_Icon": "Ikona",
|
||||
"Device_TableHead_LastIP": "Poslední IP",
|
||||
"Device_TableHead_LastIPOrder": "Poslední IP v pořadí",
|
||||
"Device_TableHead_LastSession": "Naposledy offline",
|
||||
"Device_TableHead_Location": "Lokace",
|
||||
"Device_TableHead_MAC": "Náhodná MAC",
|
||||
"Device_TableHead_MAC_full": "Celá MAC",
|
||||
"Device_TableHead_Name": "Název",
|
||||
"Device_TableHead_NetworkSite": "Umístění v síti",
|
||||
"Device_TableHead_Owner": "Vlastník",
|
||||
"Device_TableHead_ParentRelType": "Vztah",
|
||||
"Device_TableHead_Parent_MAC": "Nadřazený node",
|
||||
"Device_TableHead_Port": "Port",
|
||||
"Device_TableHead_PresentLastScan": "Výskyt",
|
||||
"Device_TableHead_ReqNicsOnline": "Vyžadovat NICs online",
|
||||
"Device_TableHead_RowID": "ID řádku",
|
||||
"Device_TableHead_Rowid": "ID řádku",
|
||||
"Device_TableHead_SSID": "SSID",
|
||||
"Device_TableHead_SourcePlugin": "Zdrojový plugin",
|
||||
"Device_TableHead_Status": "Stav",
|
||||
"Device_TableHead_SyncHubNodeName": "Sync node",
|
||||
"Device_TableHead_Type": "Typ",
|
||||
"Device_TableHead_Vendor": "Výrobce",
|
||||
"Device_TableHead_Vlan": "VLAN",
|
||||
"Device_Table_Not_Network_Device": "Nenakonfigurováno jako síťové zařízení",
|
||||
"Device_Table_info": "Zobrazeno _START_ to _END_ of _TOTAL_ záznamů",
|
||||
"Device_Table_nav_next": "Další",
|
||||
"Device_Table_nav_prev": "Předchozí",
|
||||
"Device_Tablelenght": "Zobrazit položky _MENU_",
|
||||
"Device_Tablelenght_all": "Vše",
|
||||
"Device_Title": "Zařízení",
|
||||
"Devices_Filters": "Filtry",
|
||||
"ENABLE_PLUGINS_description": "Povoluje funkcionalitu <a target=\"_blank\" href=\"https://docs.netalertx.com/PLUGINS\">pluginů</a>. Načítání pluginů vyžaduje více hardwarových prostředků, takže je bude lepší zakázat na výkonově slabším systému.",
|
||||
"ENABLE_PLUGINS_name": "Povolit pluginy",
|
||||
"ENCRYPTION_KEY_description": "Klíč šifrování dat.",
|
||||
"ENCRYPTION_KEY_name": "Šifrovací klíč",
|
||||
"Email_display_name": "Email",
|
||||
"Email_icon": "<i class=\"fa fa-at\"></i>",
|
||||
"Events_Loading": "Načítání…",
|
||||
"Events_Periodselect_All": "Všechny informace",
|
||||
"Events_Periodselect_LastMonth": "Minulý měsíc",
|
||||
"Events_Periodselect_LastWeek": "Minulý týden",
|
||||
"Events_Periodselect_LastYear": "Minulý rok",
|
||||
"Events_Periodselect_today": "Dnes",
|
||||
"Events_Searchbox": "Vyhledat",
|
||||
"Events_Shortcut_AllEvents": "Všechny události",
|
||||
"Events_Shortcut_DownAlerts": "Výzvy nedostupnosti",
|
||||
"Events_Shortcut_Events": "Události",
|
||||
"Events_Shortcut_MissSessions": "Chybějící sessions",
|
||||
"Events_Shortcut_NewDevices": "Nová zařízení",
|
||||
"Events_Shortcut_Sessions": "Sessions",
|
||||
"Events_Shortcut_VoidSessions": "Povolená sessions",
|
||||
"Events_TableHead_AdditionalInfo": "Další informace",
|
||||
"Events_TableHead_Connection": "Spojení",
|
||||
"Events_TableHead_Date": "Datum",
|
||||
"Events_TableHead_Device": "Zařízení",
|
||||
"Events_TableHead_Disconnection": "Odpojení",
|
||||
"Events_TableHead_Duration": "Trvání",
|
||||
"Events_TableHead_DurationOrder": "Pořadí trvání",
|
||||
"Events_TableHead_EventType": "Druh události",
|
||||
"Events_TableHead_IP": "IP",
|
||||
"Events_TableHead_IPOrder": "Pořadí IP",
|
||||
"Events_TableHead_Order": "Pořadí",
|
||||
"Events_TableHead_Owner": "Vlastník",
|
||||
"Events_TableHead_PendingAlert": "Čekající výzva",
|
||||
"Events_Table_info": "Zobrazení položek _START_ to _END_ of _TOTAL_",
|
||||
"Events_Table_nav_next": "Další",
|
||||
"Events_Table_nav_prev": "Předchozí",
|
||||
"Events_Tablelenght": "Zobrazení položek _MENU_",
|
||||
"Events_Tablelenght_all": "Vše",
|
||||
"Events_Title": "Události",
|
||||
"FakeMAC_hover": "Toto zařízení má falešnou MAC adresu",
|
||||
"FieldLock_Error": "Chyba při aktualizaci stavu zámku položky",
|
||||
"FieldLock_Lock_Tooltip": "Zamknout položku (zabrání přepsání pluginuem)",
|
||||
"FieldLock_Locked": "Položka uzamčena",
|
||||
"FieldLock_SaveBeforeLocking": "Uložit změny před uzamčením",
|
||||
"FieldLock_Source_Label": "Zdroj ",
|
||||
"FieldLock_Unlock_Tooltip": "Odemknout položku (povolit přepsání pluginem)",
|
||||
"FieldLock_Unlocked": "Položka odemčena",
|
||||
"GRAPHQL_PORT_description": "Číslo portu GraphQL serveru. Ujistěte se, že je port unikátně přes všechny vaše aplikace na tomto hostiteli a NetAlertX instance.",
|
||||
"GRAPHQL_PORT_name": "Port GraphQL",
|
||||
"Gen_Action": "Akce",
|
||||
"Gen_Add": "Přidat",
|
||||
"Gen_AddDevice": "Přidat zařízení",
|
||||
"Gen_Add_All": "Přidat vše",
|
||||
"Gen_All_Devices": "Všechna zařízení",
|
||||
"Gen_Archived": "",
|
||||
"Gen_Archived": "Archivováno",
|
||||
"Gen_AreYouSure": "Jste si jistý?",
|
||||
"Gen_Backup": "Spustit zálohování",
|
||||
"Gen_Cancel": "Zrušit",
|
||||
"Gen_Change": "Změnit",
|
||||
"Gen_Copy": "Spustit",
|
||||
"Gen_CopyToClipboard": "",
|
||||
"Gen_CopyToClipboard": "Zkopírovat do schránky",
|
||||
"Gen_DataUpdatedUITakesTime": "OK - může zabrat chvíli aktualizovat rozhraní, pokud běží scan.",
|
||||
"Gen_Delete": "Smazat",
|
||||
"Gen_DeleteAll": "Smazat vše",
|
||||
"Gen_Description": "Popis",
|
||||
"Gen_Down": "",
|
||||
"Gen_Down": "Nedostupné",
|
||||
"Gen_Error": "Chyba",
|
||||
"Gen_Filter": "Filtr",
|
||||
"Gen_Flapping": "",
|
||||
"Gen_Flapping": "Nestabilní",
|
||||
"Gen_Generate": "Vygenerovat",
|
||||
"Gen_InvalidMac": "",
|
||||
"Gen_Invalid_Value": "",
|
||||
"Gen_InvalidMac": "Neplatná MAC adresa.",
|
||||
"Gen_Invalid_Value": "Zadána neplatná hodnota",
|
||||
"Gen_LockedDB": "CHYBA - Databáze je možná zamčená - Zkontrolujte F12 -> Nástroje pro vývojáře -> Konzole. nebo to zkuste později.",
|
||||
"Gen_NetworkMask": "",
|
||||
"Gen_New": "",
|
||||
"Gen_NetworkMask": "Maska sítě",
|
||||
"Gen_New": "Nový",
|
||||
"Gen_No_Data": "Bez dat",
|
||||
"Gen_Offline": "Offline",
|
||||
"Gen_Okay": "Ok",
|
||||
"Gen_Online": "Online",
|
||||
@@ -361,8 +364,8 @@
|
||||
"Gen_SelectIcon": "<i class=\"fa-solid fa-chevron-down fa-fade\"></i>",
|
||||
"Gen_SelectToPreview": "Vybrat na náhled",
|
||||
"Gen_Selected_Devices": "Vybraná zařízení:",
|
||||
"Gen_Sleeping": "",
|
||||
"Gen_Subnet": "",
|
||||
"Gen_Sleeping": "Spící",
|
||||
"Gen_Subnet": "Subnet",
|
||||
"Gen_Switch": "Přepnout",
|
||||
"Gen_Upd": "Úspěšně aktualizováno",
|
||||
"Gen_Upd_Fail": "Aktualizace se nezdařila",
|
||||
@@ -370,71 +373,71 @@
|
||||
"Gen_Update_Value": "Aktualizovat hodnotu",
|
||||
"Gen_ValidIcon": "<i class=\"fa-solid fa-chevron-right \"></i>",
|
||||
"Gen_Warning": "Upozornění",
|
||||
"Gen_Work_In_Progress": "",
|
||||
"Gen_create_new_device": "",
|
||||
"Gen_create_new_device_info": "",
|
||||
"General_display_name": "",
|
||||
"General_icon": "",
|
||||
"HRS_TO_KEEP_NEWDEV_description": "",
|
||||
"HRS_TO_KEEP_NEWDEV_name": "",
|
||||
"HRS_TO_KEEP_OFFDEV_description": "",
|
||||
"HRS_TO_KEEP_OFFDEV_name": "",
|
||||
"Gen_Work_In_Progress": "Rozpracováno, ideální čas pro zpětnou vazbu na https://github.com/netalertx/NetAlertX/issues",
|
||||
"Gen_create_new_device": "Nové zařízení",
|
||||
"Gen_create_new_device_info": "Zařízení jsou vyhledávána pomocí <a target=\"_blank\" href=\"https://docs.netalertx.com/PLUGINS\">pluginů</a>. V určitých případech je však potřeba přidat zařízení ručně. Chcete-li prozkoumat konkrétní scénáře, podívejte se do <a target=\"_blank\" href=\"https://docs.netalertx.com/REMOTE_NETWORKS\">Dokumentace vzdálených sítí</a>.",
|
||||
"General_display_name": "Základní",
|
||||
"General_icon": "<i class=\"fa fa-gears\"></i>",
|
||||
"HRS_TO_KEEP_NEWDEV_description": "Toto je údržbářské nastavení <b>ODSTRANĚNÍ zařízení</b>. Pokud je povoleno (<code>0</code> zakázáno), zařízení označená jako <b>Nové zařízení</b> budou odstraněna, pokud je jejich čas <b>První session</b> starší, než uvedené hodiny v tomto nastavení. Použijte toto nastavení, pokud chcete automaticky mazat <b>Nová zařízení</b> po uplynutí <code>X</code> hodin.",
|
||||
"HRS_TO_KEEP_NEWDEV_name": "Odstranit nová zařízení po",
|
||||
"HRS_TO_KEEP_OFFDEV_description": "Toto je údržbářské nastavení <b>ODSTRANĚNÍ zařízení</b>. Pokud je povoleno (<code>0</code> zakázáno), zařízení <b>Offline</b> s jejich datumem <b>Posledního připojení</b> starším, než uvedené hodiny v tomto nastavení, budou odstraněna. Použijte toto nastavení, pokud chcete automaticky mazat <b>Offline zařízení</b> po uplynutí <code>X</code> hodin offline.",
|
||||
"HRS_TO_KEEP_OFFDEV_name": "Odstranit offline zařízení po",
|
||||
"LOADED_PLUGINS_description": "",
|
||||
"LOADED_PLUGINS_name": "",
|
||||
"LOG_LEVEL_description": "",
|
||||
"LOG_LEVEL_name": "",
|
||||
"Loading": "",
|
||||
"Login_Box": "",
|
||||
"LOADED_PLUGINS_name": "Načtené pluginy",
|
||||
"LOG_LEVEL_description": "Toto nastavení způsobí více detailní logování. To je užitečné pro ladění událostí zapisujících do databáze.",
|
||||
"LOG_LEVEL_name": "Vypisovat dodatečné logování",
|
||||
"Loading": "Načítání…",
|
||||
"Login_Box": "Zadejte vaše heslo",
|
||||
"Login_Default_PWD": "",
|
||||
"Login_Info": "",
|
||||
"Login_Psw-box": "",
|
||||
"Login_Psw_alert": "",
|
||||
"Login_Psw_folder": "",
|
||||
"Login_Psw_new": "",
|
||||
"Login_Psw_run": "",
|
||||
"Login_Remember": "",
|
||||
"Login_Remember_small": "",
|
||||
"Login_Submit": "",
|
||||
"Login_Toggle_Alert_headline": "",
|
||||
"Login_Toggle_Info": "",
|
||||
"Login_Toggle_Info_headline": "",
|
||||
"Maint_PurgeLog": "",
|
||||
"Maint_RestartServer": "",
|
||||
"Maint_Restart_Server_noti_text": "",
|
||||
"Maintenance_InitCheck": "",
|
||||
"Maintenance_InitCheck_Checking": "",
|
||||
"Maintenance_InitCheck_QuickSetupGuide": "",
|
||||
"Maintenance_InitCheck_Success": "",
|
||||
"Maintenance_ReCheck": "",
|
||||
"Maintenance_Running_Version": "",
|
||||
"Maintenance_Status": "",
|
||||
"Maintenance_Title": "",
|
||||
"Maintenance_Tool_DownloadConfig": "",
|
||||
"Maintenance_Tool_DownloadConfig_text": "",
|
||||
"Maintenance_Tool_DownloadWorkflows": "",
|
||||
"Maintenance_Tool_DownloadWorkflows_text": "",
|
||||
"Maintenance_Tool_ExportCSV": "",
|
||||
"Maintenance_Tool_ExportCSV_noti": "",
|
||||
"Maintenance_Tool_ExportCSV_noti_text": "",
|
||||
"Maintenance_Tool_ExportCSV_text": "",
|
||||
"Maintenance_Tool_ImportCSV": "",
|
||||
"Maintenance_Tool_ImportCSV_noti": "",
|
||||
"Maintenance_Tool_ImportCSV_noti_text": "",
|
||||
"Maintenance_Tool_ImportCSV_text": "",
|
||||
"Maintenance_Tool_ImportConfig_noti": "",
|
||||
"Maintenance_Tool_ImportPastedCSV": "",
|
||||
"Maintenance_Tool_ImportPastedCSV_noti_text": "",
|
||||
"Maintenance_Tool_ImportPastedCSV_text": "",
|
||||
"Maintenance_Tool_ImportPastedConfig": "",
|
||||
"Maintenance_Tool_ImportPastedConfig_noti_text": "",
|
||||
"Maintenance_Tool_ImportPastedConfig_text": "",
|
||||
"Maintenance_Tool_UnlockFields": "",
|
||||
"Maintenance_Tool_UnlockFields_noti": "",
|
||||
"Maintenance_Tool_UnlockFields_noti_text": "",
|
||||
"Maintenance_Tool_UnlockFields_text": "",
|
||||
"Maintenance_Tool_arpscansw": "",
|
||||
"Maintenance_Tool_arpscansw_noti": "",
|
||||
"Maintenance_Tool_arpscansw_noti_text": "",
|
||||
"Login_Info": "Hesla jsou nastavována přes Set Password plugin. Zkontrolujte <a target=\"_blank\" href=\"https://github.com/netalertx/NetAlertX/tree/main/front/plugins/set_password\">dokumentaci SETPWD</a>, pokud máte potíže s přihlášením.",
|
||||
"Login_Psw-box": "Heslo",
|
||||
"Login_Psw_alert": "Upozornění na heslo!",
|
||||
"Login_Psw_folder": "v config složce.",
|
||||
"Login_Psw_new": "Nové heslo",
|
||||
"Login_Psw_run": "Pro změnu hesla spusťte:",
|
||||
"Login_Remember": "Zapamatujte si",
|
||||
"Login_Remember_small": "(platné 7 dní)",
|
||||
"Login_Submit": "Přihlásit",
|
||||
"Login_Toggle_Alert_headline": "Upozornění na heslo!",
|
||||
"Login_Toggle_Info": "Informace o hesle",
|
||||
"Login_Toggle_Info_headline": "Informace o hesle",
|
||||
"Maint_PurgeLog": "Vyprázdnit log",
|
||||
"Maint_RestartServer": "Restartovat server",
|
||||
"Maint_Restart_Server_noti_text": "Opravdu chcete restartovat backendový server? Toto může způsobit nekonzistence v aplikaci. Nejprve si zazálohujte vaše nastavení. <br/><br/> Poznámka: Toto může trvat několik minut.",
|
||||
"Maintenance_InitCheck": "Inicializační kontrola",
|
||||
"Maintenance_InitCheck_Checking": "Kontroluje se…",
|
||||
"Maintenance_InitCheck_QuickSetupGuide": "Ujistěte se, že jste postupovali podle <a href=\"https://docs.netalertx.com/INITIAL_SETUP/\" target=\"_blank\">příručky pro rychlé nastavení</a>.",
|
||||
"Maintenance_InitCheck_Success": "Aplikace zinicializována úspěšně!",
|
||||
"Maintenance_ReCheck": "Opakovat pokus",
|
||||
"Maintenance_Running_Version": "Nainstalovaná verze",
|
||||
"Maintenance_Status": "Stav",
|
||||
"Maintenance_Title": "Nástroje údržby",
|
||||
"Maintenance_Tool_DownloadConfig": "Export nastavení",
|
||||
"Maintenance_Tool_DownloadConfig_text": "Stáhněte si kompletní zálohu vašeho nastavení a konfigurace uloženou v souboru <code>app.conf</code> .",
|
||||
"Maintenance_Tool_DownloadWorkflows": "Export workflows",
|
||||
"Maintenance_Tool_DownloadWorkflows_text": "Stáhněte si kompletní zálohu vašich workflows uloženou v soboru <code>workflows.json</code>.",
|
||||
"Maintenance_Tool_ExportCSV": "Export zařízení (CSV)",
|
||||
"Maintenance_Tool_ExportCSV_noti": "Export zařízení (CSV)",
|
||||
"Maintenance_Tool_ExportCSV_noti_text": "Opravdu chcete vygenerovat CSV soubor?",
|
||||
"Maintenance_Tool_ExportCSV_text": "Vygenerovat CSV (čárkami oddělené hodnoty) soubor obsahující seznam zařízení zahrnující síťové vazby mezi síťovými nody a připojenými zařízeními. Toto můžete vyvolat také povolením pluginu <a href=\"settings.php#CSVBCKP_header\">CSV Backup</a>.",
|
||||
"Maintenance_Tool_ImportCSV": "Import zařízení (CSV)",
|
||||
"Maintenance_Tool_ImportCSV_noti": "Import zařízení (CSV)",
|
||||
"Maintenance_Tool_ImportCSV_noti_text": "Opravdu chcete importovat CSV soubor? Toto kompletně <b>přepíše</b> zařízení ve vaší databázi.",
|
||||
"Maintenance_Tool_ImportCSV_text": "Než začnete používat tuto funkci, vytvořte si raději zálohu. Import CSV (čárkou oddělené hodnoty) souboru obsahujícího seznam zařízení, zahrnující síťové vazby mezi síťovými nody a připojenými zařízeními. Abyste toto provedli, umístěte CSV soubor s názvem <b>devices.csv</b> do složky <b>/config</b>.",
|
||||
"Maintenance_Tool_ImportConfig_noti": "Import nastavení (app.conf)",
|
||||
"Maintenance_Tool_ImportPastedCSV": "Import zařízení (CSV) (paste)",
|
||||
"Maintenance_Tool_ImportPastedCSV_noti_text": "Opravdu chcete importovat vložené CSV? Toto kompletně <b>přepíše</b> zařízení ve vaší databázi.",
|
||||
"Maintenance_Tool_ImportPastedCSV_text": "Před použitím této funkce raději udělejte zálohu. Importování CSV (čárkou oddělené hodnoty) souboru obsahující seznam zařízení zahrnující síťově vazby mezi síťovými nody a připojenými zařízeními.",
|
||||
"Maintenance_Tool_ImportPastedConfig": "Import nastavení (paste)",
|
||||
"Maintenance_Tool_ImportPastedConfig_noti_text": "Opravdu chcete importovat vložené konfigurační nastavení? Toto kompletně <b>přepíše</b> soubor <code>app.conf</code>.",
|
||||
"Maintenance_Tool_ImportPastedConfig_text": "Importovat soubor <code>app.conf</code> obsahující veškerá aplikační nastavení. Doporučujeme zálohovat stávající <code>app.conf</code> pomocí <b>Exportu nastavení</b>.",
|
||||
"Maintenance_Tool_UnlockFields": "Odemknout položky zařízení",
|
||||
"Maintenance_Tool_UnlockFields_noti": "Odemknout položky zařízení",
|
||||
"Maintenance_Tool_UnlockFields_noti_text": "Opravdu chcete vymazat všechny zdrojové hodnoty (UZAMČENÉ/UŽIVATELSKÉ) všech položek u všech zařízení? Tuto akci nelze vrátit zpět.",
|
||||
"Maintenance_Tool_UnlockFields_text": "Tento nástroj odstraní všechny zdrojové hodnoty ze všech sledovaných polí pro všechna zařízení, čímž efektivně odemkne všechna pole pro pluginy a uživatele. Používejte jej opatrně, protože to ovlivní celý inventář vašich zařízení.",
|
||||
"Maintenance_Tool_arpscansw": "Přepnout ARP sken (zapnuto/vypnuto)",
|
||||
"Maintenance_Tool_arpscansw_noti": "Přepne ARP sken na zapnuto nebo vypnuto",
|
||||
"Maintenance_Tool_arpscansw_noti_text": "Pokud je scan vypnut, zůstává vypnutý do opětovné aktivace.",
|
||||
"Maintenance_Tool_arpscansw_text": "",
|
||||
"Maintenance_Tool_backup": "",
|
||||
"Maintenance_Tool_backup_noti": "",
|
||||
@@ -805,4 +808,4 @@
|
||||
"settings_system_label": "",
|
||||
"settings_update_item_warning": "",
|
||||
"test_event_tooltip": ""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,8 +29,8 @@
|
||||
"AppEvents_Type": "Typ",
|
||||
"Apprise_display_name": "Apprise",
|
||||
"Apprise_icon": "<i class=\"fa fa-bullhorn\"></i>",
|
||||
"BACKEND_API_URL_description": "",
|
||||
"BACKEND_API_URL_name": "",
|
||||
"BACKEND_API_URL_description": "Wird verwendet, damit das Frontend mit dem Backend kommunizieren kann. Standardmäßig ist hier <code>/server</code> eingestellt und sollte in der Regel nicht geändert werden.",
|
||||
"BACKEND_API_URL_name": "URL der Backend-API",
|
||||
"BackDevDetail_Actions_Ask_Run": "Möchtest du die Aktion ausführen?",
|
||||
"BackDevDetail_Actions_Not_Registered": "Aktion nicht registriert: ",
|
||||
"BackDevDetail_Actions_Title_Run": "Aktion ausführen",
|
||||
@@ -70,16 +70,18 @@
|
||||
"CustProps_cant_remove": "Kann nicht entfernt werden, es wird mindestens eine Eigenschaft benötigt.",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "Dies ist eine Wartungseinstellung. Spezifiziert wie viele Tage Events gespeichert bleiben. Alle älteren Events werden periodisch gelöscht. Wird auch auf die Plugins History angewendet.",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "Ereignisse löschen, die älter sind als",
|
||||
"DEEP_SLEEP_description": "Senkt die CPU-Auslastung, indem die Wartezeiten im Leerlauf zwischen den Verarbeitungszyklen verlängert werden. Bei Aktivierung können sich Scans um bis zu 1 Minute verzögern, und die Benutzeroberfläche reagiert möglicherweise weniger schnell.",
|
||||
"DEEP_SLEEP_name": "Tiefschlaf",
|
||||
"DISCOVER_PLUGINS_description": "Deaktiviere diese Option, um Initialisierung und Speichern der Einstellungen zu beschleunigen. Wenn es deaktiviert ist, werden keine neuen Plugins gefunden und es können keine manuell hinzugefügt werden.",
|
||||
"DISCOVER_PLUGINS_name": "Entdecke Erweiterungen",
|
||||
"DevDetail_Children_Title": "",
|
||||
"DevDetail_Children_Title": "Beziehungen zu untergeordneten Elementen",
|
||||
"DevDetail_Copy_Device_Title": "Details von Gerät kopieren",
|
||||
"DevDetail_Copy_Device_Tooltip": "Details vom Gerät aus der Dropdown-Liste kopieren. Alles auf dieser Seite wird überschrieben",
|
||||
"DevDetail_CustomProperties_Title": "Benutzerdefinierte Eigenschaften",
|
||||
"DevDetail_CustomProps_reset_info": "Dadurch werden Ihre benutzerdefinierten Eigenschaften auf diesem Gerät entfernt und auf den Standardwert zurückgesetzt.",
|
||||
"DevDetail_DisplayFields_Title": "Anzeige",
|
||||
"DevDetail_EveandAl_AlertAllEvents": "Alarmereignisse",
|
||||
"DevDetail_EveandAl_AlertDown": "Melde Down",
|
||||
"DevDetail_EveandAl_AlertDown": "Alarm ausgeschaltet",
|
||||
"DevDetail_EveandAl_Archived": "Archiviert",
|
||||
"DevDetail_EveandAl_NewDevice": "Neues Gerät",
|
||||
"DevDetail_EveandAl_NewDevice_Tooltip": "Zeigt den Status „Neu“ für das Gerät an und nimmt es in Listen auf, wenn der Filter „Neue Geräte“ aktiv ist. Hat keine Auswirkungen auf Benachrichtigungen.",
|
||||
@@ -109,11 +111,11 @@
|
||||
"DevDetail_MainInfo_Type": "Typ",
|
||||
"DevDetail_MainInfo_Vendor": "Hersteller",
|
||||
"DevDetail_MainInfo_mac": "MAC",
|
||||
"DevDetail_NavToChildNode": "",
|
||||
"DevDetail_NavToChildNode": "Knoten untergeordneter Elemente öffnen",
|
||||
"DevDetail_Network_Node_hover": "Wählen Sie das Elternnetzgerät aus, an das das aktuelle Gerät angeschlossen ist, um den Netzwerkbaum zu erstellen.",
|
||||
"DevDetail_Network_Port_hover": "Der Port, mit dem dieses Gerät am übergeordneten Netzwerkgerät verbunden ist. Bleibt er leer, wird ein WLAN-Symbol in der Netzwerkstruktur angezeigt.",
|
||||
"DevDetail_Nmap_Scans": "Nmap Scans",
|
||||
"DevDetail_Nmap_Scans_desc": "Hier kannst du manuelle NMAP Scans starten. Reguläre automatische NMAP Scans können mit dem Services & Ports (NMAP) Plugin geplant werden. Gehe zu den <a href='/settings.php' target='_blank'>Einstellungen</a> um erfahren",
|
||||
"DevDetail_Nmap_Scans_desc": "Hier kannst du manuelle NMAP Scans starten. Reguläre automatische NMAP Scans können mit dem Services & Ports (NMAP) Plugin geplant werden. Gehe zu den <a href=\"https://github.com/netalertx/NetAlertX/tree/main/front/plugins/nmap_scan\" target=\"_blank\">Docs</a> um mehr erfahren",
|
||||
"DevDetail_Nmap_buttonDefault": "Standard Scan",
|
||||
"DevDetail_Nmap_buttonDefault_text": "Standard Scan: Nmap scannt die ersten 1.000 Ports für jedes angeforderte Scan-Protokoll. Damit werden etwa 93 % der TCP-Ports und 49 % der UDP-Ports erfasst. (ca. 5-10 Sekunden)",
|
||||
"DevDetail_Nmap_buttonDetail": "Detailierter Scan",
|
||||
@@ -185,7 +187,7 @@
|
||||
"DevDetail_Tools_WOL": "Sende Wol Befehl an ",
|
||||
"DevDetail_Tools_WOL_noti": "Wake-on-LAN",
|
||||
"DevDetail_Tools_WOL_noti_text": "Der Wake-on-LAN Befehl wurde and die Broadcast Adresse gesendet. Wenn sich das zu startende Gerät nicht im gleichen Subnet / VLan wie NetAlertX befindet, wird das Gerät nicht reagieren.",
|
||||
"DevDetail_Type_hover": "Der Type des Gerätes. If you select any of the pre-defined network devices (e.g.: AP, Firewall, Router, Switch...) they will show up in the Network tree configuration as possible parent network nodes.",
|
||||
"DevDetail_Type_hover": "Der Gerätetyp. Wenn Sie eines der vordefinierten Netzwerkgeräte (z. B. AP, Firewall, Router, Switch…) auswählen, werden diese in der Netzwerkbaumkonfiguration als mögliche übergeordnete Netzwerkknoten angezeigt.",
|
||||
"DevDetail_Vendor_hover": "Der Anbieter sollte automatisch erkannt werden. Du kannst den Wert überschreiben oder deinen eigenen Wert hinzufügen.",
|
||||
"DevDetail_WOL_Title": "<i class=\"fa fa-power-off\"></i> Wake-on-LAN",
|
||||
"DevDetail_button_AddIcon": "Neues Symbol Hinzufügen",
|
||||
@@ -207,17 +209,17 @@
|
||||
"Device_MultiEdit_MassActions": "Massen aktionen:",
|
||||
"Device_MultiEdit_No_Devices": "Keine Geräte ausgewählt.",
|
||||
"Device_MultiEdit_Tooltip": "Achtung! Beim Drücken werden alle Werte auf die oben ausgewählten Geräte übertragen.",
|
||||
"Device_NextScan_Imminent": "",
|
||||
"Device_NextScan_In": "",
|
||||
"Device_NoData_Help": "",
|
||||
"Device_NoData_Scanning": "",
|
||||
"Device_NextScan_Imminent": "Bevorstehend...",
|
||||
"Device_NextScan_In": "Nächster Scan in etwa ",
|
||||
"Device_NoData_Help": "Falls nach dem Scan keine Geräte angezeigt werden, überprüfen Sie Ihre SCAN_SUBNETS Einstellung und die <a href=\"https://docs.netalertx.com/SUBNETS\" target=\"_blank\">Dokumentation</a>.",
|
||||
"Device_NoData_Scanning": "Warten auf den ersten Scan – dies kann nach der Ersteinrichtung einige Minuten dauern.",
|
||||
"Device_NoData_Title": "Noch keine Geräte gefunden",
|
||||
"Device_NoMatch_Title": "",
|
||||
"Device_Save_Failed": "",
|
||||
"Device_Save_Unauthorized": "",
|
||||
"Device_NoMatch_Title": "Es wurden keine Geräte gefunden, die dem aktuellen Filter entsprechen",
|
||||
"Device_Save_Failed": "Das Speichern des Geräts ist fehlgeschlagen",
|
||||
"Device_Save_Unauthorized": "Nicht autorisiert – ungültiger API-Token",
|
||||
"Device_Saved_Success": "Gerät erfolgreich gespeichert",
|
||||
"Device_Saved_Unexpected": "",
|
||||
"Device_Scanning": "",
|
||||
"Device_Saved_Unexpected": "Geräteaktualisierung hat eine unerwartete Antwort zurückgegeben",
|
||||
"Device_Scanning": "Wird gescannt...",
|
||||
"Device_Searchbox": "Suche",
|
||||
"Device_Shortcut_AllDevices": "Meine Geräte",
|
||||
"Device_Shortcut_AllNodes": "Alle Knoten",
|
||||
@@ -348,6 +350,7 @@
|
||||
"Gen_LockedDB": "ERROR - DB eventuell gesperrt - Nutze die Konsole in den Entwickler Werkzeugen (F12) zur Überprüfung oder probiere es später erneut.",
|
||||
"Gen_NetworkMask": "Netzmaske",
|
||||
"Gen_New": "Neu",
|
||||
"Gen_No_Data": "Keine Daten",
|
||||
"Gen_Offline": "Offline",
|
||||
"Gen_Okay": "Ok",
|
||||
"Gen_Online": "Online",
|
||||
|
||||
@@ -66,6 +66,8 @@
|
||||
"CustProps_cant_remove": "Can't remove, at least one property is needed.",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "This is a maintenance setting. This specifies the number of days worth of event entries that will be kept. All older events will be deleted periodically. Also applies on Plugin Events History.",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "Delete events older than",
|
||||
"DEEP_SLEEP_description": "Lowers CPU usage by extending idle wait times between processing cycles. When enabled, scans may be delayed by up to 1 minute and the UI might become less responsive.",
|
||||
"DEEP_SLEEP_name": "Deep sleep",
|
||||
"DISCOVER_PLUGINS_description": "Disable this option to speed up initialization and settings saving. When disabled, plugins are not discovered, and you cannot add new plugins to the <code>LOADED_PLUGINS</code> setting.",
|
||||
"DISCOVER_PLUGINS_name": "Discover plugins",
|
||||
"DevDetail_Children_Title": "Children Relationships",
|
||||
@@ -247,8 +249,8 @@
|
||||
"Device_TableHead_Name": "Name",
|
||||
"Device_TableHead_NetworkSite": "Network Site",
|
||||
"Device_TableHead_Owner": "Owner",
|
||||
"Device_TableHead_ParentRelType": "Relationship Type",
|
||||
"Device_TableHead_Parent_MAC": "Parent network node",
|
||||
"Device_TableHead_ParentRelType": "Relationship",
|
||||
"Device_TableHead_Parent_MAC": "Parent node",
|
||||
"Device_TableHead_Port": "Port",
|
||||
"Device_TableHead_PresentLastScan": "Presence",
|
||||
"Device_TableHead_ReqNicsOnline": "Require NICs Online",
|
||||
@@ -344,6 +346,7 @@
|
||||
"Gen_LockedDB": "ERROR - DB might be locked - Check F12 Dev tools -> Console or try later.",
|
||||
"Gen_NetworkMask": "Network mask",
|
||||
"Gen_New": "New",
|
||||
"Gen_No_Data": "No data",
|
||||
"Gen_Offline": "Offline",
|
||||
"Gen_Okay": "Ok",
|
||||
"Gen_Online": "Online",
|
||||
@@ -400,11 +403,11 @@
|
||||
"Login_Toggle_Info_headline": "Password Information",
|
||||
"Maint_PurgeLog": "Purge log",
|
||||
"Maint_RestartServer": "Restart server",
|
||||
"Maint_Restart_Server_noti_text": "Are you sure you want to restart the backend server? This may casue app inconsistency. Backup your setup first. <br/> <br/> Note: This may take a few minutes.",
|
||||
"Maint_Restart_Server_noti_text": "Are you sure you want to restart the backend server? This may cause app inconsistency. Backup your setup first. <br/> <br/> Note: This may take a few minutes.",
|
||||
"Maintenance_InitCheck": "Init check",
|
||||
"Maintenance_InitCheck_Checking": "Checking…",
|
||||
"Maintenance_InitCheck_QuickSetupGuide": "Make sure you followed the <a href=\"https://docs.netalertx.com/INITIAL_SETUP/\" target=\"_blank\">quick setup guide</a>.",
|
||||
"Maintenance_InitCheck_Success": "Application initialized succesfully!",
|
||||
"Maintenance_InitCheck_Success": "Application initialized successfully!",
|
||||
"Maintenance_ReCheck": "Retry check",
|
||||
"Maintenance_Running_Version": "Installed version",
|
||||
"Maintenance_Status": "Status",
|
||||
|
||||
@@ -68,6 +68,8 @@
|
||||
"CustProps_cant_remove": "No se puede eliminar, al menos una propiedad es requerida.",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "Esta es una configuración de mantenimiento. Esto especifica el número de días de entradas de eventos que se guardarán. Todos los eventos anteriores se eliminarán periódicamente.",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "Eliminar eventos anteriores a",
|
||||
"DEEP_SLEEP_description": "Reduce el uso de la CPU al extender los tiempos de espera entre los ciclos de procesamiento. Cuando se habilita, los análisis pueden retrasarse hasta un minuto y la interfaz de usuario puede volverse menos reactiva.",
|
||||
"DEEP_SLEEP_name": "Sueño profundo",
|
||||
"DISCOVER_PLUGINS_description": "Desactive esta opción para acelerar la inicialización y el ahorro de ajustes. Cuando está desactivado, los plugins no se descubren y no puede añadir nuevos plugins a la configuración <code>LOADED_PLUGINS</code>.",
|
||||
"DISCOVER_PLUGINS_name": "Descubrir plugins",
|
||||
"DevDetail_Children_Title": "Relaciones hijo",
|
||||
@@ -346,6 +348,7 @@
|
||||
"Gen_LockedDB": "Fallo - La base de datos puede estar bloqueada - Pulsa F1 -> Ajustes de desarrolladores -> Consola o prueba más tarde.",
|
||||
"Gen_NetworkMask": "Máscara de red",
|
||||
"Gen_New": "",
|
||||
"Gen_No_Data": "",
|
||||
"Gen_Offline": "Desconectado",
|
||||
"Gen_Okay": "Aceptar",
|
||||
"Gen_Online": "En linea",
|
||||
@@ -876,4 +879,4 @@
|
||||
"settings_system_label": "Sistema",
|
||||
"settings_update_item_warning": "Actualice el valor a continuación. Tenga cuidado de seguir el formato anterior. <b>O la validación no se realiza.</b>",
|
||||
"test_event_tooltip": "Guarda tus cambios antes de probar nuevos ajustes."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,6 +66,8 @@
|
||||
"CustProps_cant_remove": "",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "",
|
||||
"DEEP_SLEEP_description": "",
|
||||
"DEEP_SLEEP_name": "",
|
||||
"DISCOVER_PLUGINS_description": "",
|
||||
"DISCOVER_PLUGINS_name": "",
|
||||
"DevDetail_Children_Title": "",
|
||||
@@ -344,6 +346,7 @@
|
||||
"Gen_LockedDB": "",
|
||||
"Gen_NetworkMask": "",
|
||||
"Gen_New": "",
|
||||
"Gen_No_Data": "",
|
||||
"Gen_Offline": "",
|
||||
"Gen_Okay": "",
|
||||
"Gen_Online": "",
|
||||
|
||||
811
front/php/templates/language/fi_fi.json
Normal file
811
front/php/templates/language/fi_fi.json
Normal file
@@ -0,0 +1,811 @@
|
||||
{
|
||||
"API_CUSTOM_SQL_description": "",
|
||||
"API_CUSTOM_SQL_name": "",
|
||||
"API_TOKEN_description": "",
|
||||
"API_TOKEN_name": "",
|
||||
"API_display_name": "",
|
||||
"API_icon": "",
|
||||
"About_Design": "",
|
||||
"About_Exit": "",
|
||||
"About_Title": "",
|
||||
"AppEvents_AppEventProcessed": "",
|
||||
"AppEvents_DateTimeCreated": "",
|
||||
"AppEvents_Extra": "",
|
||||
"AppEvents_GUID": "",
|
||||
"AppEvents_Helper1": "",
|
||||
"AppEvents_Helper2": "",
|
||||
"AppEvents_Helper3": "",
|
||||
"AppEvents_ObjectForeignKey": "",
|
||||
"AppEvents_ObjectIndex": "",
|
||||
"AppEvents_ObjectIsArchived": "",
|
||||
"AppEvents_ObjectIsNew": "",
|
||||
"AppEvents_ObjectPlugin": "",
|
||||
"AppEvents_ObjectPrimaryID": "",
|
||||
"AppEvents_ObjectSecondaryID": "",
|
||||
"AppEvents_ObjectStatus": "",
|
||||
"AppEvents_ObjectStatusColumn": "",
|
||||
"AppEvents_ObjectType": "",
|
||||
"AppEvents_Plugin": "",
|
||||
"AppEvents_Type": "",
|
||||
"BACKEND_API_URL_description": "",
|
||||
"BACKEND_API_URL_name": "",
|
||||
"BackDevDetail_Actions_Ask_Run": "",
|
||||
"BackDevDetail_Actions_Not_Registered": "",
|
||||
"BackDevDetail_Actions_Title_Run": "",
|
||||
"BackDevDetail_Copy_Ask": "",
|
||||
"BackDevDetail_Copy_Title": "",
|
||||
"BackDevDetail_Tools_WOL_error": "",
|
||||
"BackDevDetail_Tools_WOL_okay": "",
|
||||
"BackDevices_Arpscan_disabled": "",
|
||||
"BackDevices_Arpscan_enabled": "",
|
||||
"BackDevices_Backup_CopError": "",
|
||||
"BackDevices_Backup_Failed": "",
|
||||
"BackDevices_Backup_okay": "",
|
||||
"BackDevices_DBTools_DelDevError_a": "",
|
||||
"BackDevices_DBTools_DelDevError_b": "",
|
||||
"BackDevices_DBTools_DelDev_a": "",
|
||||
"BackDevices_DBTools_DelDev_b": "",
|
||||
"BackDevices_DBTools_DelEvents": "",
|
||||
"BackDevices_DBTools_DelEventsError": "",
|
||||
"BackDevices_DBTools_ImportCSV": "",
|
||||
"BackDevices_DBTools_ImportCSVError": "",
|
||||
"BackDevices_DBTools_ImportCSVMissing": "",
|
||||
"BackDevices_DBTools_Purge": "",
|
||||
"BackDevices_DBTools_UpdDev": "",
|
||||
"BackDevices_DBTools_UpdDevError": "",
|
||||
"BackDevices_DBTools_Upgrade": "",
|
||||
"BackDevices_DBTools_UpgradeError": "",
|
||||
"BackDevices_Device_UpdDevError": "",
|
||||
"BackDevices_Restore_CopError": "",
|
||||
"BackDevices_Restore_Failed": "",
|
||||
"BackDevices_Restore_okay": "",
|
||||
"BackDevices_darkmode_disabled": "",
|
||||
"BackDevices_darkmode_enabled": "",
|
||||
"CLEAR_NEW_FLAG_description": "",
|
||||
"CLEAR_NEW_FLAG_name": "",
|
||||
"CustProps_cant_remove": "",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "",
|
||||
"DEEP_SLEEP_description": "",
|
||||
"DEEP_SLEEP_name": "",
|
||||
"DISCOVER_PLUGINS_description": "",
|
||||
"DISCOVER_PLUGINS_name": "",
|
||||
"DevDetail_Children_Title": "",
|
||||
"DevDetail_Copy_Device_Title": "",
|
||||
"DevDetail_Copy_Device_Tooltip": "",
|
||||
"DevDetail_CustomProperties_Title": "",
|
||||
"DevDetail_CustomProps_reset_info": "",
|
||||
"DevDetail_DisplayFields_Title": "",
|
||||
"DevDetail_EveandAl_AlertAllEvents": "",
|
||||
"DevDetail_EveandAl_AlertDown": "",
|
||||
"DevDetail_EveandAl_Archived": "",
|
||||
"DevDetail_EveandAl_NewDevice": "",
|
||||
"DevDetail_EveandAl_NewDevice_Tooltip": "",
|
||||
"DevDetail_EveandAl_RandomMAC": "",
|
||||
"DevDetail_EveandAl_ScanCycle": "",
|
||||
"DevDetail_EveandAl_ScanCycle_a": "",
|
||||
"DevDetail_EveandAl_ScanCycle_z": "",
|
||||
"DevDetail_EveandAl_Skip": "",
|
||||
"DevDetail_EveandAl_Title": "",
|
||||
"DevDetail_Events_CheckBox": "",
|
||||
"DevDetail_GoToNetworkNode": "",
|
||||
"DevDetail_Icon": "",
|
||||
"DevDetail_Icon_Descr": "",
|
||||
"DevDetail_Loading": "",
|
||||
"DevDetail_MainInfo_Comments": "",
|
||||
"DevDetail_MainInfo_Favorite": "",
|
||||
"DevDetail_MainInfo_Group": "",
|
||||
"DevDetail_MainInfo_Location": "",
|
||||
"DevDetail_MainInfo_Name": "",
|
||||
"DevDetail_MainInfo_Network": "",
|
||||
"DevDetail_MainInfo_Network_Port": "",
|
||||
"DevDetail_MainInfo_Network_Site": "",
|
||||
"DevDetail_MainInfo_Network_Title": "",
|
||||
"DevDetail_MainInfo_Owner": "",
|
||||
"DevDetail_MainInfo_SSID": "",
|
||||
"DevDetail_MainInfo_Title": "",
|
||||
"DevDetail_MainInfo_Type": "",
|
||||
"DevDetail_MainInfo_Vendor": "",
|
||||
"DevDetail_MainInfo_mac": "",
|
||||
"DevDetail_NavToChildNode": "",
|
||||
"DevDetail_Network_Node_hover": "",
|
||||
"DevDetail_Network_Port_hover": "",
|
||||
"DevDetail_Nmap_Scans": "",
|
||||
"DevDetail_Nmap_Scans_desc": "",
|
||||
"DevDetail_Nmap_buttonDefault": "",
|
||||
"DevDetail_Nmap_buttonDefault_text": "",
|
||||
"DevDetail_Nmap_buttonDetail": "",
|
||||
"DevDetail_Nmap_buttonDetail_text": "",
|
||||
"DevDetail_Nmap_buttonFast": "",
|
||||
"DevDetail_Nmap_buttonFast_text": "",
|
||||
"DevDetail_Nmap_buttonSkipDiscovery": "",
|
||||
"DevDetail_Nmap_buttonSkipDiscovery_text": "",
|
||||
"DevDetail_Nmap_resultsLink": "",
|
||||
"DevDetail_Owner_hover": "",
|
||||
"DevDetail_Periodselect_All": "",
|
||||
"DevDetail_Periodselect_LastMonth": "",
|
||||
"DevDetail_Periodselect_LastWeek": "",
|
||||
"DevDetail_Periodselect_LastYear": "",
|
||||
"DevDetail_Periodselect_today": "",
|
||||
"DevDetail_Run_Actions_Title": "",
|
||||
"DevDetail_Run_Actions_Tooltip": "",
|
||||
"DevDetail_SessionInfo_FirstSession": "",
|
||||
"DevDetail_SessionInfo_LastIP": "",
|
||||
"DevDetail_SessionInfo_LastSession": "",
|
||||
"DevDetail_SessionInfo_StaticIP": "",
|
||||
"DevDetail_SessionInfo_Status": "",
|
||||
"DevDetail_SessionInfo_Title": "",
|
||||
"DevDetail_SessionTable_Additionalinfo": "",
|
||||
"DevDetail_SessionTable_Connection": "",
|
||||
"DevDetail_SessionTable_Disconnection": "",
|
||||
"DevDetail_SessionTable_Duration": "",
|
||||
"DevDetail_SessionTable_IP": "",
|
||||
"DevDetail_SessionTable_Order": "",
|
||||
"DevDetail_Shortcut_CurrentStatus": "",
|
||||
"DevDetail_Shortcut_DownAlerts": "",
|
||||
"DevDetail_Shortcut_Presence": "",
|
||||
"DevDetail_Shortcut_Sessions": "",
|
||||
"DevDetail_Tab_Details": "",
|
||||
"DevDetail_Tab_Events": "",
|
||||
"DevDetail_Tab_EventsTableDate": "",
|
||||
"DevDetail_Tab_EventsTableEvent": "",
|
||||
"DevDetail_Tab_EventsTableIP": "",
|
||||
"DevDetail_Tab_EventsTableInfo": "",
|
||||
"DevDetail_Tab_Nmap": "",
|
||||
"DevDetail_Tab_NmapEmpty": "",
|
||||
"DevDetail_Tab_NmapTableExtra": "",
|
||||
"DevDetail_Tab_NmapTableHeader": "",
|
||||
"DevDetail_Tab_NmapTableIndex": "",
|
||||
"DevDetail_Tab_NmapTablePort": "",
|
||||
"DevDetail_Tab_NmapTableService": "",
|
||||
"DevDetail_Tab_NmapTableState": "",
|
||||
"DevDetail_Tab_NmapTableText": "",
|
||||
"DevDetail_Tab_NmapTableTime": "",
|
||||
"DevDetail_Tab_Plugins": "",
|
||||
"DevDetail_Tab_Presence": "",
|
||||
"DevDetail_Tab_Sessions": "",
|
||||
"DevDetail_Tab_Tools": "",
|
||||
"DevDetail_Tab_Tools_Internet_Info_Description": "",
|
||||
"DevDetail_Tab_Tools_Internet_Info_Error": "",
|
||||
"DevDetail_Tab_Tools_Internet_Info_Start": "",
|
||||
"DevDetail_Tab_Tools_Internet_Info_Title": "",
|
||||
"DevDetail_Tab_Tools_Nslookup_Description": "",
|
||||
"DevDetail_Tab_Tools_Nslookup_Error": "",
|
||||
"DevDetail_Tab_Tools_Nslookup_Start": "",
|
||||
"DevDetail_Tab_Tools_Nslookup_Title": "",
|
||||
"DevDetail_Tab_Tools_Speedtest_Description": "",
|
||||
"DevDetail_Tab_Tools_Speedtest_Start": "",
|
||||
"DevDetail_Tab_Tools_Speedtest_Title": "",
|
||||
"DevDetail_Tab_Tools_Traceroute_Description": "",
|
||||
"DevDetail_Tab_Tools_Traceroute_Error": "",
|
||||
"DevDetail_Tab_Tools_Traceroute_Start": "",
|
||||
"DevDetail_Tab_Tools_Traceroute_Title": "",
|
||||
"DevDetail_Tools_WOL": "",
|
||||
"DevDetail_Tools_WOL_noti": "",
|
||||
"DevDetail_Tools_WOL_noti_text": "",
|
||||
"DevDetail_Type_hover": "",
|
||||
"DevDetail_Vendor_hover": "",
|
||||
"DevDetail_WOL_Title": "",
|
||||
"DevDetail_button_AddIcon": "",
|
||||
"DevDetail_button_AddIcon_Help": "",
|
||||
"DevDetail_button_AddIcon_Tooltip": "",
|
||||
"DevDetail_button_Delete": "",
|
||||
"DevDetail_button_DeleteEvents": "",
|
||||
"DevDetail_button_DeleteEvents_Warning": "",
|
||||
"DevDetail_button_Delete_ask": "",
|
||||
"DevDetail_button_OverwriteIcons": "",
|
||||
"DevDetail_button_OverwriteIcons_Tooltip": "",
|
||||
"DevDetail_button_OverwriteIcons_Warning": "",
|
||||
"DevDetail_button_Reset": "",
|
||||
"DevDetail_button_Save": "",
|
||||
"DeviceEdit_ValidMacIp": "",
|
||||
"Device_MultiEdit": "",
|
||||
"Device_MultiEdit_Backup": "",
|
||||
"Device_MultiEdit_Fields": "",
|
||||
"Device_MultiEdit_MassActions": "",
|
||||
"Device_MultiEdit_No_Devices": "",
|
||||
"Device_MultiEdit_Tooltip": "",
|
||||
"Device_NextScan_Imminent": "",
|
||||
"Device_NextScan_In": "",
|
||||
"Device_NoData_Help": "",
|
||||
"Device_NoData_Scanning": "",
|
||||
"Device_NoData_Title": "",
|
||||
"Device_NoMatch_Title": "",
|
||||
"Device_Save_Failed": "",
|
||||
"Device_Save_Unauthorized": "",
|
||||
"Device_Saved_Success": "",
|
||||
"Device_Saved_Unexpected": "",
|
||||
"Device_Scanning": "",
|
||||
"Device_Searchbox": "",
|
||||
"Device_Shortcut_AllDevices": "",
|
||||
"Device_Shortcut_AllNodes": "",
|
||||
"Device_Shortcut_Archived": "",
|
||||
"Device_Shortcut_Connected": "",
|
||||
"Device_Shortcut_Devices": "",
|
||||
"Device_Shortcut_DownAlerts": "",
|
||||
"Device_Shortcut_DownOnly": "",
|
||||
"Device_Shortcut_Favorites": "",
|
||||
"Device_Shortcut_NewDevices": "",
|
||||
"Device_Shortcut_OnlineChart": "",
|
||||
"Device_Shortcut_Unstable": "",
|
||||
"Device_TableHead_AlertDown": "",
|
||||
"Device_TableHead_Connected_Devices": "",
|
||||
"Device_TableHead_CustomProps": "",
|
||||
"Device_TableHead_FQDN": "",
|
||||
"Device_TableHead_Favorite": "",
|
||||
"Device_TableHead_FirstSession": "",
|
||||
"Device_TableHead_Flapping": "",
|
||||
"Device_TableHead_GUID": "",
|
||||
"Device_TableHead_Group": "",
|
||||
"Device_TableHead_IPv4": "",
|
||||
"Device_TableHead_IPv6": "",
|
||||
"Device_TableHead_Icon": "",
|
||||
"Device_TableHead_LastIP": "",
|
||||
"Device_TableHead_LastIPOrder": "",
|
||||
"Device_TableHead_LastSession": "",
|
||||
"Device_TableHead_Location": "",
|
||||
"Device_TableHead_MAC": "",
|
||||
"Device_TableHead_MAC_full": "",
|
||||
"Device_TableHead_Name": "",
|
||||
"Device_TableHead_NetworkSite": "",
|
||||
"Device_TableHead_Owner": "",
|
||||
"Device_TableHead_ParentRelType": "",
|
||||
"Device_TableHead_Parent_MAC": "",
|
||||
"Device_TableHead_Port": "",
|
||||
"Device_TableHead_PresentLastScan": "",
|
||||
"Device_TableHead_ReqNicsOnline": "",
|
||||
"Device_TableHead_RowID": "",
|
||||
"Device_TableHead_Rowid": "",
|
||||
"Device_TableHead_SSID": "",
|
||||
"Device_TableHead_SourcePlugin": "",
|
||||
"Device_TableHead_Status": "",
|
||||
"Device_TableHead_SyncHubNodeName": "",
|
||||
"Device_TableHead_Type": "",
|
||||
"Device_TableHead_Vendor": "",
|
||||
"Device_TableHead_Vlan": "",
|
||||
"Device_Table_Not_Network_Device": "",
|
||||
"Device_Table_info": "",
|
||||
"Device_Table_nav_next": "",
|
||||
"Device_Table_nav_prev": "",
|
||||
"Device_Tablelenght": "",
|
||||
"Device_Tablelenght_all": "",
|
||||
"Device_Title": "",
|
||||
"Devices_Filters": "",
|
||||
"ENABLE_PLUGINS_description": "",
|
||||
"ENABLE_PLUGINS_name": "",
|
||||
"ENCRYPTION_KEY_description": "",
|
||||
"ENCRYPTION_KEY_name": "",
|
||||
"Email_display_name": "",
|
||||
"Email_icon": "",
|
||||
"Events_Loading": "",
|
||||
"Events_Periodselect_All": "",
|
||||
"Events_Periodselect_LastMonth": "",
|
||||
"Events_Periodselect_LastWeek": "",
|
||||
"Events_Periodselect_LastYear": "",
|
||||
"Events_Periodselect_today": "",
|
||||
"Events_Searchbox": "",
|
||||
"Events_Shortcut_AllEvents": "",
|
||||
"Events_Shortcut_DownAlerts": "",
|
||||
"Events_Shortcut_Events": "",
|
||||
"Events_Shortcut_MissSessions": "",
|
||||
"Events_Shortcut_NewDevices": "",
|
||||
"Events_Shortcut_Sessions": "",
|
||||
"Events_Shortcut_VoidSessions": "",
|
||||
"Events_TableHead_AdditionalInfo": "",
|
||||
"Events_TableHead_Connection": "",
|
||||
"Events_TableHead_Date": "",
|
||||
"Events_TableHead_Device": "",
|
||||
"Events_TableHead_Disconnection": "",
|
||||
"Events_TableHead_Duration": "",
|
||||
"Events_TableHead_DurationOrder": "",
|
||||
"Events_TableHead_EventType": "",
|
||||
"Events_TableHead_IP": "",
|
||||
"Events_TableHead_IPOrder": "",
|
||||
"Events_TableHead_Order": "",
|
||||
"Events_TableHead_Owner": "",
|
||||
"Events_TableHead_PendingAlert": "",
|
||||
"Events_Table_info": "",
|
||||
"Events_Table_nav_next": "",
|
||||
"Events_Table_nav_prev": "",
|
||||
"Events_Tablelenght": "",
|
||||
"Events_Tablelenght_all": "",
|
||||
"Events_Title": "",
|
||||
"FakeMAC_hover": "",
|
||||
"FieldLock_Error": "",
|
||||
"FieldLock_Lock_Tooltip": "",
|
||||
"FieldLock_Locked": "",
|
||||
"FieldLock_SaveBeforeLocking": "",
|
||||
"FieldLock_Source_Label": "",
|
||||
"FieldLock_Unlock_Tooltip": "",
|
||||
"FieldLock_Unlocked": "",
|
||||
"GRAPHQL_PORT_description": "",
|
||||
"GRAPHQL_PORT_name": "",
|
||||
"Gen_Action": "",
|
||||
"Gen_Add": "",
|
||||
"Gen_AddDevice": "",
|
||||
"Gen_Add_All": "",
|
||||
"Gen_All_Devices": "",
|
||||
"Gen_Archived": "",
|
||||
"Gen_AreYouSure": "",
|
||||
"Gen_Backup": "",
|
||||
"Gen_Cancel": "",
|
||||
"Gen_Change": "",
|
||||
"Gen_Copy": "",
|
||||
"Gen_CopyToClipboard": "",
|
||||
"Gen_DataUpdatedUITakesTime": "",
|
||||
"Gen_Delete": "",
|
||||
"Gen_DeleteAll": "",
|
||||
"Gen_Description": "",
|
||||
"Gen_Down": "",
|
||||
"Gen_Error": "",
|
||||
"Gen_Filter": "",
|
||||
"Gen_Flapping": "",
|
||||
"Gen_Generate": "",
|
||||
"Gen_InvalidMac": "",
|
||||
"Gen_Invalid_Value": "",
|
||||
"Gen_LockedDB": "",
|
||||
"Gen_NetworkMask": "",
|
||||
"Gen_New": "",
|
||||
"Gen_No_Data": "",
|
||||
"Gen_Offline": "",
|
||||
"Gen_Okay": "",
|
||||
"Gen_Online": "",
|
||||
"Gen_Purge": "",
|
||||
"Gen_ReadDocs": "",
|
||||
"Gen_Remove_All": "",
|
||||
"Gen_Remove_Last": "",
|
||||
"Gen_Reset": "",
|
||||
"Gen_Restore": "",
|
||||
"Gen_Run": "",
|
||||
"Gen_Save": "",
|
||||
"Gen_Saved": "",
|
||||
"Gen_Search": "",
|
||||
"Gen_Select": "",
|
||||
"Gen_SelectIcon": "",
|
||||
"Gen_SelectToPreview": "",
|
||||
"Gen_Selected_Devices": "",
|
||||
"Gen_Sleeping": "",
|
||||
"Gen_Subnet": "",
|
||||
"Gen_Switch": "",
|
||||
"Gen_Upd": "",
|
||||
"Gen_Upd_Fail": "",
|
||||
"Gen_Update": "",
|
||||
"Gen_Update_Value": "",
|
||||
"Gen_ValidIcon": "",
|
||||
"Gen_Warning": "",
|
||||
"Gen_Work_In_Progress": "",
|
||||
"Gen_create_new_device": "",
|
||||
"Gen_create_new_device_info": "",
|
||||
"General_display_name": "",
|
||||
"General_icon": "",
|
||||
"HRS_TO_KEEP_NEWDEV_description": "",
|
||||
"HRS_TO_KEEP_NEWDEV_name": "",
|
||||
"HRS_TO_KEEP_OFFDEV_description": "",
|
||||
"HRS_TO_KEEP_OFFDEV_name": "",
|
||||
"LOADED_PLUGINS_description": "",
|
||||
"LOADED_PLUGINS_name": "",
|
||||
"LOG_LEVEL_description": "",
|
||||
"LOG_LEVEL_name": "",
|
||||
"Loading": "",
|
||||
"Login_Box": "",
|
||||
"Login_Default_PWD": "",
|
||||
"Login_Info": "",
|
||||
"Login_Psw-box": "",
|
||||
"Login_Psw_alert": "",
|
||||
"Login_Psw_folder": "",
|
||||
"Login_Psw_new": "",
|
||||
"Login_Psw_run": "",
|
||||
"Login_Remember": "",
|
||||
"Login_Remember_small": "",
|
||||
"Login_Submit": "",
|
||||
"Login_Toggle_Alert_headline": "",
|
||||
"Login_Toggle_Info": "",
|
||||
"Login_Toggle_Info_headline": "",
|
||||
"Maint_PurgeLog": "",
|
||||
"Maint_RestartServer": "",
|
||||
"Maint_Restart_Server_noti_text": "",
|
||||
"Maintenance_InitCheck": "",
|
||||
"Maintenance_InitCheck_Checking": "",
|
||||
"Maintenance_InitCheck_QuickSetupGuide": "",
|
||||
"Maintenance_InitCheck_Success": "",
|
||||
"Maintenance_ReCheck": "",
|
||||
"Maintenance_Running_Version": "",
|
||||
"Maintenance_Status": "",
|
||||
"Maintenance_Title": "",
|
||||
"Maintenance_Tool_DownloadConfig": "",
|
||||
"Maintenance_Tool_DownloadConfig_text": "",
|
||||
"Maintenance_Tool_DownloadWorkflows": "",
|
||||
"Maintenance_Tool_DownloadWorkflows_text": "",
|
||||
"Maintenance_Tool_ExportCSV": "",
|
||||
"Maintenance_Tool_ExportCSV_noti": "",
|
||||
"Maintenance_Tool_ExportCSV_noti_text": "",
|
||||
"Maintenance_Tool_ExportCSV_text": "",
|
||||
"Maintenance_Tool_ImportCSV": "",
|
||||
"Maintenance_Tool_ImportCSV_noti": "",
|
||||
"Maintenance_Tool_ImportCSV_noti_text": "",
|
||||
"Maintenance_Tool_ImportCSV_text": "",
|
||||
"Maintenance_Tool_ImportConfig_noti": "",
|
||||
"Maintenance_Tool_ImportPastedCSV": "",
|
||||
"Maintenance_Tool_ImportPastedCSV_noti_text": "",
|
||||
"Maintenance_Tool_ImportPastedCSV_text": "",
|
||||
"Maintenance_Tool_ImportPastedConfig": "",
|
||||
"Maintenance_Tool_ImportPastedConfig_noti_text": "",
|
||||
"Maintenance_Tool_ImportPastedConfig_text": "",
|
||||
"Maintenance_Tool_UnlockFields": "",
|
||||
"Maintenance_Tool_UnlockFields_noti": "",
|
||||
"Maintenance_Tool_UnlockFields_noti_text": "",
|
||||
"Maintenance_Tool_UnlockFields_text": "",
|
||||
"Maintenance_Tool_arpscansw": "",
|
||||
"Maintenance_Tool_arpscansw_noti": "",
|
||||
"Maintenance_Tool_arpscansw_noti_text": "",
|
||||
"Maintenance_Tool_arpscansw_text": "",
|
||||
"Maintenance_Tool_backup": "",
|
||||
"Maintenance_Tool_backup_noti": "",
|
||||
"Maintenance_Tool_backup_noti_text": "",
|
||||
"Maintenance_Tool_backup_text": "",
|
||||
"Maintenance_Tool_check_visible": "",
|
||||
"Maintenance_Tool_clearSourceFields_selected": "",
|
||||
"Maintenance_Tool_clearSourceFields_selected_noti": "",
|
||||
"Maintenance_Tool_clearSourceFields_selected_text": "",
|
||||
"Maintenance_Tool_darkmode": "",
|
||||
"Maintenance_Tool_darkmode_noti": "",
|
||||
"Maintenance_Tool_darkmode_noti_text": "",
|
||||
"Maintenance_Tool_darkmode_text": "",
|
||||
"Maintenance_Tool_del_ActHistory": "",
|
||||
"Maintenance_Tool_del_ActHistory_noti": "",
|
||||
"Maintenance_Tool_del_ActHistory_noti_text": "",
|
||||
"Maintenance_Tool_del_ActHistory_text": "",
|
||||
"Maintenance_Tool_del_alldev": "",
|
||||
"Maintenance_Tool_del_alldev_noti": "",
|
||||
"Maintenance_Tool_del_alldev_noti_text": "",
|
||||
"Maintenance_Tool_del_alldev_text": "",
|
||||
"Maintenance_Tool_del_allevents": "",
|
||||
"Maintenance_Tool_del_allevents30": "",
|
||||
"Maintenance_Tool_del_allevents30_noti": "",
|
||||
"Maintenance_Tool_del_allevents30_noti_text": "",
|
||||
"Maintenance_Tool_del_allevents30_text": "",
|
||||
"Maintenance_Tool_del_allevents_noti": "",
|
||||
"Maintenance_Tool_del_allevents_noti_text": "",
|
||||
"Maintenance_Tool_del_allevents_text": "",
|
||||
"Maintenance_Tool_del_empty_macs": "",
|
||||
"Maintenance_Tool_del_empty_macs_noti": "",
|
||||
"Maintenance_Tool_del_empty_macs_noti_text": "",
|
||||
"Maintenance_Tool_del_empty_macs_text": "",
|
||||
"Maintenance_Tool_del_selecteddev": "",
|
||||
"Maintenance_Tool_del_selecteddev_text": "",
|
||||
"Maintenance_Tool_del_unknowndev": "",
|
||||
"Maintenance_Tool_del_unknowndev_noti": "",
|
||||
"Maintenance_Tool_del_unknowndev_noti_text": "",
|
||||
"Maintenance_Tool_del_unknowndev_text": "",
|
||||
"Maintenance_Tool_del_unlockFields_selecteddev_text": "",
|
||||
"Maintenance_Tool_displayed_columns_text": "",
|
||||
"Maintenance_Tool_drag_me": "",
|
||||
"Maintenance_Tool_order_columns_text": "",
|
||||
"Maintenance_Tool_purgebackup": "",
|
||||
"Maintenance_Tool_purgebackup_noti": "",
|
||||
"Maintenance_Tool_purgebackup_noti_text": "",
|
||||
"Maintenance_Tool_purgebackup_text": "",
|
||||
"Maintenance_Tool_restore": "",
|
||||
"Maintenance_Tool_restore_noti": "",
|
||||
"Maintenance_Tool_restore_noti_text": "",
|
||||
"Maintenance_Tool_restore_text": "",
|
||||
"Maintenance_Tool_unlockFields_selecteddev": "",
|
||||
"Maintenance_Tool_unlockFields_selecteddev_noti": "",
|
||||
"Maintenance_Tool_upgrade_database_noti": "",
|
||||
"Maintenance_Tool_upgrade_database_noti_text": "",
|
||||
"Maintenance_Tool_upgrade_database_text": "",
|
||||
"Maintenance_Tools_Tab_BackupRestore": "",
|
||||
"Maintenance_Tools_Tab_Logging": "",
|
||||
"Maintenance_Tools_Tab_Settings": "",
|
||||
"Maintenance_Tools_Tab_Tools": "",
|
||||
"Maintenance_Tools_Tab_UISettings": "",
|
||||
"Maintenance_arp_status": "",
|
||||
"Maintenance_arp_status_off": "",
|
||||
"Maintenance_arp_status_on": "",
|
||||
"Maintenance_built_on": "",
|
||||
"Maintenance_current_version": "",
|
||||
"Maintenance_database_backup": "",
|
||||
"Maintenance_database_backup_found": "",
|
||||
"Maintenance_database_backup_total": "",
|
||||
"Maintenance_database_lastmod": "",
|
||||
"Maintenance_database_path": "",
|
||||
"Maintenance_database_rows": "",
|
||||
"Maintenance_database_size": "",
|
||||
"Maintenance_lang_selector_apply": "",
|
||||
"Maintenance_lang_selector_empty": "",
|
||||
"Maintenance_lang_selector_lable": "",
|
||||
"Maintenance_lang_selector_text": "",
|
||||
"Maintenance_new_version": "",
|
||||
"Maintenance_themeselector_apply": "",
|
||||
"Maintenance_themeselector_empty": "",
|
||||
"Maintenance_themeselector_lable": "",
|
||||
"Maintenance_themeselector_text": "",
|
||||
"Maintenance_version": "",
|
||||
"NETWORK_DEVICE_TYPES_description": "",
|
||||
"NETWORK_DEVICE_TYPES_name": "",
|
||||
"Navigation_About": "",
|
||||
"Navigation_AppEvents": "",
|
||||
"Navigation_Devices": "",
|
||||
"Navigation_Donations": "",
|
||||
"Navigation_Events": "",
|
||||
"Navigation_Integrations": "",
|
||||
"Navigation_Maintenance": "",
|
||||
"Navigation_Monitoring": "",
|
||||
"Navigation_Network": "",
|
||||
"Navigation_Notifications": "",
|
||||
"Navigation_Plugins": "",
|
||||
"Navigation_Presence": "",
|
||||
"Navigation_Report": "",
|
||||
"Navigation_Settings": "",
|
||||
"Navigation_SystemInfo": "",
|
||||
"Navigation_Workflows": "",
|
||||
"Network_Assign": "",
|
||||
"Network_Cant_Assign": "",
|
||||
"Network_Cant_Assign_No_Node_Selected": "",
|
||||
"Network_Configuration_Error": "",
|
||||
"Network_Connected": "",
|
||||
"Network_Devices": "",
|
||||
"Network_ManageAdd": "",
|
||||
"Network_ManageAdd_Name": "",
|
||||
"Network_ManageAdd_Name_text": "",
|
||||
"Network_ManageAdd_Port": "",
|
||||
"Network_ManageAdd_Port_text": "",
|
||||
"Network_ManageAdd_Submit": "",
|
||||
"Network_ManageAdd_Type": "",
|
||||
"Network_ManageAdd_Type_text": "",
|
||||
"Network_ManageAssign": "",
|
||||
"Network_ManageDel": "",
|
||||
"Network_ManageDel_Name": "",
|
||||
"Network_ManageDel_Name_text": "",
|
||||
"Network_ManageDel_Submit": "",
|
||||
"Network_ManageDevices": "",
|
||||
"Network_ManageEdit": "",
|
||||
"Network_ManageEdit_ID": "",
|
||||
"Network_ManageEdit_ID_text": "",
|
||||
"Network_ManageEdit_Name": "",
|
||||
"Network_ManageEdit_Name_text": "",
|
||||
"Network_ManageEdit_Port": "",
|
||||
"Network_ManageEdit_Port_text": "",
|
||||
"Network_ManageEdit_Submit": "",
|
||||
"Network_ManageEdit_Type": "",
|
||||
"Network_ManageEdit_Type_text": "",
|
||||
"Network_ManageLeaf": "",
|
||||
"Network_ManageUnassign": "",
|
||||
"Network_NoAssignedDevices": "",
|
||||
"Network_NoDevices": "",
|
||||
"Network_Node": "",
|
||||
"Network_Node_Name": "",
|
||||
"Network_Parent": "",
|
||||
"Network_Root": "",
|
||||
"Network_Root_Not_Configured": "",
|
||||
"Network_Root_Unconfigurable": "",
|
||||
"Network_ShowArchived": "",
|
||||
"Network_ShowOffline": "",
|
||||
"Network_Table_Hostname": "",
|
||||
"Network_Table_IP": "",
|
||||
"Network_Table_State": "",
|
||||
"Network_Title": "",
|
||||
"Network_UnassignedDevices": "",
|
||||
"Notifications_All": "",
|
||||
"Notifications_Mark_All_Read": "",
|
||||
"PIALERT_WEB_PASSWORD_description": "",
|
||||
"PIALERT_WEB_PASSWORD_name": "",
|
||||
"PIALERT_WEB_PROTECTION_description": "",
|
||||
"PIALERT_WEB_PROTECTION_name": "",
|
||||
"PLUGINS_KEEP_HIST_description": "",
|
||||
"PLUGINS_KEEP_HIST_name": "",
|
||||
"PRAGMA_JOURNAL_SIZE_LIMIT_description": "",
|
||||
"PRAGMA_JOURNAL_SIZE_LIMIT_name": "",
|
||||
"Plugins_DeleteAll": "",
|
||||
"Plugins_Filters_Mac": "",
|
||||
"Plugins_History": "",
|
||||
"Plugins_Obj_DeleteListed": "",
|
||||
"Plugins_Objects": "",
|
||||
"Plugins_Out_of": "",
|
||||
"Plugins_Unprocessed_Events": "",
|
||||
"Plugins_no_control": "",
|
||||
"Presence_CalHead_day": "",
|
||||
"Presence_CalHead_lang": "",
|
||||
"Presence_CalHead_month": "",
|
||||
"Presence_CalHead_quarter": "",
|
||||
"Presence_CalHead_week": "",
|
||||
"Presence_CalHead_year": "",
|
||||
"Presence_CallHead_Devices": "",
|
||||
"Presence_Key_OnlineNow": "",
|
||||
"Presence_Key_OnlineNow_desc": "",
|
||||
"Presence_Key_OnlinePast": "",
|
||||
"Presence_Key_OnlinePastMiss": "",
|
||||
"Presence_Key_OnlinePastMiss_desc": "",
|
||||
"Presence_Key_OnlinePast_desc": "",
|
||||
"Presence_Loading": "",
|
||||
"Presence_Shortcut_AllDevices": "",
|
||||
"Presence_Shortcut_Archived": "",
|
||||
"Presence_Shortcut_Connected": "",
|
||||
"Presence_Shortcut_Devices": "",
|
||||
"Presence_Shortcut_DownAlerts": "",
|
||||
"Presence_Shortcut_Favorites": "",
|
||||
"Presence_Shortcut_NewDevices": "",
|
||||
"Presence_Title": "",
|
||||
"REFRESH_FQDN_description": "",
|
||||
"REFRESH_FQDN_name": "",
|
||||
"REPORT_DASHBOARD_URL_description": "",
|
||||
"REPORT_DASHBOARD_URL_name": "",
|
||||
"REPORT_ERROR": "",
|
||||
"REPORT_MAIL_description": "",
|
||||
"REPORT_MAIL_name": "",
|
||||
"REPORT_TITLE": "",
|
||||
"RandomMAC_hover": "",
|
||||
"Reports_Sent_Log": "",
|
||||
"SCAN_SUBNETS_description": "",
|
||||
"SCAN_SUBNETS_name": "",
|
||||
"SYSTEM_TITLE": "",
|
||||
"Setting_Override": "",
|
||||
"Setting_Override_Description": "",
|
||||
"Settings_Metadata_Toggle": "",
|
||||
"Settings_Show_Description": "",
|
||||
"Settings_device_Scanners_desync": "",
|
||||
"Settings_device_Scanners_desync_popup": "",
|
||||
"Speedtest_Results": "",
|
||||
"Systeminfo_AvailableIps": "",
|
||||
"Systeminfo_CPU": "",
|
||||
"Systeminfo_CPU_Cores": "",
|
||||
"Systeminfo_CPU_Name": "",
|
||||
"Systeminfo_CPU_Speed": "",
|
||||
"Systeminfo_CPU_Temp": "",
|
||||
"Systeminfo_CPU_Vendor": "",
|
||||
"Systeminfo_Client_Resolution": "",
|
||||
"Systeminfo_Client_User_Agent": "",
|
||||
"Systeminfo_General": "",
|
||||
"Systeminfo_General_Date": "",
|
||||
"Systeminfo_General_Date2": "",
|
||||
"Systeminfo_General_Full_Date": "",
|
||||
"Systeminfo_General_TimeZone": "",
|
||||
"Systeminfo_Memory": "",
|
||||
"Systeminfo_Memory_Total_Memory": "",
|
||||
"Systeminfo_Memory_Usage": "",
|
||||
"Systeminfo_Memory_Usage_Percent": "",
|
||||
"Systeminfo_Motherboard": "",
|
||||
"Systeminfo_Motherboard_BIOS": "",
|
||||
"Systeminfo_Motherboard_BIOS_Date": "",
|
||||
"Systeminfo_Motherboard_BIOS_Vendor": "",
|
||||
"Systeminfo_Motherboard_Manufactured": "",
|
||||
"Systeminfo_Motherboard_Name": "",
|
||||
"Systeminfo_Motherboard_Revision": "",
|
||||
"Systeminfo_Network": "",
|
||||
"Systeminfo_Network_Accept_Encoding": "",
|
||||
"Systeminfo_Network_Accept_Language": "",
|
||||
"Systeminfo_Network_Connection_Port": "",
|
||||
"Systeminfo_Network_HTTP_Host": "",
|
||||
"Systeminfo_Network_HTTP_Referer": "",
|
||||
"Systeminfo_Network_HTTP_Referer_String": "",
|
||||
"Systeminfo_Network_Hardware": "",
|
||||
"Systeminfo_Network_Hardware_Interface_Mask": "",
|
||||
"Systeminfo_Network_Hardware_Interface_Name": "",
|
||||
"Systeminfo_Network_Hardware_Interface_RX": "",
|
||||
"Systeminfo_Network_Hardware_Interface_TX": "",
|
||||
"Systeminfo_Network_IP": "",
|
||||
"Systeminfo_Network_IP_Connection": "",
|
||||
"Systeminfo_Network_IP_Server": "",
|
||||
"Systeminfo_Network_MIME": "",
|
||||
"Systeminfo_Network_Request_Method": "",
|
||||
"Systeminfo_Network_Request_Time": "",
|
||||
"Systeminfo_Network_Request_URI": "",
|
||||
"Systeminfo_Network_Secure_Connection": "",
|
||||
"Systeminfo_Network_Secure_Connection_String": "",
|
||||
"Systeminfo_Network_Server_Name": "",
|
||||
"Systeminfo_Network_Server_Name_String": "",
|
||||
"Systeminfo_Network_Server_Query": "",
|
||||
"Systeminfo_Network_Server_Query_String": "",
|
||||
"Systeminfo_Network_Server_Version": "",
|
||||
"Systeminfo_Services": "",
|
||||
"Systeminfo_Services_Description": "",
|
||||
"Systeminfo_Services_Name": "",
|
||||
"Systeminfo_Storage": "",
|
||||
"Systeminfo_Storage_Device": "",
|
||||
"Systeminfo_Storage_Mount": "",
|
||||
"Systeminfo_Storage_Size": "",
|
||||
"Systeminfo_Storage_Type": "",
|
||||
"Systeminfo_Storage_Usage": "",
|
||||
"Systeminfo_Storage_Usage_Free": "",
|
||||
"Systeminfo_Storage_Usage_Mount": "",
|
||||
"Systeminfo_Storage_Usage_Total": "",
|
||||
"Systeminfo_Storage_Usage_Used": "",
|
||||
"Systeminfo_System": "",
|
||||
"Systeminfo_System_AVG": "",
|
||||
"Systeminfo_System_Architecture": "",
|
||||
"Systeminfo_System_Kernel": "",
|
||||
"Systeminfo_System_OSVersion": "",
|
||||
"Systeminfo_System_Running_Processes": "",
|
||||
"Systeminfo_System_System": "",
|
||||
"Systeminfo_System_Uname": "",
|
||||
"Systeminfo_System_Uptime": "",
|
||||
"Systeminfo_This_Client": "",
|
||||
"Systeminfo_USB_Devices": "",
|
||||
"TICKER_MIGRATE_TO_NETALERTX": "",
|
||||
"TIMEZONE_description": "",
|
||||
"TIMEZONE_name": "",
|
||||
"UI_DEV_SECTIONS_description": "",
|
||||
"UI_DEV_SECTIONS_name": "",
|
||||
"UI_ICONS_description": "",
|
||||
"UI_ICONS_name": "",
|
||||
"UI_LANG_description": "",
|
||||
"UI_LANG_name": "",
|
||||
"UI_MY_DEVICES_description": "",
|
||||
"UI_MY_DEVICES_name": "",
|
||||
"UI_NOT_RANDOM_MAC_description": "",
|
||||
"UI_NOT_RANDOM_MAC_name": "",
|
||||
"UI_PRESENCE_description": "",
|
||||
"UI_PRESENCE_name": "",
|
||||
"UI_REFRESH_description": "",
|
||||
"UI_REFRESH_name": "",
|
||||
"VERSION_description": "",
|
||||
"VERSION_name": "",
|
||||
"WF_Action_Add": "",
|
||||
"WF_Action_field": "",
|
||||
"WF_Action_type": "",
|
||||
"WF_Action_value": "",
|
||||
"WF_Actions": "",
|
||||
"WF_Add": "",
|
||||
"WF_Add_Condition": "",
|
||||
"WF_Add_Group": "",
|
||||
"WF_Condition_field": "",
|
||||
"WF_Condition_operator": "",
|
||||
"WF_Condition_value": "",
|
||||
"WF_Conditions": "",
|
||||
"WF_Conditions_logic_rules": "",
|
||||
"WF_Duplicate": "",
|
||||
"WF_Enabled": "",
|
||||
"WF_Export": "",
|
||||
"WF_Export_Copy": "",
|
||||
"WF_Import": "",
|
||||
"WF_Import_Copy": "",
|
||||
"WF_Name": "",
|
||||
"WF_Remove": "",
|
||||
"WF_Remove_Copy": "",
|
||||
"WF_Save": "",
|
||||
"WF_Trigger": "",
|
||||
"WF_Trigger_event_type": "",
|
||||
"WF_Trigger_type": "",
|
||||
"add_icon_event_tooltip": "",
|
||||
"add_option_event_tooltip": "",
|
||||
"copy_icons_event_tooltip": "",
|
||||
"devices_old": "",
|
||||
"general_event_description": "",
|
||||
"general_event_title": "",
|
||||
"go_to_device_event_tooltip": "",
|
||||
"go_to_node_event_tooltip": "",
|
||||
"new_version_available": "",
|
||||
"report_guid": "",
|
||||
"report_guid_missing": "",
|
||||
"report_select_format": "",
|
||||
"report_time": "",
|
||||
"run_event_tooltip": "",
|
||||
"select_icon_event_tooltip": "",
|
||||
"settings_core_icon": "",
|
||||
"settings_core_label": "",
|
||||
"settings_device_scanners": "",
|
||||
"settings_device_scanners_icon": "",
|
||||
"settings_device_scanners_info": "",
|
||||
"settings_device_scanners_label": "",
|
||||
"settings_enabled": "",
|
||||
"settings_enabled_icon": "",
|
||||
"settings_expand_all": "",
|
||||
"settings_imported": "",
|
||||
"settings_imported_label": "",
|
||||
"settings_missing": "",
|
||||
"settings_missing_block": "",
|
||||
"settings_old": "",
|
||||
"settings_other_scanners": "",
|
||||
"settings_other_scanners_icon": "",
|
||||
"settings_other_scanners_label": "",
|
||||
"settings_publishers": "",
|
||||
"settings_publishers_icon": "",
|
||||
"settings_publishers_info": "",
|
||||
"settings_publishers_label": "",
|
||||
"settings_readonly": "",
|
||||
"settings_saved": "",
|
||||
"settings_system_icon": "",
|
||||
"settings_system_label": "",
|
||||
"settings_update_item_warning": "",
|
||||
"test_event_tooltip": ""
|
||||
}
|
||||
@@ -66,6 +66,8 @@
|
||||
"CustProps_cant_remove": "Suppression impossible, au moins une donnée est requise.",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "Il s'agit d'un paramètre de maintenance. Il indique le nombre de jours pendant lesquels les entrées d'événements seront conservées. Tous les événements plus anciens seront supprimés périodiquement. S'applique également à l'historique des événements du plugin.",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "Supprimer les événements plus anciens que",
|
||||
"DEEP_SLEEP_description": "Diminue l'utilisation du processeur, en augmentant les temps de repos entre les cycles de calcul. Quand activé, les scans peuvent être retardés jusqu'à 1 minute, et l'interface peut être moins réactive.",
|
||||
"DEEP_SLEEP_name": "Veille profonde",
|
||||
"DISCOVER_PLUGINS_description": "Désactivez cette option pour accélérer le démarrage et l'enregistrement de paramètres. Quand elle est désactivée, les plugins ne sont pas découverts, et vous ne pouvez près ajouter de nouveaux plugins au paramètre <code>LOADED_PLUGINS</code>.",
|
||||
"DISCOVER_PLUGINS_name": "Découvrir des plugins",
|
||||
"DevDetail_Children_Title": "Relations avec les éléments inférieurs",
|
||||
@@ -117,7 +119,7 @@
|
||||
"DevDetail_Nmap_buttonFast": "Scan rapide",
|
||||
"DevDetail_Nmap_buttonFast_text": "Scan rapide : analyse moins de ports (100) que le scan par défaut (plusieurs secondes)",
|
||||
"DevDetail_Nmap_buttonSkipDiscovery": "Passer la découverte d'hôtes",
|
||||
"DevDetail_Nmap_buttonSkipDiscovery_text": "Passer la découverte d'hôtes (option -PN) : scan par défaut sans découvert d'hôtes",
|
||||
"DevDetail_Nmap_buttonSkipDiscovery_text": "Ignorer la découverte d'hôtes (option -PN) : scan par défaut sans découverte d'hôtes",
|
||||
"DevDetail_Nmap_resultsLink": "Vous pouvez quitter cette page après lancement du scan. Les resultats seront aussi disponibles dans le fichier <code>app_front.log</code>.",
|
||||
"DevDetail_Owner_hover": "Possesseur de l'appareil. Texte libre.",
|
||||
"DevDetail_Periodselect_All": "Toutes les infos",
|
||||
@@ -232,7 +234,7 @@
|
||||
"Device_TableHead_FQDN": "Nom de domaine FQDN",
|
||||
"Device_TableHead_Favorite": "Favori",
|
||||
"Device_TableHead_FirstSession": "Première session",
|
||||
"Device_TableHead_Flapping": "Flapping",
|
||||
"Device_TableHead_Flapping": "Bagotage",
|
||||
"Device_TableHead_GUID": "GUID",
|
||||
"Device_TableHead_Group": "Groupe",
|
||||
"Device_TableHead_IPv4": "IPv4",
|
||||
@@ -247,8 +249,8 @@
|
||||
"Device_TableHead_Name": "Nom",
|
||||
"Device_TableHead_NetworkSite": "Site Réseau",
|
||||
"Device_TableHead_Owner": "Propriétaire",
|
||||
"Device_TableHead_ParentRelType": "Type de relation",
|
||||
"Device_TableHead_Parent_MAC": "Nœud réseau principal",
|
||||
"Device_TableHead_ParentRelType": "Relation",
|
||||
"Device_TableHead_Parent_MAC": "Nœud principal",
|
||||
"Device_TableHead_Port": "Port",
|
||||
"Device_TableHead_PresentLastScan": "Présence",
|
||||
"Device_TableHead_ReqNicsOnline": "Nécessite que l'interface réseau (NIC) soit connectée",
|
||||
@@ -337,13 +339,14 @@
|
||||
"Gen_Down": "En panne",
|
||||
"Gen_Error": "Erreur",
|
||||
"Gen_Filter": "Filtrer",
|
||||
"Gen_Flapping": "Flapping",
|
||||
"Gen_Flapping": "Bagotage",
|
||||
"Gen_Generate": "Générer",
|
||||
"Gen_InvalidMac": "Adresse MAC invalide.",
|
||||
"Gen_Invalid_Value": "Une valeur invalide a été renseignée",
|
||||
"Gen_LockedDB": "Erreur - La base de données est peut-être verrouillée - Vérifier avec les outils de dév via F12 -> Console ou essayer plus tard.",
|
||||
"Gen_NetworkMask": "Masque réseau",
|
||||
"Gen_New": "Nouveau",
|
||||
"Gen_No_Data": "Aucune donnée",
|
||||
"Gen_Offline": "Hors ligne",
|
||||
"Gen_Okay": "OK",
|
||||
"Gen_Online": "En ligne",
|
||||
@@ -400,7 +403,7 @@
|
||||
"Login_Toggle_Info_headline": "Information sur le mot de passe",
|
||||
"Maint_PurgeLog": "Nettoyer les logs",
|
||||
"Maint_RestartServer": "Relancer le serveur",
|
||||
"Maint_Restart_Server_noti_text": "Êtes-vous sûr de vouloir relancer le serveur back-end ? Cela peut causer des incohérences avec l'application. Sauvegarder vos paramètres en premier lieu. <br/> <br/> Remarque : cela peut prendre quelques minutes.",
|
||||
"Maint_Restart_Server_noti_text": "Êtes-vous sûr de vouloir relancer le serveur back-end ? Cela peut causer des incohérences avec l'application. Sauvegarder vos paramètres en premier lieu. <br/> <br/> Remarque : cela peut prendre quelques minutes.",
|
||||
"Maintenance_InitCheck": "Vérification initiale",
|
||||
"Maintenance_InitCheck_Checking": "Vérification…",
|
||||
"Maintenance_InitCheck_QuickSetupGuide": "Assurez-vous de suivre le <a href=\"https://docs.netalertx.com/INITIAL_SETUP/\" target=\"_blank\">guide de démarrage rapide</a>.",
|
||||
@@ -475,7 +478,7 @@
|
||||
"Maintenance_Tool_del_unknowndev_noti_text": "Êtes-vous sûr de vouloir supprimer tous les appareils inconnus et sans nom trouvé ?",
|
||||
"Maintenance_Tool_del_unknowndev_text": "Avant d'utiliser cette fonction, veuillez effectuer une sauvegarde. La suppression ne peut pas être annulée. Tous les appareils nommés (inconnus) seront supprimés de la base de données.",
|
||||
"Maintenance_Tool_del_unlockFields_selecteddev_text": "Cela va déverrouiller les champs verrouillés par l'utilisateur (LOCKED/USER) des appareils sélectionnés. Cette action ne peut pas être annulée.",
|
||||
"Maintenance_Tool_displayed_columns_text": "Changer la visibilité et l'ordre des colonnes dans la page <a href=\"devices.php\"><b> <i class=\"fa fa-laptop\"></i>appareils</b></a> page.",
|
||||
"Maintenance_Tool_displayed_columns_text": "Changer la visibilité et l'ordre des colonnes dans la page <a href=\"devices.php\"><b> <i class=\"fa fa-laptop\"></i>Appareils</b></a>.",
|
||||
"Maintenance_Tool_drag_me": "Déplacez-moi pour réordonner les colonnes.",
|
||||
"Maintenance_Tool_order_columns_text": "Maintenance_Tool_order_columns_text",
|
||||
"Maintenance_Tool_purgebackup": "Supprimer les sauvegardes",
|
||||
@@ -568,7 +571,7 @@
|
||||
"Network_ManageEdit_Type_text": "-- Sélectionner le type --",
|
||||
"Network_ManageLeaf": "Gérer l'assignation",
|
||||
"Network_ManageUnassign": "Désassigner",
|
||||
"Network_NoAssignedDevices": "Ce nœud réseau ne contient pas d'appareils assignés. Vous pouvez en assigner un ci-dessous, ou en allant dans l'onglet <b><i class=\"fa fa-info-circle\"></i> Détails</b> d'un appareil depuis le menu <a href=\"devices.php\"><b> <i class=\"fa fa-laptop\"></i> Appareils</b></a>, et assigner cet équipement à un <b><i class=\"fa fa-server\"></i> Nœud (MAC)</b> réseau et à un <b><i class=\"fa fa-ethernet\"></i>Port</b>.",
|
||||
"Network_NoAssignedDevices": "Ce nœud réseau ne contient pas d'appareils assignés. Vous pouvez en assigner un ci-dessous, ou en allant dans l'onglet <b><i class=\"fa fa-info-circle\"></i>Détails</b> d'un appareil depuis le menu <a href=\"devices.php\"><b> <i class=\"fa fa-laptop\"></i>Appareils</b></a>, et assigner cet équipement à un <b><i class=\"fa fa-server\"></i>Nœud (MAC)</b> réseau et à un <b><i class=\"fa fa-ethernet\"></i>Port</b>.",
|
||||
"Network_NoDevices": "Pas d'appareil à configurer",
|
||||
"Network_Node": "Nœud réseau",
|
||||
"Network_Node_Name": "Nom du nœud",
|
||||
@@ -805,4 +808,4 @@
|
||||
"settings_system_label": "Système",
|
||||
"settings_update_item_warning": "Mettre à jour la valeur ci-dessous. Veillez à bien suivre le même format qu'auparavant. <b>Il n'y a pas de pas de contrôle.</b>",
|
||||
"test_event_tooltip": "Enregistrer d'abord vos modifications avant de tester vôtre paramétrage."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,6 +66,8 @@
|
||||
"CustProps_cant_remove": "",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "",
|
||||
"DEEP_SLEEP_description": "",
|
||||
"DEEP_SLEEP_name": "",
|
||||
"DISCOVER_PLUGINS_description": "",
|
||||
"DISCOVER_PLUGINS_name": "",
|
||||
"DevDetail_Children_Title": "",
|
||||
@@ -344,6 +346,7 @@
|
||||
"Gen_LockedDB": "",
|
||||
"Gen_NetworkMask": "",
|
||||
"Gen_New": "",
|
||||
"Gen_No_Data": "",
|
||||
"Gen_Offline": "",
|
||||
"Gen_Okay": "",
|
||||
"Gen_Online": "",
|
||||
|
||||
@@ -66,6 +66,8 @@
|
||||
"CustProps_cant_remove": "",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "",
|
||||
"DEEP_SLEEP_description": "",
|
||||
"DEEP_SLEEP_name": "",
|
||||
"DISCOVER_PLUGINS_description": "",
|
||||
"DISCOVER_PLUGINS_name": "",
|
||||
"DevDetail_Children_Title": "",
|
||||
@@ -344,6 +346,7 @@
|
||||
"Gen_LockedDB": "",
|
||||
"Gen_NetworkMask": "",
|
||||
"Gen_New": "",
|
||||
"Gen_No_Data": "",
|
||||
"Gen_Offline": "",
|
||||
"Gen_Okay": "",
|
||||
"Gen_Online": "",
|
||||
|
||||
@@ -66,6 +66,8 @@
|
||||
"CustProps_cant_remove": "Impossibile rimuovere, è necessaria almeno una proprietà.",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "Questa è un'impostazione di manutenzione. Specifica il numero di giorni delle voci degli eventi che verranno conservati. Tutti gli eventi più vecchi verranno eliminati periodicamente. Si applica anche alla cronologia degli eventi del plugin (Plugin Events History).",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "Elimina eventi più vecchi di",
|
||||
"DEEP_SLEEP_description": "Riduce l'utilizzo della CPU estendendo i tempi di attesa tra i cicli di elaborazione. Quando questa opzione è abilitata, le scansioni potrebbero subire ritardi fino a 1 minuto e l'interfaccia utente potrebbe risultare meno reattiva.",
|
||||
"DEEP_SLEEP_name": "Sonno profondo",
|
||||
"DISCOVER_PLUGINS_description": "Disattiva questa opzione per velocizzare l'inizializzazione e il salvataggio delle impostazioni. Quando è disattivata, i plugin non vengono scoperti e non puoi aggiungere nuovi plugin all'impostazione <code>LOADED_PLUGINS</code>.",
|
||||
"DISCOVER_PLUGINS_name": "Scopri i plugin",
|
||||
"DevDetail_Children_Title": "Relazioni tra figli",
|
||||
@@ -247,8 +249,8 @@
|
||||
"Device_TableHead_Name": "Nome",
|
||||
"Device_TableHead_NetworkSite": "Sito di rete",
|
||||
"Device_TableHead_Owner": "Proprietario",
|
||||
"Device_TableHead_ParentRelType": "Tipo di relazione",
|
||||
"Device_TableHead_Parent_MAC": "Nodo di rete principale",
|
||||
"Device_TableHead_ParentRelType": "Relazione",
|
||||
"Device_TableHead_Parent_MAC": "Nodo principale",
|
||||
"Device_TableHead_Port": "Porta",
|
||||
"Device_TableHead_PresentLastScan": "Presenza",
|
||||
"Device_TableHead_ReqNicsOnline": "Richiedi NIC online",
|
||||
@@ -344,6 +346,7 @@
|
||||
"Gen_LockedDB": "ERRORE: il DB potrebbe essere bloccato, controlla F12 Strumenti di sviluppo -> Console o riprova più tardi.",
|
||||
"Gen_NetworkMask": "Maschera di rete",
|
||||
"Gen_New": "Nuovo",
|
||||
"Gen_No_Data": "Nessun dato",
|
||||
"Gen_Offline": "Offline",
|
||||
"Gen_Okay": "Ok",
|
||||
"Gen_Online": "Online",
|
||||
@@ -538,7 +541,7 @@
|
||||
"Navigation_Workflows": "Workflow",
|
||||
"Network_Assign": "Connetti al nodo di rete <i class=\"fa fa-server\"></i> sopra",
|
||||
"Network_Cant_Assign": "Impossibile assegnare il nodo Internet root come nodo foglia figlio.",
|
||||
"Network_Cant_Assign_No_Node_Selected": "Impossibile assegnare, nessun nodo padre selezionato.",
|
||||
"Network_Cant_Assign_No_Node_Selected": "Impossibile assegnare, nessun nodo principale selezionato.",
|
||||
"Network_Configuration_Error": "Errore di configurazione",
|
||||
"Network_Connected": "Dispositivi connessi",
|
||||
"Network_Devices": "Dispositivi di rete",
|
||||
@@ -805,4 +808,4 @@
|
||||
"settings_system_label": "Sistema",
|
||||
"settings_update_item_warning": "Aggiorna il valore qui sotto. Fai attenzione a seguire il formato precedente. <b>La convalida non viene eseguita.</b>",
|
||||
"test_event_tooltip": "Salva le modifiche prima di provare le nuove impostazioni."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,6 +66,8 @@
|
||||
"CustProps_cant_remove": "削除できません。少なくとも1つのプロパティが必要です。",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "これはメンテナンス設定です。イベントエントリを保持する日数を指定します。それより古いイベントは定期的に削除されます。プラグインイベント履歴にも適用されます。",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "古いイベントの削除",
|
||||
"DEEP_SLEEP_description": "",
|
||||
"DEEP_SLEEP_name": "",
|
||||
"DISCOVER_PLUGINS_description": "このオプションを無効にすると、初期化と設定の保存が高速化されます。無効にした場合、プラグインは検出されず、<code>LOADED_PLUGINS</code> 設定に新しいプラグインを追加することはできません。",
|
||||
"DISCOVER_PLUGINS_name": "プラグインの検出",
|
||||
"DevDetail_Children_Title": "親子関係",
|
||||
@@ -344,6 +346,7 @@
|
||||
"Gen_LockedDB": "エラー - DBがロックされている可能性があります - F12で開発者ツール→コンソールを確認するか、後で試してください。",
|
||||
"Gen_NetworkMask": "ネットワークマスク",
|
||||
"Gen_New": "New",
|
||||
"Gen_No_Data": "",
|
||||
"Gen_Offline": "オフライン",
|
||||
"Gen_Okay": "Ok",
|
||||
"Gen_Online": "オンライン",
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
{ "code": "fa_fa", "display": "Farsi (fa_fa)" },
|
||||
{ "code": "id_id", "display": "Indonesian (id_id)" },
|
||||
{ "code": "fr_fr", "display": "French (fr_fr)" },
|
||||
{ "code": "fi_fi", "display": "Finnish (fi_fi)" },
|
||||
{ "code": "he_il", "display": "Hebrew (he_il)" },
|
||||
{ "code": "it_it", "display": "Italian (it_it)" },
|
||||
{ "code": "ja_jp", "display": "Japanese (ja_jp)" },
|
||||
|
||||
@@ -66,6 +66,8 @@
|
||||
"CustProps_cant_remove": "",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "Dette er en vedlikeholdsinnstilling. Dette spesifiserer antall dager verdt med hendelsesoppføringer som vil beholdes. Alle eldre hendelser vil bli slettet med jevne mellomrom. Gjelder også for plugin-hendelseshistorikk.",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "Slett hendelser eldre enn",
|
||||
"DEEP_SLEEP_description": "",
|
||||
"DEEP_SLEEP_name": "",
|
||||
"DISCOVER_PLUGINS_description": "",
|
||||
"DISCOVER_PLUGINS_name": "",
|
||||
"DevDetail_Children_Title": "",
|
||||
@@ -344,6 +346,7 @@
|
||||
"Gen_LockedDB": "FEIL - DB kan være låst - Sjekk F12 Dev tools -> Konsoll eller prøv senere.",
|
||||
"Gen_NetworkMask": "",
|
||||
"Gen_New": "",
|
||||
"Gen_No_Data": "",
|
||||
"Gen_Offline": "Frakoblet",
|
||||
"Gen_Okay": "Ok",
|
||||
"Gen_Online": "",
|
||||
|
||||
@@ -66,6 +66,8 @@
|
||||
"CustProps_cant_remove": "Nie można usunąć – wymagana jest przynajmniej jedna właściwość.",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "To jest ustawienie konserwacyjne. Określa liczbę dni, przez które będą przechowywane wpisy zdarzeń. Wszystkie starsze zdarzenia będą okresowo usuwane. Dotyczy również Historii Zdarzeń Wtyczek.",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "Usuń zdarzenia starsze niż",
|
||||
"DEEP_SLEEP_description": "",
|
||||
"DEEP_SLEEP_name": "",
|
||||
"DISCOVER_PLUGINS_description": "Wyłącz tę opcję, aby przyspieszyć inicjalizację i zapisywanie ustawień. Po wyłączeniu wtyczki nie są wykrywane i nie można dodawać nowych wtyczek do ustawienia <code>LOADED_PLUGINS</code>.",
|
||||
"DISCOVER_PLUGINS_name": "Wykryj wtyczki",
|
||||
"DevDetail_Children_Title": "",
|
||||
@@ -344,6 +346,7 @@
|
||||
"Gen_LockedDB": "Błąd - Baza danych może być zablokowana - Sprawdź narzędzia deweloperskie F12 -> Konsola lub spróbuj później.",
|
||||
"Gen_NetworkMask": "",
|
||||
"Gen_New": "",
|
||||
"Gen_No_Data": "",
|
||||
"Gen_Offline": "Niedostępne",
|
||||
"Gen_Okay": "Ok",
|
||||
"Gen_Online": "Dostępne",
|
||||
|
||||
@@ -66,6 +66,8 @@
|
||||
"CustProps_cant_remove": "Não é possível remover, é necessária pelo menos uma propriedade.",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "Esta é uma definição de manutenção. Especifica o número de dias de entradas de eventos que serão mantidas. Todos os eventos mais antigos serão eliminados periodicamente. Também se aplica ao Histórico de eventos do plug-in.",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "Excluir eventos mais antigos que",
|
||||
"DEEP_SLEEP_description": "",
|
||||
"DEEP_SLEEP_name": "",
|
||||
"DISCOVER_PLUGINS_description": "Desative esta opção para acelerar a inicialização e a gravação de definições. Quando desativada, os plug-ins não são descobertos e não é possível adicionar novos plug-ins à definição<code>LOADED_PLUGINS</code>.",
|
||||
"DISCOVER_PLUGINS_name": "Descobrir plugins",
|
||||
"DevDetail_Children_Title": "",
|
||||
@@ -344,6 +346,7 @@
|
||||
"Gen_LockedDB": "ERRO - O banco de dados pode estar bloqueado - Verifique F12 Ferramentas de desenvolvimento -> Console ou tente mais tarde.",
|
||||
"Gen_NetworkMask": "",
|
||||
"Gen_New": "",
|
||||
"Gen_No_Data": "",
|
||||
"Gen_Offline": "Offline",
|
||||
"Gen_Okay": "Ok",
|
||||
"Gen_Online": "Online",
|
||||
|
||||
@@ -27,8 +27,8 @@
|
||||
"AppEvents_ObjectType": "Tipo de Objeto",
|
||||
"AppEvents_Plugin": "Plugin",
|
||||
"AppEvents_Type": "Tipo",
|
||||
"BACKEND_API_URL_description": "",
|
||||
"BACKEND_API_URL_name": "",
|
||||
"BACKEND_API_URL_description": "Usado para permitir que o frontend comunique com o backend. Por padrão isto é definido para <code>/server</code> e geralmente não deve ser mudado.",
|
||||
"BACKEND_API_URL_name": "URL do API do backend",
|
||||
"BackDevDetail_Actions_Ask_Run": "Deseja executar esta ação?",
|
||||
"BackDevDetail_Actions_Not_Registered": "Ação não registada: ",
|
||||
"BackDevDetail_Actions_Title_Run": "Executar ação",
|
||||
@@ -66,6 +66,8 @@
|
||||
"CustProps_cant_remove": "Não é possível remover, é necessária pelo menos uma propriedade.",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "Esta é uma definição de manutenção. Especifica o número de dias de entradas de eventos que serão mantidas. Todos os eventos mais antigos serão apagados periodicamente. Também se aplica ao Histórico de eventos do plug-in.",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "Apagar eventos mais antigos que",
|
||||
"DEEP_SLEEP_description": "",
|
||||
"DEEP_SLEEP_name": "",
|
||||
"DISCOVER_PLUGINS_description": "Desative esta opção para acelerar a inicialização e a gravação de definições. Quando desativada, os plug-ins não são descobertos e não é possível adicionar novos plug-ins à definição<code>LOADED_PLUGINS</code>.",
|
||||
"DISCOVER_PLUGINS_name": "Descobrir plugins",
|
||||
"DevDetail_Children_Title": "Relacionamentos de crianças",
|
||||
@@ -98,10 +100,10 @@
|
||||
"DevDetail_MainInfo_Network": "<i class=\"fa fa-server\"> </i> Node (MAC)",
|
||||
"DevDetail_MainInfo_Network_Port": "<i class=\"fa fa-ethernet\"></i>Porta",
|
||||
"DevDetail_MainInfo_Network_Site": "Site",
|
||||
"DevDetail_MainInfo_Network_Title": "Rede",
|
||||
"DevDetail_MainInfo_Network_Title": "Detalhes de Rede",
|
||||
"DevDetail_MainInfo_Owner": "Proprietário",
|
||||
"DevDetail_MainInfo_SSID": "SSID",
|
||||
"DevDetail_MainInfo_Title": "Informações principais",
|
||||
"DevDetail_MainInfo_Title": "Informação de Dispositivo",
|
||||
"DevDetail_MainInfo_Type": "Tipo",
|
||||
"DevDetail_MainInfo_Vendor": "Fornecedor",
|
||||
"DevDetail_MainInfo_mac": "MAC",
|
||||
@@ -139,7 +141,7 @@
|
||||
"DevDetail_SessionTable_Duration": "Duração",
|
||||
"DevDetail_SessionTable_IP": "IP",
|
||||
"DevDetail_SessionTable_Order": "Ordem",
|
||||
"DevDetail_Shortcut_CurrentStatus": "Estado atual",
|
||||
"DevDetail_Shortcut_CurrentStatus": "Estado",
|
||||
"DevDetail_Shortcut_DownAlerts": "Alertas para baixo",
|
||||
"DevDetail_Shortcut_Presence": "Presença",
|
||||
"DevDetail_Shortcut_Sessions": "Sessões",
|
||||
@@ -198,22 +200,22 @@
|
||||
"DevDetail_button_Save": "Gravar",
|
||||
"DeviceEdit_ValidMacIp": "Insira um endereço <b>Mac</b> e <b>IP</b> válidos.",
|
||||
"Device_MultiEdit": "Edição múltipla",
|
||||
"Device_MultiEdit_Backup": "",
|
||||
"Device_MultiEdit_Backup": "Cuidado, introduzir valores errados abaixo pode quebrar a sua configuração. Por favor configure a sua base de dados ou configurações de Dispositivos primeiro (<a href=\"#\" onclick=\"ExportCSV()\">clique para transferir <i class=\"fa-solid fa-download fa-bounce\"></i></a>). Leia como recuperar Dispositivos a partir deste ficheiro na <a href=\"https://docs.netalertx.com/BACKUPS#scenario-2-corrupted-database\" target=\"_blank\">Documentação de cópias de segurança</a>. De maneira a aplicar as suas mudanças clique no ícone <b>Guardar<i class=\"fa-solid fa-save\"></i></b> em cada campo que deseja atualizar.",
|
||||
"Device_MultiEdit_Fields": "Editar campos:",
|
||||
"Device_MultiEdit_MassActions": "Ações em massa:",
|
||||
"Device_MultiEdit_No_Devices": "Nenhum dispositivo selecionado.",
|
||||
"Device_MultiEdit_Tooltip": "Cuidadoso. Clicar aqui aplicará o valor à esquerda a todos os dispositivos selecionados acima.",
|
||||
"Device_NextScan_Imminent": "",
|
||||
"Device_NextScan_In": "",
|
||||
"Device_NoData_Help": "",
|
||||
"Device_NoData_Scanning": "",
|
||||
"Device_NoData_Title": "",
|
||||
"Device_NoMatch_Title": "",
|
||||
"Device_Save_Failed": "",
|
||||
"Device_Save_Unauthorized": "",
|
||||
"Device_Saved_Success": "",
|
||||
"Device_Saved_Unexpected": "",
|
||||
"Device_Scanning": "",
|
||||
"Device_NextScan_Imminent": "Iminente...",
|
||||
"Device_NextScan_In": "Próxima análise em aproximadamente ",
|
||||
"Device_NoData_Help": "Se dispositivos não aparecem após a análise, verifique a sua definição SCAN_SUBNETS e a <a href=\"https://docs.netalertx.com/SUBNETS\" target=\"_blank\">documentação</a>.",
|
||||
"Device_NoData_Scanning": "Espere primeiro pela análise - isto pode levar vários minutos após a primeira configuração inicial.",
|
||||
"Device_NoData_Title": "Nenhum dispositivo encontrado ainda",
|
||||
"Device_NoMatch_Title": "Nenhum dispositivo corresponde ao filtro atual",
|
||||
"Device_Save_Failed": "Falha ao guardar dispositivo",
|
||||
"Device_Save_Unauthorized": "Não autorizado - token de API inválido",
|
||||
"Device_Saved_Success": "Dispositivo guardado com sucesso",
|
||||
"Device_Saved_Unexpected": "Atualização de dispositivo devolveu uma resposta inesperada",
|
||||
"Device_Scanning": "Analisando...",
|
||||
"Device_Searchbox": "Procurar",
|
||||
"Device_Shortcut_AllDevices": "Os meus dispositivos",
|
||||
"Device_Shortcut_AllNodes": "Todos os Nodes",
|
||||
@@ -225,18 +227,18 @@
|
||||
"Device_Shortcut_Favorites": "Favoritos",
|
||||
"Device_Shortcut_NewDevices": "Novo dispostivo",
|
||||
"Device_Shortcut_OnlineChart": "Presença do dispositivo",
|
||||
"Device_Shortcut_Unstable": "",
|
||||
"Device_Shortcut_Unstable": "Instável",
|
||||
"Device_TableHead_AlertDown": "Alerta em baixo",
|
||||
"Device_TableHead_Connected_Devices": "Conexões",
|
||||
"Device_TableHead_CustomProps": "Propriedades / Ações",
|
||||
"Device_TableHead_FQDN": "FQDN",
|
||||
"Device_TableHead_Favorite": "Favorito",
|
||||
"Device_TableHead_FirstSession": "Primeira sessão",
|
||||
"Device_TableHead_Flapping": "",
|
||||
"Device_TableHead_Flapping": "Flapping",
|
||||
"Device_TableHead_GUID": "GUID",
|
||||
"Device_TableHead_Group": "Grupo",
|
||||
"Device_TableHead_IPv4": "",
|
||||
"Device_TableHead_IPv6": "",
|
||||
"Device_TableHead_IPv4": "IPv4",
|
||||
"Device_TableHead_IPv6": "IPv6",
|
||||
"Device_TableHead_Icon": "Ícone",
|
||||
"Device_TableHead_LastIP": "Último IP",
|
||||
"Device_TableHead_LastIPOrder": "Último pedido de IP",
|
||||
@@ -260,7 +262,7 @@
|
||||
"Device_TableHead_SyncHubNodeName": "Nó de sincronização",
|
||||
"Device_TableHead_Type": "Tipo",
|
||||
"Device_TableHead_Vendor": "Fornecedor",
|
||||
"Device_TableHead_Vlan": "",
|
||||
"Device_TableHead_Vlan": "VLAN",
|
||||
"Device_Table_Not_Network_Device": "Não configurado como um dispositivo de rede",
|
||||
"Device_Table_info": "A mostrar _START_ to _END_ of _TOTAL_ entradas",
|
||||
"Device_Table_nav_next": "Próximo",
|
||||
@@ -308,14 +310,14 @@
|
||||
"Events_Tablelenght": "Mostrar entradas do _MENU_",
|
||||
"Events_Tablelenght_all": "Todos",
|
||||
"Events_Title": "Eventos",
|
||||
"FakeMAC_hover": "",
|
||||
"FieldLock_Error": "",
|
||||
"FieldLock_Lock_Tooltip": "",
|
||||
"FieldLock_Locked": "",
|
||||
"FieldLock_SaveBeforeLocking": "",
|
||||
"FieldLock_Source_Label": "",
|
||||
"FieldLock_Unlock_Tooltip": "",
|
||||
"FieldLock_Unlocked": "",
|
||||
"FakeMAC_hover": "Este dispositivo tem um endereço MAC falso/alterado",
|
||||
"FieldLock_Error": "Erro ao atualizar o estado de bloqueio do campo",
|
||||
"FieldLock_Lock_Tooltip": "Bloquear campo (evita sobrescrita de plugins)",
|
||||
"FieldLock_Locked": "Campo bloqueado",
|
||||
"FieldLock_SaveBeforeLocking": "Guarde as suas mudanças antes de bloquear",
|
||||
"FieldLock_Source_Label": "Fonte: ",
|
||||
"FieldLock_Unlock_Tooltip": "Desbloquear campo (permite sobrescritas de plugins)",
|
||||
"FieldLock_Unlocked": "Campo desbloqueado",
|
||||
"GRAPHQL_PORT_description": "O número da porta do servidor GraphQL. Certifique-se de que a porta seja exclusiva em todas as suas aplicações neste host e nas instâncias do NetAlertX.",
|
||||
"GRAPHQL_PORT_name": "Porta GraphQL",
|
||||
"Gen_Action": "Ação",
|
||||
@@ -323,7 +325,7 @@
|
||||
"Gen_AddDevice": "Adicionar dispositivo",
|
||||
"Gen_Add_All": "Adicionar todos",
|
||||
"Gen_All_Devices": "Todos os dispostivos",
|
||||
"Gen_Archived": "",
|
||||
"Gen_Archived": "Arquivado",
|
||||
"Gen_AreYouSure": "Tem certeza?",
|
||||
"Gen_Backup": "Executar backup",
|
||||
"Gen_Cancel": "Cancelar",
|
||||
@@ -334,16 +336,17 @@
|
||||
"Gen_Delete": "Apagar",
|
||||
"Gen_DeleteAll": "Apagar todos",
|
||||
"Gen_Description": "Descrição",
|
||||
"Gen_Down": "",
|
||||
"Gen_Down": "Em Baixo",
|
||||
"Gen_Error": "Erro",
|
||||
"Gen_Filter": "Filtro",
|
||||
"Gen_Flapping": "",
|
||||
"Gen_Flapping": "Flapping",
|
||||
"Gen_Generate": "Gerar",
|
||||
"Gen_InvalidMac": "Endereço MAC Inválido.",
|
||||
"Gen_Invalid_Value": "",
|
||||
"Gen_Invalid_Value": "Um valor inválido foi inserido",
|
||||
"Gen_LockedDB": "ERRO - A base de dados pode estar bloqueada - Verifique F12 Ferramentas de desenvolvimento -> Console ou tente mais tarde.",
|
||||
"Gen_NetworkMask": "Máscara de Rede",
|
||||
"Gen_New": "",
|
||||
"Gen_New": "Novo",
|
||||
"Gen_No_Data": "Sem dados",
|
||||
"Gen_Offline": "Offline",
|
||||
"Gen_Okay": "Ok",
|
||||
"Gen_Online": "Online",
|
||||
@@ -361,7 +364,7 @@
|
||||
"Gen_SelectIcon": "<i class=\"fa-solid fa-chevron-down fa-fade\"></i>",
|
||||
"Gen_SelectToPreview": "Selecionar para pré-visualizar",
|
||||
"Gen_Selected_Devices": "Seleciona dispostivos:",
|
||||
"Gen_Sleeping": "",
|
||||
"Gen_Sleeping": "A Dormir",
|
||||
"Gen_Subnet": "Sub-rede",
|
||||
"Gen_Switch": "Trocar",
|
||||
"Gen_Upd": "Atualizado com sucesso",
|
||||
@@ -375,9 +378,9 @@
|
||||
"Gen_create_new_device_info": "Os dispositivos são normalmente descobertos usando <a target=\"_blank\" href=\"https://docs.netalertx.com/PLUGINS\">plugins</a>. No entanto, em certos casos, pode ser necessário adicionar dispositivos manualmente. Para explorar cenários específicos, verifique a <a target=\"_blank\" href=\"https://docs.netalertx.com/REMOTE_NETWORKS\">documentação de Redes Remotas</a>.",
|
||||
"General_display_name": "Geral",
|
||||
"General_icon": "<i class=\"fa fa-gears\"></i>",
|
||||
"HRS_TO_KEEP_NEWDEV_description": "",
|
||||
"HRS_TO_KEEP_NEWDEV_description": "Isto é uma definição de manutenção <b>ELIMINAR dispositivos</b>. Se ativado (<code>0</code> é desativado), dispositivos marcados como <b>Novo dispositivo</b> serão eliminados se o seu tempo de <b>Primeira Sessão</b> foi mais antigo que as horas especificadas nesta definição. Use esta definição se quer auto-eliminar <b>Novos dispositivos</b> após <code>X</code> horas.",
|
||||
"HRS_TO_KEEP_NEWDEV_name": "Remover novos dispostivos depois",
|
||||
"HRS_TO_KEEP_OFFDEV_description": "",
|
||||
"HRS_TO_KEEP_OFFDEV_description": "Isto é uma definição de manutenção <b>ELIMINAR dispositivos</b>. Se ativado (<code>0</code> é desativado), dispositivos que estão <b>Offline</b> e a sua data de <b>Última conexão</b> foi mais antigo que as horas especificadas nesta definição, será eliminado. Use esta definição se quer auto-eliminar <b>Dispositivos Offline</b> após <code>X</code> horas de estarem offline.",
|
||||
"HRS_TO_KEEP_OFFDEV_name": "Apagar dispositivos offline após",
|
||||
"LOADED_PLUGINS_description": "Quais plugins carregar. Adicionar plugins pode deixar a aplicação lenta. Leia mais sobre quais plugins precisam ser ativados, tipos ou opções de escaneamento na <a target=\"_blank\" href=\"https://docs.netalertx.com/PLUGINS\">documentação de plugins</a>. Plugins descarregados perderão as suas configurações. Somente plugins <code>desativados</code> podem ser descarregados.",
|
||||
"LOADED_PLUGINS_name": "Plugins carregados",
|
||||
@@ -416,7 +419,7 @@
|
||||
"Maintenance_Tool_ExportCSV": "Exportar dispostivos (csv)",
|
||||
"Maintenance_Tool_ExportCSV_noti": "Exportar dispostivos (csv)",
|
||||
"Maintenance_Tool_ExportCSV_noti_text": "Tem a certeza de que pretende gerar um ficheiro CSV?",
|
||||
"Maintenance_Tool_ExportCSV_text": "Gere um ficheiro CSV (valor separado por vírgula) contendo a lista de dispositivos, incluindo os relacionamentos de rede entre os nós de rede e os dispositivos conectados. Também pode acionar isto a aceder esta URL <code>your_NetAlertX_url/php/server/devices.php?action=ExportCSV</code> ou ativando o plugin <a href=\"settings.php#CSVBCKP_header\">CSV Backup</a>.",
|
||||
"Maintenance_Tool_ExportCSV_text": "Gere um ficheiro CSV (valor separado por vírgula) contendo a lista de dispositivos, incluindo os relacionamentos de rede entre os nós de rede e os dispositivos conectados. Também pode acionar isto ativando o plugin <a href=\"settings.php#CSVBCKP_header\">CSV Backup</a>.",
|
||||
"Maintenance_Tool_ImportCSV": "Importação de dispositivos (csv)",
|
||||
"Maintenance_Tool_ImportCSV_noti": "Importação de dispositivos (csv)",
|
||||
"Maintenance_Tool_ImportCSV_noti_text": "Tem certeza de que deseja importar o ficheiro CSV? Isto <b>sobrescreverá</b> completamente os dispositivos na sua base de dados.",
|
||||
@@ -428,10 +431,10 @@
|
||||
"Maintenance_Tool_ImportPastedConfig": "Configurações Importar (colar)",
|
||||
"Maintenance_Tool_ImportPastedConfig_noti_text": "Tem certeza de que deseja importar as configurações coladas? Isto irá <b>sobrescrever</b> completamente o ficheiro <code>app.conf</code>.",
|
||||
"Maintenance_Tool_ImportPastedConfig_text": "Importa o ficheiro <code>app.conf</code> contendo todas as configurações da aplicação. Pode descarregar primeiro o ficheiro <code>app.conf</code> com a <b>Exportação de configurações</b>.",
|
||||
"Maintenance_Tool_UnlockFields": "",
|
||||
"Maintenance_Tool_UnlockFields_noti": "",
|
||||
"Maintenance_Tool_UnlockFields_noti_text": "",
|
||||
"Maintenance_Tool_UnlockFields_text": "",
|
||||
"Maintenance_Tool_UnlockFields": "Desbloquear Campos do Dispositivo",
|
||||
"Maintenance_Tool_UnlockFields_noti": "Desbloquear Campos do Dispositivo",
|
||||
"Maintenance_Tool_UnlockFields_noti_text": "Tem a certeza que quer limpar todos os valores fonte (LOCKED/USER) para todos os campos de dispositivo em todos os dispositivos? Esta ação não pode ser desfeita.",
|
||||
"Maintenance_Tool_UnlockFields_text": "Esta ferramenta removerá todos os valores fonte de todos os campos rastreados para todos os dispositivos, efetivamente desbloqueando todos os campos para plugins e utilizadores. Use isto com caução, uma vez que afetará todo o inventário do seu dispositivo.",
|
||||
"Maintenance_Tool_arpscansw": "Alternar arp-Scan (ligado/desligado)",
|
||||
"Maintenance_Tool_arpscansw_noti": "Ativar ou desativar o arp-Scan",
|
||||
"Maintenance_Tool_arpscansw_noti_text": "Quando a análise é desligada, permanece desligada até ser novamente ativada.",
|
||||
@@ -441,9 +444,9 @@
|
||||
"Maintenance_Tool_backup_noti_text": "Tem a certeza de que pretende executar a cópia de segurança da BD? Certifique-se de que não está a ser executada nenhuma verificação.",
|
||||
"Maintenance_Tool_backup_text": "Os backups da base de dados estão localizadas no diretório da base de dados como um arquivo zip, nomeado com a data de criação. Não há nenhum número máximo de backups.",
|
||||
"Maintenance_Tool_check_visible": "Desmarque para esconder a coluna.",
|
||||
"Maintenance_Tool_clearSourceFields_selected": "",
|
||||
"Maintenance_Tool_clearSourceFields_selected_noti": "",
|
||||
"Maintenance_Tool_clearSourceFields_selected_text": "",
|
||||
"Maintenance_Tool_clearSourceFields_selected": "Limpar campos fonte",
|
||||
"Maintenance_Tool_clearSourceFields_selected_noti": "Limpar fontes",
|
||||
"Maintenance_Tool_clearSourceFields_selected_text": "Isto limpará todos os campos fonte para os dispositivos selecionados. Esta ação não pode ser desfeita.",
|
||||
"Maintenance_Tool_darkmode": "Modos de alternância (escuro/claro)",
|
||||
"Maintenance_Tool_darkmode_noti": "Modos de alternância",
|
||||
"Maintenance_Tool_darkmode_noti_text": "Após a mudança de tema, a página tenta recarregar-se para ativar a alteração. Se necessário, a cache deve ser limpa.",
|
||||
@@ -474,7 +477,7 @@
|
||||
"Maintenance_Tool_del_unknowndev_noti": "Eliminar dispositivos desconhecidos",
|
||||
"Maintenance_Tool_del_unknowndev_noti_text": "Tem certeza que deseja apagar todos (desconhecidos) e (nome não encontrados) dispositivos?",
|
||||
"Maintenance_Tool_del_unknowndev_text": "Antes de usar esta função, faça um backup. Apagar não pode ser desfeito. Todos os dispositivos nomeados (não conhecidos) serão apagados da base de dados.",
|
||||
"Maintenance_Tool_del_unlockFields_selecteddev_text": "",
|
||||
"Maintenance_Tool_del_unlockFields_selecteddev_text": "Isto desbloqueará os campos LOCKED/USER para os dispositivos selecionados. Esta ação não pode ser desfeita.",
|
||||
"Maintenance_Tool_displayed_columns_text": "Altere a visibilidade e a ordem das colunas na página <a href=\"devices.php\"><b> <i class=\"fa fa-portátil\"></i> Dispositivos</b></a>.",
|
||||
"Maintenance_Tool_drag_me": "Arraste-me para reordenar colunas.",
|
||||
"Maintenance_Tool_order_columns_text": "Maintenance_Tool_order_columns_text",
|
||||
@@ -486,8 +489,8 @@
|
||||
"Maintenance_Tool_restore_noti": "Restauração de DB",
|
||||
"Maintenance_Tool_restore_noti_text": "Tem a certeza de que quer executar a Restauração DB? Certifique-se de que nenhuma varredura funciona atualmente.",
|
||||
"Maintenance_Tool_restore_text": "O backup mais recente pode ser restaurado através do botão, mas os backups mais antigos só podem ser restaurados manualmente. Após a restauração, faça uma verificação de integridade na base de dados para segurança, caso o db estivesse atualmente em acesso de gravação quando o backup foi criado.",
|
||||
"Maintenance_Tool_unlockFields_selecteddev": "",
|
||||
"Maintenance_Tool_unlockFields_selecteddev_noti": "",
|
||||
"Maintenance_Tool_unlockFields_selecteddev": "Desbloquear campos de dispositivo",
|
||||
"Maintenance_Tool_unlockFields_selecteddev_noti": "Desbloquear campos",
|
||||
"Maintenance_Tool_upgrade_database_noti": "Atualizar a base de dados",
|
||||
"Maintenance_Tool_upgrade_database_noti_text": "Tem certeza de que deseja atualizar a base de dados?<br>(talvez prefira arquivá-la)",
|
||||
"Maintenance_Tool_upgrade_database_text": "Este botão atualizará a base de dados para ativar o gráfico Atividade de rede nas últimas 12 horas. Faça uma cópia de segurança da sua base de dados em caso de problemas.",
|
||||
@@ -563,69 +566,69 @@
|
||||
"Network_ManageEdit_Name_text": "Nome sem caracteres especiais",
|
||||
"Network_ManageEdit_Port": " Nova contagem de portas",
|
||||
"Network_ManageEdit_Port_text": "Deixe em branco para Wi-Fi e Powerline.",
|
||||
"Network_ManageEdit_Submit": "",
|
||||
"Network_ManageEdit_Type": "",
|
||||
"Network_ManageEdit_Type_text": "",
|
||||
"Network_ManageLeaf": "",
|
||||
"Network_ManageUnassign": "",
|
||||
"Network_NoAssignedDevices": "",
|
||||
"Network_NoDevices": "",
|
||||
"Network_Node": "",
|
||||
"Network_Node_Name": "",
|
||||
"Network_Parent": "",
|
||||
"Network_Root": "",
|
||||
"Network_Root_Not_Configured": "",
|
||||
"Network_Root_Unconfigurable": "",
|
||||
"Network_ShowArchived": "",
|
||||
"Network_ShowOffline": "",
|
||||
"Network_Table_Hostname": "",
|
||||
"Network_Table_IP": "",
|
||||
"Network_Table_State": "",
|
||||
"Network_Title": "",
|
||||
"Network_UnassignedDevices": "",
|
||||
"Notifications_All": "",
|
||||
"Notifications_Mark_All_Read": "",
|
||||
"PIALERT_WEB_PASSWORD_description": "",
|
||||
"PIALERT_WEB_PASSWORD_name": "",
|
||||
"PIALERT_WEB_PROTECTION_description": "",
|
||||
"PIALERT_WEB_PROTECTION_name": "",
|
||||
"PLUGINS_KEEP_HIST_description": "",
|
||||
"PLUGINS_KEEP_HIST_name": "",
|
||||
"PRAGMA_JOURNAL_SIZE_LIMIT_description": "",
|
||||
"PRAGMA_JOURNAL_SIZE_LIMIT_name": "",
|
||||
"Plugins_DeleteAll": "",
|
||||
"Plugins_Filters_Mac": "",
|
||||
"Plugins_History": "",
|
||||
"Plugins_Obj_DeleteListed": "",
|
||||
"Plugins_Objects": "",
|
||||
"Plugins_Out_of": "",
|
||||
"Plugins_Unprocessed_Events": "",
|
||||
"Plugins_no_control": "",
|
||||
"Presence_CalHead_day": "",
|
||||
"Presence_CalHead_lang": "",
|
||||
"Presence_CalHead_month": "",
|
||||
"Presence_CalHead_quarter": "",
|
||||
"Presence_CalHead_week": "",
|
||||
"Presence_CalHead_year": "",
|
||||
"Presence_CallHead_Devices": "",
|
||||
"Presence_Key_OnlineNow": "",
|
||||
"Presence_Key_OnlineNow_desc": "",
|
||||
"Presence_Key_OnlinePast": "",
|
||||
"Presence_Key_OnlinePastMiss": "",
|
||||
"Presence_Key_OnlinePastMiss_desc": "",
|
||||
"Presence_Key_OnlinePast_desc": "",
|
||||
"Presence_Loading": "",
|
||||
"Presence_Shortcut_AllDevices": "",
|
||||
"Presence_Shortcut_Archived": "",
|
||||
"Presence_Shortcut_Connected": "",
|
||||
"Presence_Shortcut_Devices": "",
|
||||
"Presence_Shortcut_DownAlerts": "",
|
||||
"Presence_Shortcut_Favorites": "",
|
||||
"Presence_Shortcut_NewDevices": "",
|
||||
"Presence_Title": "",
|
||||
"REFRESH_FQDN_description": "",
|
||||
"REFRESH_FQDN_name": "",
|
||||
"REPORT_DASHBOARD_URL_description": "",
|
||||
"Network_ManageEdit_Submit": "Guardar Alterações",
|
||||
"Network_ManageEdit_Type": "Novo tipo de dispositivo",
|
||||
"Network_ManageEdit_Type_text": "-- Selecionar tipo --",
|
||||
"Network_ManageLeaf": "Gerir atribuição",
|
||||
"Network_ManageUnassign": "Cancelar Atribuição",
|
||||
"Network_NoAssignedDevices": "Este nó de rede não tem quaisquer dispositivos atribuídos (nós folha). Atribua um abaixo ou vá ao separador <b><i class=\"fa fa-info-circle\"> Detalhes</b> em qualquer dispositivo em <a href=\"devices.php\"><b><i class=\"fa fa-laptop\"></i> Dispositivos</b></a>, e atribua-o a um <i <b><i class=\"fa fa-server\"></i> Nó de rede (MAC)</b> e <b><i class=\"fa fa-ethernet\"></i> Porta</b> lá.",
|
||||
"Network_NoDevices": "Sem dispositivos para configurar",
|
||||
"Network_Node": "Nó de rede",
|
||||
"Network_Node_Name": "Nome do nó",
|
||||
"Network_Parent": "Dispositivo da rede parente",
|
||||
"Network_Root": "Nó raiz",
|
||||
"Network_Root_Not_Configured": "Selecione um tipo de dispositivo de rede, por exemplo um <b>Gateway</b>, no campo <b>Tipo</b> do <a href=\"deviceDetails.php?mac=Internet\">o dispositivo raiz da Internet</a> para começar a configurar este ecrã. <br/><br/> Mais documentação pode ser encontrada no guia <a href=\"https://docs.netalertx.com/NETWORK_TREE\" target=\"_blank\">Como configurar a sua página de Rede</a>",
|
||||
"Network_Root_Unconfigurable": "Raiz não configurável",
|
||||
"Network_ShowArchived": "Mostrar arquivados",
|
||||
"Network_ShowOffline": "Mostrar offline",
|
||||
"Network_Table_Hostname": "Nome do anfitrião",
|
||||
"Network_Table_IP": "IP",
|
||||
"Network_Table_State": "Estado",
|
||||
"Network_Title": "Visão geral da rede",
|
||||
"Network_UnassignedDevices": "Dispositivos não atribuídos",
|
||||
"Notifications_All": "Todas as notificações",
|
||||
"Notifications_Mark_All_Read": "Marcar todas como lidas",
|
||||
"PIALERT_WEB_PASSWORD_description": "A palavra passe padrão é <code>123456</code>. Para mudar esta palavra passe execute <code>/app/back/pialert-cli</code> no contentor ou use o <a onclick=\"toggleAllSettings()\" href=\"#SETPWD_RUN\"><code>SETPWD_RUN</code> Definir plugin de palavra passe</a>.",
|
||||
"PIALERT_WEB_PASSWORD_name": "Palavra passe de início de sessão",
|
||||
"PIALERT_WEB_PROTECTION_description": "Quando ativo um diálogo de início de sessão é mostrado. Leia abaixo com cuidado se ficar trancado fora da sua instância.",
|
||||
"PIALERT_WEB_PROTECTION_name": "Ativar início de sessão",
|
||||
"PLUGINS_KEEP_HIST_description": "Quantas entradas de resultados de análise de Histórico de Plugins devem ser mantidos (por Plugin, e não específico a dispositivos).",
|
||||
"PLUGINS_KEEP_HIST_name": "Histórico de Plugins",
|
||||
"PRAGMA_JOURNAL_SIZE_LIMIT_description": "Tamanho máximo do SQLite WAL (Write-Ahead Log) em MB antes de ativar pontos de controlo automáticos. Valores mais pequenos (10-20MB) reduzem utilização de disco/armazenamento durante análises. Valores mais altos (50-100MB) reduzem picos de CPU durante operações mas podem usar mais RAM e espaço no disco. O padrão <code>50 MB</code> equilibra ambos. Útil para sistemas com recursos limitados como dispositivos NAS com cartões SD. Reinicie o servidor para que as mudanças entrem em vigor após guardar as definições.",
|
||||
"PRAGMA_JOURNAL_SIZE_LIMIT_name": "Tamanho limite do WAL (MB)",
|
||||
"Plugins_DeleteAll": "Eliminar todos (filtros são ignorados)",
|
||||
"Plugins_Filters_Mac": "Filtro Mac",
|
||||
"Plugins_History": "Histórico de Eventos",
|
||||
"Plugins_Obj_DeleteListed": "Eliminar Objetos Listados",
|
||||
"Plugins_Objects": "Objetos de Plugin",
|
||||
"Plugins_Out_of": "de",
|
||||
"Plugins_Unprocessed_Events": "Eventos Não-Processados",
|
||||
"Plugins_no_control": "Nenhum controlo de formulário foi encontrado para renderizar este valor.",
|
||||
"Presence_CalHead_day": "dia",
|
||||
"Presence_CalHead_lang": "en-us",
|
||||
"Presence_CalHead_month": "mês",
|
||||
"Presence_CalHead_quarter": "trimestre",
|
||||
"Presence_CalHead_week": "semana",
|
||||
"Presence_CalHead_year": "ano",
|
||||
"Presence_CallHead_Devices": "Dispositivos",
|
||||
"Presence_Key_OnlineNow": "Agora online",
|
||||
"Presence_Key_OnlineNow_desc": "Dispositivo detetado como online na última análise.",
|
||||
"Presence_Key_OnlinePast": "Últimos online",
|
||||
"Presence_Key_OnlinePastMiss": "Últimos online (desajustado)",
|
||||
"Presence_Key_OnlinePastMiss_desc": "Dispositivo online no passado, mas atualmente offline, mas o início de sessão pode estar em falta ou tem dados em conflito.",
|
||||
"Presence_Key_OnlinePast_desc": "Dispositivo online no passado, mas atualmente offline.",
|
||||
"Presence_Loading": "A Carregar…",
|
||||
"Presence_Shortcut_AllDevices": "Os meus dispositivos",
|
||||
"Presence_Shortcut_Archived": "Arquivado",
|
||||
"Presence_Shortcut_Connected": "Conectado",
|
||||
"Presence_Shortcut_Devices": "Dispositivos",
|
||||
"Presence_Shortcut_DownAlerts": "Alertas de Interrupção",
|
||||
"Presence_Shortcut_Favorites": "Favoritos",
|
||||
"Presence_Shortcut_NewDevices": "Novos dispositivos",
|
||||
"Presence_Title": "Presença por dispositivo",
|
||||
"REFRESH_FQDN_description": "Reanalisa todos os dispositivos e atualiza o seu Nome de Domínio Qualificado Completo (FQDN). Se estiver desativado, apenas dispositivos sem um nome conhecido serão analisados para melhorar o desempenho. Neste caso, FQDN é atualizado apenas durante a descoberta de dispositivos inicial.",
|
||||
"REFRESH_FQDN_name": "Atualizar FQDN",
|
||||
"REPORT_DASHBOARD_URL_description": "Este URL é usado como base para gerar links nos relatórios HTML (p.ex.: emails). Introduza o URL começado com <code>http://</code> incluindo o número da porta (sem barra final <code>/</code>).",
|
||||
"REPORT_DASHBOARD_URL_name": "",
|
||||
"REPORT_ERROR": "",
|
||||
"REPORT_MAIL_description": "",
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
"BackDevices_DBTools_DelEventsError": "Ошибка удаления событий",
|
||||
"BackDevices_DBTools_ImportCSV": "Устройства из файла CSV были успешно импортированы.",
|
||||
"BackDevices_DBTools_ImportCSVError": "Не удалось импортировать файл CSV. Убедитесь, что формат правильный.",
|
||||
"BackDevices_DBTools_ImportCSVMissing": "CSV-файл не найден в<b>/config/devices.csv.</b>",
|
||||
"BackDevices_DBTools_ImportCSVMissing": "CSV-файл не найден в <b>/config/devices.csv.</b>",
|
||||
"BackDevices_DBTools_Purge": "Самые старые резервные копии были удалены",
|
||||
"BackDevices_DBTools_UpdDev": "Устройство успешно обновлено. При выполнении сканирования может потребоваться некоторое время для перезагрузки основного списка устройств.",
|
||||
"BackDevices_DBTools_UpdDevError": "Ошибка обновления устройства",
|
||||
@@ -66,6 +66,8 @@
|
||||
"CustProps_cant_remove": "Невозможно удалить, необходимо хотя бы одно свойство.",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "Это настройка обслуживания. Здесь указывается количество дней, в течение которых будут храниться записи о событиях. Все старые события будут периодически удаляться. Также применимо к истории событий плагина.",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "Удалить события старше",
|
||||
"DEEP_SLEEP_description": "Снижает нагрузку на процессор за счет увеличения времени ожидания между циклами обработки. При включении, сканирование может быть отложено до 1 минуты, а пользовательский интерфейс может стать менее отзывчивым.",
|
||||
"DEEP_SLEEP_name": "Глубокий сон",
|
||||
"DISCOVER_PLUGINS_description": "Отключите эту опцию, чтобы ускорить инициализацию и сохранение настроек. При отключении этой опции плагины не обнаруживаются, и вы не можете добавлять новые плагины в параметр <code>LOADED_PLUGINS</code>.",
|
||||
"DISCOVER_PLUGINS_name": "Обзор плагинов",
|
||||
"DevDetail_Children_Title": "Дочерние отношения",
|
||||
@@ -185,7 +187,7 @@
|
||||
"DevDetail_Vendor_hover": "Поставщик должен определяться автоматически. Вы можете перезаписать или добавить свое собственное значение.",
|
||||
"DevDetail_WOL_Title": "<i class=\"fa fa-power-off\"></i> Wake-on-LAN",
|
||||
"DevDetail_button_AddIcon": "Добавить новый значок",
|
||||
"DevDetail_button_AddIcon_Help": "Вставьте HTML-тег SVG или Font Awesome. Подробная информация по значкам по ссылке <a href=\"https://docs.netalertx.com/ICONS\" target=\"_blank\"></a>.",
|
||||
"DevDetail_button_AddIcon_Help": "Вставьте HTML-тег SVG или значок Font Awesome. Подробнее читайте в <a href=\"https://docs.netalertx.com/ICONS\" target=\"_blank\">документации по иконкам</a>.",
|
||||
"DevDetail_button_AddIcon_Tooltip": "Добавьте к этому устройству новый значок, которого еще нет в раскрывающемся списке.",
|
||||
"DevDetail_button_Delete": "Удалить устройство",
|
||||
"DevDetail_button_DeleteEvents": "Удалить события",
|
||||
@@ -247,8 +249,8 @@
|
||||
"Device_TableHead_Name": "Имя",
|
||||
"Device_TableHead_NetworkSite": "Сайт устройства",
|
||||
"Device_TableHead_Owner": "Владелец",
|
||||
"Device_TableHead_ParentRelType": "Тип отношений",
|
||||
"Device_TableHead_Parent_MAC": "Родительский узел сети",
|
||||
"Device_TableHead_ParentRelType": "Отношения",
|
||||
"Device_TableHead_Parent_MAC": "Родительский узел",
|
||||
"Device_TableHead_Port": "Порт",
|
||||
"Device_TableHead_PresentLastScan": "Присутствие",
|
||||
"Device_TableHead_ReqNicsOnline": "Требуется NIC онлайн",
|
||||
@@ -269,7 +271,7 @@
|
||||
"Device_Tablelenght_all": "Все",
|
||||
"Device_Title": "Устройства",
|
||||
"Devices_Filters": "Фильтры",
|
||||
"ENABLE_PLUGINS_description": "Включает функциональность <a target=\"_blank\" href=\"https://docs.netalertx.com/PLUGINS\">плагинов.</a> Загрузка плагинов требует больше аппаратных ресурсов, поэтому вы можете отключить их в маломощной системе.",
|
||||
"ENABLE_PLUGINS_description": "Включает функциональность <a target=\"_blank\" href=\"https://docs.netalertx.com/PLUGINS\">плагинов</a>. Загрузка плагинов требует больше аппаратных ресурсов, поэтому вы можете отключить их в маломощной системе.",
|
||||
"ENABLE_PLUGINS_name": "Разрешить плагины",
|
||||
"ENCRYPTION_KEY_description": "Ключ шифрования данных.",
|
||||
"ENCRYPTION_KEY_name": "Ключ шифрования",
|
||||
@@ -344,6 +346,7 @@
|
||||
"Gen_LockedDB": "ОШИБКА - Возможно, база данных заблокирована. Проверьте инструменты разработчика F12 -> Консоль или повторите попытку позже.",
|
||||
"Gen_NetworkMask": "Маска сети",
|
||||
"Gen_New": "Новый",
|
||||
"Gen_No_Data": "Нет данных",
|
||||
"Gen_Offline": "Оффлайн",
|
||||
"Gen_Okay": "OK",
|
||||
"Gen_Online": "Онлайн",
|
||||
@@ -403,7 +406,7 @@
|
||||
"Maint_Restart_Server_noti_text": "Вы уверены, что хотите перезапустить внутренний сервер? Это может привести к несогласованности работы приложения. Сначала создайте резервную копию настроек. <br/> <br/> Примечание: Это может занять несколько минут.",
|
||||
"Maintenance_InitCheck": "Инициализация проверки",
|
||||
"Maintenance_InitCheck_Checking": "Проверяется…",
|
||||
"Maintenance_InitCheck_QuickSetupGuide": "Убедитесь, что вы следовали быстрому руководству по настройке <a href=\"https://docs.netalertx.com/INITIAL_SETUP/\" target=\"_blank\"></a>.",
|
||||
"Maintenance_InitCheck_QuickSetupGuide": "Убедитесь, что вы следовали <a href=\"https://docs.netalertx.com/INITIAL_SETUP/\" target=\"_blank\">краткому руководству по настройке</a>.",
|
||||
"Maintenance_InitCheck_Success": "Приложение инициализировано успешно!",
|
||||
"Maintenance_ReCheck": "Повторить проверку",
|
||||
"Maintenance_Running_Version": "Установленная версия",
|
||||
@@ -412,7 +415,7 @@
|
||||
"Maintenance_Tool_DownloadConfig": "Экспорт настроек",
|
||||
"Maintenance_Tool_DownloadConfig_text": "Загрузите полную резервную копию конфигурации настроек, хранящуюся в файле <code>app.conf</code>.",
|
||||
"Maintenance_Tool_DownloadWorkflows": "Экспорт Workflow",
|
||||
"Maintenance_Tool_DownloadWorkflows_text": "Загрузите полную резервную копию ваших Workflow, хранящихся в файле <code> hairpflows.json </code>.",
|
||||
"Maintenance_Tool_DownloadWorkflows_text": "Загрузите полную резервную копию ваших Workflow, хранящихся в файле <code>workflows.json</code>.",
|
||||
"Maintenance_Tool_ExportCSV": "Экспорт устройств (csv)",
|
||||
"Maintenance_Tool_ExportCSV_noti": "Экспорт устройств (csv)",
|
||||
"Maintenance_Tool_ExportCSV_noti_text": "Вы уверены, что хотите создать файл CSV?",
|
||||
@@ -422,7 +425,7 @@
|
||||
"Maintenance_Tool_ImportCSV_noti_text": "Вы уверены, что хотите импортировать файл CSV? Это полностью <b>перезапишет</b> устройства в вашей базе данных.",
|
||||
"Maintenance_Tool_ImportCSV_text": "Прежде чем использовать эту функцию, сделайте резервную копию. Импортируйте файл CSV (значения, разделенные запятыми), содержащий список устройств, включая сетевые отношения между сетевыми узлами и подключенными устройствами. Для этого поместите файл CSV с именем <b>devices.csv</b> в папку <b>/config</b>.",
|
||||
"Maintenance_Tool_ImportConfig_noti": "Импорт настроек (app.conf)",
|
||||
"Maintenance_Tool_ImportPastedCSV": "Импорт устройств CSV (вставка)",
|
||||
"Maintenance_Tool_ImportPastedCSV": "Импорт устройств (csv) (вставка)",
|
||||
"Maintenance_Tool_ImportPastedCSV_noti_text": "Вы уверены, что хотите импортировать вставленный CSV? Это полностью <b>перезапишет</b> устройства в вашей базе данных.",
|
||||
"Maintenance_Tool_ImportPastedCSV_text": "Перед использованием этой функции, пожалуйста, создайте резервную копию. Импортируйте файл формата CSV (значения, разделенные запятыми), содержащий список устройств, включая сетевые связи между узлами сети и подключенными устройствами.",
|
||||
"Maintenance_Tool_ImportPastedConfig": "Импорт настроек (вставка)",
|
||||
@@ -585,7 +588,7 @@
|
||||
"Network_UnassignedDevices": "Нераспределенные устройства",
|
||||
"Notifications_All": "Все уведомления",
|
||||
"Notifications_Mark_All_Read": "Отметить все как прочитанные",
|
||||
"PIALERT_WEB_PASSWORD_description": "Пароль по умолчанию: <code>123456</code>. Чтобы изменить пароль, запустите <code>/app/back/pialert-cli</code> в контейнере или используйте <a onclick=\"toggleAllSettings()\" href=\"#SETPWD_RUN\"><code>SETPWD_RUN. </code> Плагин установки пароля</a>.",
|
||||
"PIALERT_WEB_PASSWORD_description": "Пароль по умолчанию: <code>123456</code>. Чтобы изменить пароль, запустите <code>/app/back/pialert-cli</code> в контейнере или используйте <a onclick=\"toggleAllSettings()\" href=\"#SETPWD_RUN\"><code>SETPWD_RUN</code> Плагин установки пароля</a>.",
|
||||
"PIALERT_WEB_PASSWORD_name": "Пароль входа",
|
||||
"PIALERT_WEB_PROTECTION_description": "При включении отображается диалоговое окно входа в систему. Внимательно прочитайте ниже, если ваш экземпляр заблокирован.",
|
||||
"PIALERT_WEB_PROTECTION_name": "Включить вход",
|
||||
@@ -718,12 +721,12 @@
|
||||
"Systeminfo_System_Uptime": "Время работы:",
|
||||
"Systeminfo_This_Client": "Этот клиент",
|
||||
"Systeminfo_USB_Devices": "USB-устройства",
|
||||
"TICKER_MIGRATE_TO_NETALERTX": "⚠ Обнаружены устаревшие местоположения. Следуйте этому руководству <a href=\"https://docs.netalertx.com/MIGRATION\" target=\"_blank\"></a>, чтобы перейти на новые <code>/data/config</code> и <code>/data/db</code> папки и контейнер <code>netalertx</code>.",
|
||||
"TICKER_MIGRATE_TO_NETALERTX": "⚠ Обнаружены устаревшие местоположения. Следуйте <a href=\"https://docs.netalertx.com/MIGRATION\" target=\"_blank\">этому руководству</a>, чтобы перейти на новые папки <code>/data/config</code> и <code>/data/db</code> и контейнер <code>netalertx</code>.",
|
||||
"TIMEZONE_description": "Часовой пояс для корректного отображения статистики. Найдите свой часовой пояс <a target=\"_blank\" href=\"https://en.wikipedia.org/wiki/List_of_tz_database_time_zones\" rel=\"nofollow\">здесь</a>.",
|
||||
"TIMEZONE_name": "Часовой пояс",
|
||||
"UI_DEV_SECTIONS_description": "Выберите, какие элементы интерфейса нужно скрыть на страницах «Устройства».",
|
||||
"UI_DEV_SECTIONS_name": "Скрыть разделы устройств",
|
||||
"UI_ICONS_description": "Список предопределенных значков. Действуйте осторожно: предпочтительный способ добавления значков описан в разделе <a href=\"https://docs.netalertx.com/ICONS\" target=\"_blank\"> документации по значкам</a>. Вы можете добавить HTML-тег SVG в кодировке Base64 или HTML-тег Font-awesome.",
|
||||
"UI_ICONS_description": "Список предопределенных значков. Действуйте осторожно: предпочтительный способ добавления значков описан в разделе <a href=\"https://docs.netalertx.com/ICONS\" target=\"_blank\">документации по значкам</a>. Вы можете добавить HTML-тег SVG в кодировке Base64 или HTML-тег Font-awesome.",
|
||||
"UI_ICONS_name": "Предопределенные значки",
|
||||
"UI_LANG_description": "Выберите предпочтительный язык пользовательского интерфейса. Помогите перевести или предложите языки на онлайн-портале <a href=\"https://hosted.weblate.org/projects/pialert/core/\" target=\"_blank\">Weblate</a>.",
|
||||
"UI_LANG_name": "Язык интерфейса",
|
||||
@@ -805,4 +808,4 @@
|
||||
"settings_system_label": "Система",
|
||||
"settings_update_item_warning": "Обновить значение ниже. Будьте осторожны, следуя предыдущему формату. <b>Проверка не выполняется.</b>",
|
||||
"test_event_tooltip": "Сначала сохраните изменения, прежде чем проверять настройки."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,6 +66,8 @@
|
||||
"CustProps_cant_remove": "",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "",
|
||||
"DEEP_SLEEP_description": "",
|
||||
"DEEP_SLEEP_name": "",
|
||||
"DISCOVER_PLUGINS_description": "",
|
||||
"DISCOVER_PLUGINS_name": "",
|
||||
"DevDetail_Children_Title": "",
|
||||
@@ -344,6 +346,7 @@
|
||||
"Gen_LockedDB": "",
|
||||
"Gen_NetworkMask": "",
|
||||
"Gen_New": "",
|
||||
"Gen_No_Data": "",
|
||||
"Gen_Offline": "",
|
||||
"Gen_Okay": "",
|
||||
"Gen_Online": "",
|
||||
|
||||
@@ -66,6 +66,8 @@
|
||||
"CustProps_cant_remove": "Kaldırılamaz, en az bir özellik gereklidir.",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "Bu bir bakım ayarıdır. Bu, saklanacak olay girişlerinin gün cinsinden sayısını belirtir. Daha eski tüm olaylar periyodik olarak silinecektir. Ayrıca Eklenti Olay Geçmişi üzerinde de geçerlidir.",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "Şu tarihten eski olayları sil",
|
||||
"DEEP_SLEEP_description": "",
|
||||
"DEEP_SLEEP_name": "",
|
||||
"DISCOVER_PLUGINS_description": "Bu seçeneği devre dışı bırakmak, başlatma süresini ve ayarların kaydedilmesini hızlandırır. Devre dışı bırakıldığında, eklentiler keşfedilmez ve <code>LOADED_PLUGINS</code> ayarına yeni eklentiler eklenemez.",
|
||||
"DISCOVER_PLUGINS_name": "Eklentileri keşfet",
|
||||
"DevDetail_Children_Title": "",
|
||||
@@ -344,6 +346,7 @@
|
||||
"Gen_LockedDB": "HATA - Veritabanı kilitlenmiş olabilir - F12 Geliştirici araçlarını -> Konsol kısmını kontrol edin veya daha sonra tekrar deneyin.",
|
||||
"Gen_NetworkMask": "",
|
||||
"Gen_New": "",
|
||||
"Gen_No_Data": "",
|
||||
"Gen_Offline": "Çevrimdışı",
|
||||
"Gen_Okay": "Tamam",
|
||||
"Gen_Online": "Çevrimiçi",
|
||||
|
||||
@@ -66,6 +66,8 @@
|
||||
"CustProps_cant_remove": "Неможливо видалити, потрібна принаймні одна властивість.",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "Це налаштування обслуговування. Це визначає кількість днів записів про події, які зберігатимуться. Усі старіші події періодично видалятимуться. Також застосовується до історії подій плагінів.",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "Видалити події, старші за",
|
||||
"DEEP_SLEEP_description": "",
|
||||
"DEEP_SLEEP_name": "",
|
||||
"DISCOVER_PLUGINS_description": "Вимкніть цю опцію, щоб прискорити ініціалізацію та збереження налаштувань. Якщо вимкнено, плагіни не виявляються, і ви не можете додавати нові плагіни до параметра <code>LOADED_PLUGINS</code>.",
|
||||
"DISCOVER_PLUGINS_name": "Відкрийте для себе плагіни",
|
||||
"DevDetail_Children_Title": "Стосунки з дітьми",
|
||||
@@ -344,6 +346,7 @@
|
||||
"Gen_LockedDB": "ПОМИЛКА – БД може бути заблоковано – перевірте F12 Інструменти розробника -> Консоль або спробуйте пізніше.",
|
||||
"Gen_NetworkMask": "Маска мережі",
|
||||
"Gen_New": "",
|
||||
"Gen_No_Data": "",
|
||||
"Gen_Offline": "Офлайн",
|
||||
"Gen_Okay": "Гаразд",
|
||||
"Gen_Online": "Онлайн",
|
||||
|
||||
@@ -66,6 +66,8 @@
|
||||
"CustProps_cant_remove": "",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "",
|
||||
"DEEP_SLEEP_description": "",
|
||||
"DEEP_SLEEP_name": "",
|
||||
"DISCOVER_PLUGINS_description": "",
|
||||
"DISCOVER_PLUGINS_name": "",
|
||||
"DevDetail_Children_Title": "",
|
||||
@@ -344,6 +346,7 @@
|
||||
"Gen_LockedDB": "",
|
||||
"Gen_NetworkMask": "",
|
||||
"Gen_New": "",
|
||||
"Gen_No_Data": "",
|
||||
"Gen_Offline": "",
|
||||
"Gen_Okay": "",
|
||||
"Gen_Online": "",
|
||||
|
||||
@@ -66,6 +66,8 @@
|
||||
"CustProps_cant_remove": "无法移除,至少需要保留一个属性。",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "这是维护设置。它指定将保留的事件条目的天数。所有较旧的事件将被定期删除。也适用于插件事件历史记录。",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "删除早于",
|
||||
"DEEP_SLEEP_description": "",
|
||||
"DEEP_SLEEP_name": "",
|
||||
"DISCOVER_PLUGINS_description": "禁用此选项可加快初始化和设置保存的速度。当禁用时,插件不会被发现,并且您无法将新插件添加到 <code>LOADED_PLUGINS</code>设置中。",
|
||||
"DISCOVER_PLUGINS_name": "发现插件",
|
||||
"DevDetail_Children_Title": "子代关系",
|
||||
@@ -344,6 +346,7 @@
|
||||
"Gen_LockedDB": "错误 - DB 可能被锁定 - 检查 F12 开发工具 -> 控制台或稍后重试。",
|
||||
"Gen_NetworkMask": "网络掩码",
|
||||
"Gen_New": "",
|
||||
"Gen_No_Data": "",
|
||||
"Gen_Offline": "离线",
|
||||
"Gen_Okay": "Ok",
|
||||
"Gen_Online": "在线",
|
||||
|
||||
@@ -142,16 +142,15 @@ def cleanup_database(
|
||||
# AppEvents
|
||||
histCount = get_setting_value("WORKFLOWS_AppEvents_hist")
|
||||
mylog("verbose", [f"[{pluginName}] Trim AppEvents to less than {histCount}"])
|
||||
delete_query = f"""DELETE FROM AppEvents
|
||||
WHERE "Index" NOT IN (
|
||||
SELECT "Index"
|
||||
FROM (
|
||||
SELECT "Index",
|
||||
ROW_NUMBER() OVER(PARTITION BY "index" ORDER BY dateTimeCreated DESC) AS row_num
|
||||
FROM AppEvents
|
||||
) AS ranked_objects
|
||||
WHERE row_num <= {histCount}
|
||||
);"""
|
||||
delete_query = f"""
|
||||
DELETE FROM AppEvents
|
||||
WHERE "Index" < (
|
||||
SELECT "Index"
|
||||
FROM AppEvents
|
||||
ORDER BY dateTimeCreated DESC
|
||||
LIMIT 1 OFFSET {histCount}
|
||||
);
|
||||
"""
|
||||
cursor.execute(delete_query)
|
||||
mylog("verbose", [f"[{pluginName}] AppEvents deleted rows: {cursor.rowcount}"])
|
||||
|
||||
|
||||
211
front/plugins/fritzbox/README.md
Executable file
211
front/plugins/fritzbox/README.md
Executable file
@@ -0,0 +1,211 @@
|
||||
## Overview
|
||||
|
||||
The Fritz!Box plugin queries connected devices from a Fritz!Box router using the **TR-064** protocol (Technical Report 064), a standardized interface for managing DSL routers and home network devices. This plugin discovers all network-connected devices and reports their MAC addresses, IP addresses, hostnames, and connection types to NetAlertX.
|
||||
|
||||
TR-064 is a UPnP-based protocol that provides programmatic access to Fritz!Box configuration and status information. Unlike web scraping, it offers a stable, documented API that works across Fritz!Box models.
|
||||
|
||||
### Features
|
||||
|
||||
- **Device Discovery**: Automatically detects all connected devices (WiFi 2.4GHz, WiFi 5GHz, Ethernet)
|
||||
- **Real-time Status**: Reports active connection status for each device
|
||||
- **Guest WiFi Monitoring**: Optional synthetic Access Point device to track guest network status
|
||||
- **Flexible Filtering**: Choose to report only active devices or include disconnected devices in Fritz!Box memory
|
||||
- **Secure Connection**: Supports both HTTP and HTTPS with configurable SSL verification
|
||||
|
||||
> [!TIP]
|
||||
> TR-064 is typically enabled by default on Fritz!Box routers. If you encounter connection issues, check that it hasn't been disabled in your Fritz!Box settings under **Home Network > Network > Network Settings > Allow access for applications**.
|
||||
|
||||
### Quick Setup Guide
|
||||
|
||||
To set up the plugin correctly:
|
||||
|
||||
1. **Enable TR-064 on Fritz!Box** (usually already enabled):
|
||||
- Log in to your Fritz!Box web interface (typically `fritz.box` or `192.168.178.1`)
|
||||
- Navigate to: **Home Network > Network > Network Settings**
|
||||
- Ensure **"Allow access for applications"** is checked
|
||||
- Note: Some models show this as **"Allow remote access"** - enable both HTTP and HTTPS
|
||||
|
||||
2. **Configure Plugin in NetAlertX**:
|
||||
- Head to **Settings** > **Fritz!Box Plugin**
|
||||
- Set the required settings (see below)
|
||||
- Choose run mode: **schedule** (recommended, runs every 5 minutes)
|
||||
|
||||
#### Required Settings
|
||||
|
||||
- **Fritz!Box Host** (`FRITZBOX_HOST`): Hostname or IP address of your Fritz!Box
|
||||
- Default: `fritz.box`
|
||||
- Alternative: `192.168.178.1` (or your Fritz!Box's IP)
|
||||
|
||||
- **TR-064 Port** (`FRITZBOX_PORT`): Port for TR-064 protocol
|
||||
- Default: `49443` (HTTPS). Use `49000` if HTTPS is disabled
|
||||
|
||||
- **Username** (`FRITZBOX_USER`): Fritz!Box username
|
||||
- Can be empty for some models when accessing from local network
|
||||
- For newer models, use an admin username
|
||||
|
||||
- **Password** (`FRITZBOX_PASS`): Fritz!Box password
|
||||
- Required: Your Fritz!Box admin password
|
||||
|
||||
#### Optional Settings
|
||||
|
||||
- **Use HTTPS** (`FRITZBOX_USE_TLS`): Enable secure HTTPS connection (default: `true`)
|
||||
- Recommended for security
|
||||
- Requires port `49443` instead of `49000`
|
||||
|
||||
- **Report Guest WiFi** (`FRITZBOX_REPORT_GUEST`): Create Access Point device for guest WiFi (default: `false`)
|
||||
- When enabled, adds a synthetic "Guest WiFi Network" device to your device list
|
||||
- Device appears only when guest WiFi is active
|
||||
- Useful for monitoring guest network status
|
||||
|
||||
- **Guest WiFi Service** (`FRITZBOX_GUEST_SERVICE`): Which WLANConfiguration service is the guest network (default: `3`)
|
||||
- Fritz!Box typically uses `1` for 2.4GHz, `2` for 5GHz, `3` for guest WiFi
|
||||
- Only relevant when **Report Guest WiFi** is enabled
|
||||
- Change this if your Fritz!Box uses a non-standard configuration
|
||||
|
||||
- **Active Devices Only** (`FRITZBOX_ACTIVE_ONLY`): Report only connected devices (default: `true`)
|
||||
- When enabled, only currently connected devices appear
|
||||
- When disabled, includes all devices stored in Fritz!Box memory (even if disconnected)
|
||||
|
||||
### Usage
|
||||
|
||||
1. Head to **Settings** > **Fritz!Box** to configure the plugin
|
||||
2. Set **When to run** to **schedule** (recommended) or **once** for manual testing
|
||||
3. The plugin will run every 5 minutes by default (configurable via **Schedule** setting)
|
||||
4. View discovered devices in the **Devices** page
|
||||
5. Check logs at `/tmp/log/plugins/script.FRITZBOX.log` for troubleshooting
|
||||
|
||||
### Device Information Reported
|
||||
|
||||
The plugin reports the following information for each device:
|
||||
|
||||
| Field | Description | Mapped To |
|
||||
|-------|-------------|-----------|
|
||||
| **MAC Address** | Device hardware address (normalized format) | `devMac` |
|
||||
| **IP Address** | Current IPv4 address | `devLastIP` |
|
||||
| **Hostname** | Device name from Fritz!Box | `devName` |
|
||||
| **Connection Status** | "Active" or "Inactive" | Plugin table only (not mapped to device fields) |
|
||||
| **Interface Type** | WiFi / LAN / Guest Network | `devType` |
|
||||
|
||||
### Guest WiFi Feature
|
||||
|
||||
When **Report Guest WiFi** is enabled and guest WiFi is active on your Fritz!Box:
|
||||
|
||||
- A synthetic device named **"Guest WiFi Network"** appears in your device list
|
||||
- Device Type: **Access Point**
|
||||
- MAC Address: Locally-administered synthetic MAC derived from Fritz!Box MAC (e.g., `02:a1:b2:c3:d4:e5`)
|
||||
- Status: Only appears when guest WiFi is enabled
|
||||
|
||||
This allows you to:
|
||||
- Monitor when guest WiFi is active
|
||||
- Set up notifications when guest network is enabled/disabled
|
||||
- Track guest network status alongside other network devices
|
||||
|
||||
> [!NOTE]
|
||||
> The guest WiFi device is synthetic (not a real physical device). It's created by the plugin to represent the guest network state.
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
#### Connection Refused / Timeout Errors
|
||||
|
||||
**Symptoms**: Plugin logs show "Failed to connect to Fritz!Box" or timeout errors
|
||||
|
||||
**Solutions**:
|
||||
1. Verify Fritz!Box is reachable:
|
||||
```bash
|
||||
ping fritz.box
|
||||
# or
|
||||
ping 192.168.178.1
|
||||
```
|
||||
|
||||
2. Check TR-064 is enabled:
|
||||
- Fritz!Box web interface > **Home Network > Network > Network Settings**
|
||||
- Enable **"Allow access for applications"**
|
||||
|
||||
3. Verify correct port:
|
||||
- HTTP: Port `49000`
|
||||
- HTTPS: Port `49443`
|
||||
- Match **Use HTTPS** setting with port
|
||||
|
||||
4. Check firewall rules (if NetAlertX runs in Docker):
|
||||
- Ensure container can reach Fritz!Box network
|
||||
- Use host IP instead of `fritz.box` if DNS resolution fails
|
||||
|
||||
#### Authentication Failed
|
||||
|
||||
**Symptoms**: "Authentication error" or "Invalid credentials"
|
||||
|
||||
**Solutions**:
|
||||
1. Verify password is correct
|
||||
2. Try leaving **Username** empty (some models allow this from local network)
|
||||
3. Create a dedicated user in Fritz!Box:
|
||||
- **System > Fritz!Box Users > Add User**
|
||||
- Grant network access permissions
|
||||
4. For newer Fritz!OS versions, ensure user has **"Access from home network"** permission
|
||||
|
||||
#### No Devices Found
|
||||
|
||||
**Symptoms**: Plugin runs successfully but reports 0 devices
|
||||
|
||||
**Solutions**:
|
||||
1. Check **Active Devices Only** setting:
|
||||
- If enabled, only connected devices appear
|
||||
- Disable to see all devices in Fritz!Box memory
|
||||
2. Verify devices are actually connected to Fritz!Box
|
||||
3. Check Fritz!Box web interface > **Home Network > Mesh** to see devices
|
||||
4. Increase log level to `verbose` and check `/tmp/log/plugins/script.FRITZBOX.log`
|
||||
|
||||
#### Guest WiFi Not Detected
|
||||
|
||||
**Symptoms**: Guest WiFi enabled but no Access Point device appears
|
||||
|
||||
**Solutions**:
|
||||
1. Ensure **Report Guest WiFi** is enabled
|
||||
2. Guest WiFi must be **active** (not just configured)
|
||||
3. Some Fritz!Box models don't expose guest network via TR-064
|
||||
4. Check plugin logs for "Guest WiFi active" message
|
||||
|
||||
### Limitations
|
||||
|
||||
- **Active-only filtering**: When `FRITZBOX_ACTIVE_ONLY` is enabled, the plugin only reports currently connected devices. Disconnected devices stored in Fritz!Box memory are ignored.
|
||||
|
||||
- **Guest WiFi synthetic device**: The guest WiFi Access Point is a synthetic device created by the plugin. Its MAC address is derived from the Fritz!Box MAC and doesn't represent a physical device.
|
||||
|
||||
- **Model differences**: Some Fritz!Box models may not expose all TR-064 services (e.g., guest WiFi detection). The plugin degrades gracefully if services are unavailable.
|
||||
|
||||
- **IPv6 support**: Currently reports IPv4 addresses only. IPv6 support may be added in future versions.
|
||||
|
||||
- **Device type detection**: Interface type (WiFi/LAN) is reported, but detailed device categorization (smartphone, laptop, etc.) is handled by NetAlertX's device type detection, not this plugin.
|
||||
|
||||
### Technical Details
|
||||
|
||||
**Protocol**: TR-064 (Technical Report 064) - UPnP-based device management protocol
|
||||
|
||||
**Library**: [fritzconnection](https://github.com/kbr/fritzconnection) >= 1.15.1
|
||||
|
||||
**Services Used**:
|
||||
- `FritzHosts`: Device discovery and information
|
||||
- `WLANConfiguration`: Guest WiFi status detection
|
||||
- `DeviceInfo`: Fritz!Box MAC address retrieval
|
||||
|
||||
**Execution Schedule**: Default every 5 minutes (configurable via cron syntax)
|
||||
|
||||
**Timeout**: 60 seconds (configurable via `RUN_TIMEOUT`)
|
||||
|
||||
### Notes
|
||||
|
||||
- **Performance**: TR-064 queries typically complete in under 2 seconds, even with many devices
|
||||
- **Security**: Passwords are stored in NetAlertX's configuration database and not logged
|
||||
- **Compatibility**: Tested with Fritz!Box models running Fritz!OS 7.x and 8.x
|
||||
- **Dependencies**: Requires `fritzconnection` Python library (automatically installed via requirements.txt)
|
||||
|
||||
### Version
|
||||
|
||||
- **Version**: 1.0.0
|
||||
- **Author**: [@sebingel](https://github.com/sebingel)
|
||||
- **Release Date**: April 2026
|
||||
|
||||
### Support
|
||||
|
||||
For issues, questions, or feature requests:
|
||||
- NetAlertX GitHub: [https://github.com/netalertx/NetAlertX](https://github.com/netalertx/NetAlertX)
|
||||
- Fritz!Box TR-064 Documentation: [https://avm.de/service/schnittstellen/](https://avm.de/service/schnittstellen/)
|
||||
2807
front/plugins/fritzbox/config.json
Executable file
2807
front/plugins/fritzbox/config.json
Executable file
File diff suppressed because it is too large
Load Diff
256
front/plugins/fritzbox/fritzbox.py
Executable file
256
front/plugins/fritzbox/fritzbox.py
Executable file
@@ -0,0 +1,256 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import os
|
||||
import sys
|
||||
from pytz import timezone
|
||||
|
||||
# Define the installation path and extend the system path for plugin imports
|
||||
INSTALL_PATH = os.getenv('NETALERTX_APP', '/app')
|
||||
sys.path.extend([f"{INSTALL_PATH}/front/plugins", f"{INSTALL_PATH}/server"])
|
||||
|
||||
from const import logPath # noqa: E402, E261 [flake8 lint suppression]
|
||||
from plugin_helper import Plugin_Objects, normalize_mac # noqa: E402, E261 [flake8 lint suppression]
|
||||
from logger import mylog, Logger # noqa: E402, E261 [flake8 lint suppression]
|
||||
from helper import get_setting_value # noqa: E402, E261 [flake8 lint suppression]
|
||||
from utils.crypto_utils import string_to_fake_mac # noqa: E402, E261 [flake8 lint suppression]
|
||||
from fritzconnection import FritzConnection # noqa: E402, E261 [flake8 lint suppression]
|
||||
from fritzconnection.lib.fritzhosts import FritzHosts # noqa: E402, E261 [flake8 lint suppression]
|
||||
|
||||
import conf # noqa: E402, E261 [flake8 lint suppression]
|
||||
|
||||
# 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 = 'FRITZBOX'
|
||||
|
||||
INTERFACE_MAP = {
|
||||
'802.11': 'WiFi',
|
||||
'Ethernet': 'LAN',
|
||||
}
|
||||
|
||||
# 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 get_fritzbox_connection(host, port, user, password, use_tls):
|
||||
"""
|
||||
Create FritzConnection with error handling.
|
||||
Returns: FritzConnection object or None on failure
|
||||
"""
|
||||
try:
|
||||
mylog('verbose', [f'[{pluginName}] Attempting connection to {host}:{port} (TLS: {use_tls})'])
|
||||
|
||||
fc = FritzConnection(
|
||||
address=host,
|
||||
port=port,
|
||||
user=user,
|
||||
password=password,
|
||||
use_tls=use_tls,
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
mylog('verbose', [f'[{pluginName}] Successfully connected to Fritz!Box'])
|
||||
mylog('verbose', [f'[{pluginName}] Model: {fc.modelname}, Software: {fc.system_version}'])
|
||||
|
||||
return fc
|
||||
except Exception as e:
|
||||
mylog('none', [f'[{pluginName}] ⚠ ERROR: Failed to connect to Fritz!Box: {e}'])
|
||||
mylog('none', [f'[{pluginName}] Check host ({host}), port ({port}), and credentials'])
|
||||
mylog('none', [f'[{pluginName}] Ensure TR-064 is enabled in Fritz!Box settings'])
|
||||
return None
|
||||
|
||||
|
||||
def get_connected_devices(fc, active_only):
|
||||
"""
|
||||
Query all hosts from Fritz!Box via FritzHosts service.
|
||||
Use get_hosts_info() for count, then get_generic_host_entry(index) for each.
|
||||
Filter by NewActive status if active_only=True.
|
||||
Returns: List of device dictionaries
|
||||
"""
|
||||
devices = []
|
||||
|
||||
try:
|
||||
hosts = FritzHosts(fc)
|
||||
host_count = hosts.host_numbers
|
||||
|
||||
mylog('verbose', [f'[{pluginName}] Found {host_count} total hosts in Fritz!Box'])
|
||||
|
||||
for index in range(host_count):
|
||||
try:
|
||||
host_info = hosts.get_generic_host_entry(index)
|
||||
|
||||
# Extract relevant fields
|
||||
mac_address = host_info.get('NewMACAddress', '')
|
||||
ip_address = host_info.get('NewIPAddress', '')
|
||||
hostname = host_info.get('NewHostName', '')
|
||||
active = host_info.get('NewActive', 0)
|
||||
interface_type = host_info.get('NewInterfaceType', 'Unknown')
|
||||
|
||||
# Skip if active_only and device is not active
|
||||
if active_only and not active:
|
||||
continue
|
||||
|
||||
# Skip entries without MAC address
|
||||
if not mac_address:
|
||||
continue
|
||||
|
||||
# Normalize MAC address
|
||||
mac_address = normalize_mac(mac_address)
|
||||
|
||||
# Map interface type to readable format
|
||||
interface_display = interface_type
|
||||
for key, value in INTERFACE_MAP.items():
|
||||
if key in interface_type:
|
||||
interface_display = value
|
||||
break
|
||||
|
||||
# Build device dictionary
|
||||
device = {
|
||||
'mac_address': mac_address,
|
||||
'ip_address': ip_address if ip_address else '',
|
||||
'hostname': hostname if hostname else 'Unknown',
|
||||
'active_status': 'Active' if active else 'Inactive',
|
||||
'interface_type': interface_display
|
||||
}
|
||||
|
||||
devices.append(device)
|
||||
mylog('verbose', [f'[{pluginName}] Device: {mac_address} ({hostname}) - {ip_address} - {interface_display}'])
|
||||
|
||||
except Exception as e:
|
||||
mylog('minimal', [f'[{pluginName}] Warning: Failed to get host entry {index}: {e}'])
|
||||
continue
|
||||
|
||||
mylog('verbose', [f'[{pluginName}] Processed {len(devices)} devices'])
|
||||
|
||||
except Exception as e:
|
||||
mylog('none', [f'[{pluginName}] ⚠ ERROR: Failed to query devices: {e}'])
|
||||
|
||||
return devices
|
||||
|
||||
|
||||
def check_guest_wifi_status(fc, guest_service_num):
|
||||
"""
|
||||
Query a specific WLANConfiguration service for guest network status.
|
||||
Returns: Dict with active status and interface info
|
||||
"""
|
||||
guest_info = {
|
||||
'active': False,
|
||||
'ssid': 'Guest WiFi',
|
||||
'interface': 'Guest Network'
|
||||
}
|
||||
|
||||
try:
|
||||
service = f'WLANConfiguration{guest_service_num}'
|
||||
result = fc.call_action(service, 'GetInfo')
|
||||
status = result.get('NewEnable', False)
|
||||
ssid = result.get('NewSSID', '')
|
||||
|
||||
if status:
|
||||
guest_info['active'] = True
|
||||
guest_info['ssid'] = ssid if ssid else 'Guest WiFi'
|
||||
mylog('verbose', [f'[{pluginName}] Guest WiFi active on service {guest_service_num}: {guest_info["ssid"]}'])
|
||||
else:
|
||||
mylog('verbose', [f'[{pluginName}] Guest WiFi service {guest_service_num} is disabled'])
|
||||
|
||||
except Exception as e:
|
||||
mylog('minimal', [f'[{pluginName}] Warning: Failed to query WLANConfiguration{guest_service_num}: {e}'])
|
||||
|
||||
return guest_info
|
||||
|
||||
|
||||
def create_guest_wifi_device(fc):
|
||||
"""
|
||||
Create a synthetic device entry for guest WiFi.
|
||||
Derives a deterministic fake MAC from the Fritz!Box hardware MAC address.
|
||||
Falls back to a fixed sentinel string if the MAC cannot be retrieved.
|
||||
Returns: Device dictionary
|
||||
"""
|
||||
try:
|
||||
fritzbox_mac = fc.call_action('DeviceInfo:1', 'GetInfo').get('NewMACAddress', '')
|
||||
guest_mac = string_to_fake_mac(normalize_mac(fritzbox_mac) if fritzbox_mac else 'FRITZBOX_GUEST')
|
||||
|
||||
device = {
|
||||
'mac_address': guest_mac,
|
||||
'ip_address': '',
|
||||
'hostname': 'Guest WiFi Network',
|
||||
'active_status': 'Active',
|
||||
'interface_type': 'Access Point'
|
||||
}
|
||||
|
||||
mylog('verbose', [f'[{pluginName}] Created guest WiFi device: {guest_mac}'])
|
||||
return device
|
||||
|
||||
except Exception as e:
|
||||
mylog('minimal', [f'[{pluginName}] Warning: Failed to create guest WiFi device: {e}'])
|
||||
return None
|
||||
|
||||
|
||||
def main():
|
||||
mylog('verbose', [f'[{pluginName}] In script'])
|
||||
|
||||
# Retrieve configuration settings
|
||||
host = get_setting_value('FRITZBOX_HOST')
|
||||
port = get_setting_value('FRITZBOX_PORT')
|
||||
user = get_setting_value('FRITZBOX_USER')
|
||||
password = get_setting_value('FRITZBOX_PASS')
|
||||
use_tls = get_setting_value('FRITZBOX_USE_TLS')
|
||||
report_guest = get_setting_value('FRITZBOX_REPORT_GUEST')
|
||||
guest_service = get_setting_value('FRITZBOX_GUEST_SERVICE')
|
||||
active_only = get_setting_value('FRITZBOX_ACTIVE_ONLY')
|
||||
|
||||
mylog('verbose', [f'[{pluginName}] Settings: host={host}, port={port}, use_tls={use_tls}, active_only={active_only}'])
|
||||
|
||||
# Create Fritz!Box connection
|
||||
fc = get_fritzbox_connection(host, port, user, password, use_tls)
|
||||
|
||||
if not fc:
|
||||
mylog('none', [f'[{pluginName}] ⚠ ERROR: Could not establish connection to Fritz!Box'])
|
||||
mylog('none', [f'[{pluginName}] Plugin will return empty results'])
|
||||
plugin_objects.write_result_file()
|
||||
return 1
|
||||
|
||||
# Retrieve device data
|
||||
device_data = get_connected_devices(fc, active_only)
|
||||
|
||||
# Check guest WiFi if enabled
|
||||
if report_guest:
|
||||
guest_status = check_guest_wifi_status(fc, guest_service)
|
||||
if guest_status['active']:
|
||||
guest_device = create_guest_wifi_device(fc)
|
||||
if guest_device:
|
||||
device_data.append(guest_device)
|
||||
|
||||
# Process the data into native application tables
|
||||
if device_data:
|
||||
for device in device_data:
|
||||
plugin_objects.add_object(
|
||||
primaryId=device['mac_address'],
|
||||
secondaryId=device['ip_address'],
|
||||
watched1=device['hostname'],
|
||||
watched2=device['active_status'],
|
||||
watched3=device['interface_type'],
|
||||
watched4='',
|
||||
extra='',
|
||||
foreignKey=device['mac_address']
|
||||
)
|
||||
|
||||
mylog('verbose', [f'[{pluginName}] Successfully processed {len(device_data)} devices'])
|
||||
else:
|
||||
mylog('minimal', [f'[{pluginName}] No devices found'])
|
||||
|
||||
# Log result
|
||||
plugin_objects.write_result_file()
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
@@ -276,7 +276,7 @@
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "List of IPs to ignore. Use <code>%</code> as a wildcard. Ignored devices will not be shown anywhere in the UI or notifications. <br/><br/>For example <code>192.168.3.%</code> to filter out an IP range."
|
||||
"string": "List of IPs to ignore. Use <code>%</code> as a wildcard. Ignored devices will not be shown anywhere in the UI or notifications. <br/><br/>For example <code>192.168.3.%</code> to filter out an IP range. (<code>%</code> matches any sequence of characters (including none) and <code>_</code> matches exactly one character."
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -19,6 +19,7 @@ __author__ = "xfilo"
|
||||
__version__ = 0.1 # Initial version
|
||||
__version__ = 0.2 # Rephrased error messages, improved logging and code logic
|
||||
__version__ = 0.3 # Refactored data collection into a class, improved code clarity with comments
|
||||
__version__ = 0.4 # Fix for https://github.com/netalertx/NetAlertX/issues/1595 - Omada Controller versions >= 6.2.0.0 removed the v1 clients endpoint
|
||||
|
||||
import os
|
||||
import sys
|
||||
@@ -26,9 +27,11 @@ import urllib3
|
||||
import requests
|
||||
import time
|
||||
import pytz
|
||||
import operator
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Literal, Any, Dict
|
||||
from packaging.version import Version, InvalidVersion
|
||||
|
||||
# Define the installation path and extend the system path for plugin imports
|
||||
INSTALL_PATH = os.getenv('NETALERTX_APP', '/app')
|
||||
@@ -220,6 +223,40 @@ class OmadaHelper:
|
||||
msg = f"Failed normalizing {input_type}(s) from site '{site_name}' - error: {str(ex)}"
|
||||
OmadaHelper.verbose(msg)
|
||||
return OmadaHelper.response("error", msg)
|
||||
|
||||
@staticmethod
|
||||
def version_check(version, base: str, op: str = ">=") -> bool:
|
||||
"""
|
||||
Compare versions using PEP 440 semantics.
|
||||
Supports int and str inputs.
|
||||
"""
|
||||
ops = {
|
||||
"==": operator.eq,
|
||||
"!=": operator.ne,
|
||||
">": operator.gt,
|
||||
">=": operator.ge,
|
||||
"<": operator.lt,
|
||||
"<=": operator.le,
|
||||
}
|
||||
|
||||
if op not in ops:
|
||||
raise ValueError("Unsupported operator")
|
||||
|
||||
def to_version(v):
|
||||
if isinstance(v, int):
|
||||
return Version(str(v))
|
||||
if isinstance(v, str):
|
||||
try:
|
||||
return Version(v)
|
||||
except InvalidVersion:
|
||||
# fallback: treat invalid versions as 0
|
||||
return Version("0")
|
||||
raise TypeError("version/base must be int or str")
|
||||
|
||||
v = to_version(version)
|
||||
b = to_version(base)
|
||||
|
||||
return ops[op](v, b)
|
||||
|
||||
|
||||
class OmadaAPI:
|
||||
@@ -259,6 +296,7 @@ class OmadaAPI:
|
||||
self.active_sites_dict = {}
|
||||
self.access_token = None
|
||||
self.refresh_token = None
|
||||
self.controller_version = None
|
||||
|
||||
OmadaHelper.verbose("OmadaAPI initialized")
|
||||
|
||||
@@ -328,11 +366,57 @@ class OmadaAPI:
|
||||
OmadaHelper.debug(f"Authentication response: {response}")
|
||||
return OmadaHelper.response("error", f"Authentication failed - error: {response.get('response_message', 'Not provided')}")
|
||||
|
||||
def get_controller_status(self) -> Dict[str, Any]:
|
||||
"""Make an endpoint request to get controller status."""
|
||||
OmadaHelper.verbose(f"Retrieving controller status for CID: {getattr(self, 'omada_id')}")
|
||||
endpoint = f"/openapi/v1/{getattr(self, 'omada_id')}/system/setting/controller-status"
|
||||
response = self._make_request("GET", endpoint)
|
||||
|
||||
if response.get("response_type") == "success":
|
||||
response_result = response.get("response_result") or {}
|
||||
result = response_result.get("result") or {}
|
||||
self.controller_version = result.get("controllerVersion")
|
||||
if not self.controller_version:
|
||||
self.controller_version = None
|
||||
OmadaHelper.debug(f"Controller status: {response}")
|
||||
return OmadaHelper.response("error", "Controller status response did not include controllerVersion")
|
||||
else:
|
||||
return OmadaHelper.response("success", "Successfully retrieved controller status")
|
||||
|
||||
OmadaHelper.debug(f"Controller status: {response}")
|
||||
return OmadaHelper.response("error", "Failed to call controller status endpoint")
|
||||
|
||||
def get_clients(self, site_id: str) -> Dict[str, Any]:
|
||||
"""Make an endpoint request to get all online clients on a site."""
|
||||
OmadaHelper.verbose(f"Retrieving clients for site: {site_id}")
|
||||
endpoint = f"/openapi/v1/{getattr(self, 'omada_id')}/sites/{site_id}/clients?page=1&pageSize={getattr(self, 'page_size')}"
|
||||
return self._make_request("GET", endpoint)
|
||||
|
||||
page_size = getattr(self, 'page_size')
|
||||
omada_id = getattr(self, 'omada_id')
|
||||
|
||||
def call_v2():
|
||||
endpoint = f"/openapi/v2/{omada_id}/sites/{site_id}/clients"
|
||||
payload = {
|
||||
"page": 1,
|
||||
"pageSize": page_size,
|
||||
"scope": 1
|
||||
}
|
||||
return self._make_request("POST", endpoint, json=payload)
|
||||
|
||||
def call_v1():
|
||||
endpoint = f"/openapi/v1/{omada_id}/sites/{site_id}/clients?page=1&pageSize={page_size}"
|
||||
return self._make_request("GET", endpoint)
|
||||
|
||||
if self.controller_version is None:
|
||||
OmadaHelper.verbose("Controller version unknown, trying v2 then v1")
|
||||
resp = call_v2()
|
||||
if resp and resp.get("response_type") == "success":
|
||||
return resp
|
||||
return call_v1()
|
||||
|
||||
if OmadaHelper.version_check(self.controller_version, "6.2.0.0", ">="):
|
||||
return call_v2()
|
||||
|
||||
return call_v1()
|
||||
|
||||
def get_devices(self, site_id: str) -> Dict[str, Any]:
|
||||
"""Make an endpoint request to get all online devices on a site."""
|
||||
@@ -454,6 +538,13 @@ class OmadaData:
|
||||
OmadaHelper.minimal("Authentication failed, aborting data collection")
|
||||
OmadaHelper.debug(f"{auth_result['response_message']}")
|
||||
return plugin_objects
|
||||
|
||||
# Controller status
|
||||
status_result = omada_api.get_controller_status()
|
||||
if status_result["response_type"] == "error":
|
||||
OmadaHelper.verbose(f"Controller version lookup failed: {status_result['response_message']}")
|
||||
else:
|
||||
OmadaHelper.verbose(f"Controller version: {omada_api.controller_version}")
|
||||
|
||||
# Populate sites
|
||||
sites_result = omada_api.populate_sites()
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"display_name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "UI settings"
|
||||
"string": "UI Settings"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
@@ -456,7 +456,7 @@
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Columns and their order that are shown on the Devices page. Drag and drop the order of columns, click <code>x</code> to remove columns. You can also click into the field to selectivelly add fields. The <code>Name</code> and <code>Status</code> fields are required."
|
||||
"string": "Columns and their order that are shown on the Devices page. Drag and drop to order the columns, click <code>x</code> to remove columns. You can also click into the field to selectivelly add fields. The <code>Name</code> and <code>Status</code> fields are required."
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -522,6 +522,7 @@
|
||||
"Device_TableHead_SSID",
|
||||
"Device_TableHead_SourcePlugin",
|
||||
"Device_TableHead_ParentRelType",
|
||||
"Device_TableHead_Parent_MAC",
|
||||
"Device_TableHead_Vlan"
|
||||
],
|
||||
"localized": ["name", "description"],
|
||||
@@ -534,7 +535,7 @@
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Which column filters should be displayed in the main Devices screen. Remove all to hide the Filters section."
|
||||
"string": "Column filters that should be displayed in the main Devices screen. Drag and drop to change the order. Remove all to hide the Filters section."
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -513,6 +513,12 @@ function generateTabs() {
|
||||
}
|
||||
});
|
||||
|
||||
if (visiblePlugins.length === 0) {
|
||||
$('#tabs-content-location').html(`<p class="text-muted" style="padding: 15px;">${getString('Gen_No_Data')}</p>`);
|
||||
hideSpinner();
|
||||
return;
|
||||
}
|
||||
|
||||
// Auto-select tab from ?tab= URL param or cache (scoped to plugin nav only)
|
||||
initializeTabsShared({
|
||||
cacheKey: 'activePluginsTab',
|
||||
|
||||
@@ -25,3 +25,4 @@ yattag
|
||||
zeroconf
|
||||
psutil
|
||||
freebox-api
|
||||
fritzconnection>=1.15.1
|
||||
|
||||
@@ -25,3 +25,4 @@ yattag
|
||||
zeroconf
|
||||
psutil
|
||||
freebox-api
|
||||
fritzconnection>=1.15.1
|
||||
|
||||
@@ -34,3 +34,4 @@ freebox-api
|
||||
mcp
|
||||
psutil
|
||||
pydantic>=2.0,<3.0
|
||||
fritzconnection>=1.15.1
|
||||
|
||||
@@ -27,7 +27,7 @@ from logger import mylog
|
||||
from helper import filePermissions
|
||||
from utils.datetime_utils import timeNowUTC
|
||||
from app_state import updateState
|
||||
from api import update_api
|
||||
from api import update_api, check_activity, update_GUI_port
|
||||
from scan.session_events import process_scan
|
||||
from initialise import importConfigs, renameSettings
|
||||
from database import DB
|
||||
@@ -85,6 +85,9 @@ def main():
|
||||
# Initialize the WorkflowManager
|
||||
workflow_manager = WorkflowManager(db)
|
||||
|
||||
#Run this once to update the defined GUI port for the activity check
|
||||
update_GUI_port()
|
||||
|
||||
# ===============================================================================
|
||||
# This is the main loop of NetAlertX
|
||||
# ===============================================================================
|
||||
@@ -261,8 +264,23 @@ def main():
|
||||
if userUpdatedDevices:
|
||||
update_api(db, all_plugins, True, ["devices"], userUpdatedDevices)
|
||||
|
||||
# loop
|
||||
time.sleep(5) # wait for N seconds
|
||||
# ------------------------------------------------------------------
|
||||
# Loop with dynamic sleep if enabled (energy saving)
|
||||
# ------------------------------------------------------------------
|
||||
if conf.DEEP_SLEEP:
|
||||
is_active = check_activity()
|
||||
|
||||
if is_active:
|
||||
mylog("debug", ["[DEEP_SLEEP] Active Cycle"])
|
||||
time.sleep(5)
|
||||
else:
|
||||
mylog("debug", ["[DEEP_SLEEP] Passive Cycle"])
|
||||
for _ in range(3):
|
||||
if check_activity():
|
||||
break
|
||||
time.sleep(20)
|
||||
else:
|
||||
time.sleep(5)
|
||||
|
||||
|
||||
# ===============================================================================
|
||||
|
||||
@@ -3,6 +3,7 @@ import json
|
||||
import time
|
||||
import threading
|
||||
import datetime
|
||||
import os
|
||||
|
||||
# Register NetAlertX modules
|
||||
import conf
|
||||
@@ -21,6 +22,7 @@ from const import (
|
||||
sql_notifications_all,
|
||||
sql_online_history,
|
||||
sql_devices_filters,
|
||||
defaultWebPort,
|
||||
)
|
||||
from db.db_helper import get_sql_devices_tiles
|
||||
from logger import mylog
|
||||
@@ -34,6 +36,8 @@ from api_server.api_server_start import start_server
|
||||
|
||||
apiEndpoints = []
|
||||
|
||||
hex_gui_port = None
|
||||
|
||||
# Lock for thread safety
|
||||
api_lock = threading.Lock()
|
||||
periodic_write_lock = threading.Lock()
|
||||
@@ -251,3 +255,47 @@ def stop_periodic_write():
|
||||
periodic_write_thread.join()
|
||||
periodic_write_running = False
|
||||
mylog("trace", ["[API] periodic_write thread stopped."])
|
||||
|
||||
|
||||
def update_GUI_port():
|
||||
"""
|
||||
Grabs the PORT for the webinterface and converts it to HEX to use for activity checks
|
||||
"""
|
||||
global hex_gui_port
|
||||
|
||||
gui_port_string = os.environ.get('PORT', str(defaultWebPort))
|
||||
try:
|
||||
port = int(gui_port_string)
|
||||
except (TypeError, ValueError):
|
||||
mylog("none", [f"[API] Invalid PORT value '{gui_port_string}', falling back to {defaultWebPort}"])
|
||||
port = defaultWebPort
|
||||
hex_gui_port = ':' + format(port, '04X')
|
||||
|
||||
|
||||
def check_activity():
|
||||
"""
|
||||
Check for active TCP connections on the host.
|
||||
|
||||
Reads `/proc/net/tcp` and looks for entries in the ESTABLISHED state
|
||||
(state code `01`). If any are found, the system is considered "active",
|
||||
typically indicating interaction via the web UI or API.
|
||||
|
||||
Returns:
|
||||
bool: True if at least one established TCP connection exists,
|
||||
False otherwise or if the check fails.
|
||||
|
||||
Notes:
|
||||
- Linux-only: relies on `/proc/net/tcp`.
|
||||
- Lightweight heuristic; does not distinguish connection origin
|
||||
(e.g., UI vs other services).
|
||||
- Fail-safe: returns False on any read/parse error.
|
||||
"""
|
||||
|
||||
try:
|
||||
with open("/proc/net/tcp", "r") as f:
|
||||
for line in f:
|
||||
if hex_gui_port in line and " 01 " in line:
|
||||
return True
|
||||
except:
|
||||
pass
|
||||
return False
|
||||
@@ -585,6 +585,11 @@ def api_device_set_alias(mac, payload=None):
|
||||
|
||||
device_handler = DeviceInstance()
|
||||
result = device_handler.updateDeviceColumn(mac, 'devName', alias)
|
||||
|
||||
if not result.get("success"):
|
||||
err = result.get("error") or result.get("message") or f"Failed to update alias for device {mac}"
|
||||
return jsonify({"success": False, "error": err})
|
||||
|
||||
return jsonify(result)
|
||||
|
||||
|
||||
|
||||
@@ -33,9 +33,19 @@ COLUMN_NAME_PATTERN = re.compile(r"^[a-zA-Z0-9_]+$")
|
||||
|
||||
# Security whitelists & Literals for documentation
|
||||
ALLOWED_DEVICE_COLUMNS = Literal[
|
||||
# Main Info
|
||||
"devName", "devOwner", "devType", "devVendor",
|
||||
"devGroup", "devLocation", "devComments", "devFavorite",
|
||||
"devParentMAC", "devCanSleep"
|
||||
"devGroup", "devLocation", "devComments", "devIcon",
|
||||
# Alerts & Behavior
|
||||
"devFavorite", "devAlertEvents", "devAlertDown",
|
||||
"devCanSleep", "devSkipRepeated", "devReqNicsOnline", "devForceStatus",
|
||||
# Network topology
|
||||
"devParentMAC", "devParentPort", "devParentRelType",
|
||||
"devSSID", "devSite", "devVlan",
|
||||
# Display / Status
|
||||
"devStaticIP", "devIsNew", "devIsArchived",
|
||||
# Custom properties
|
||||
"devCustomProps",
|
||||
]
|
||||
|
||||
ALLOWED_NMAP_MODES = Literal[
|
||||
@@ -407,7 +417,7 @@ class UpdateDeviceColumnRequest(BaseModel):
|
||||
class LockDeviceFieldRequest(BaseModel):
|
||||
"""Request to lock/unlock a device field."""
|
||||
fieldName: str = Field(..., description="Field name to lock/unlock (e.g., devName, devVendor). Required.")
|
||||
lock: bool = Field(True, description="True to lock the field, False to unlock")
|
||||
lock: bool = Field(False, description="True to lock the field, False (default) to unlock")
|
||||
|
||||
|
||||
class UnlockDeviceFieldsRequest(BaseModel):
|
||||
@@ -420,7 +430,7 @@ class UnlockDeviceFieldsRequest(BaseModel):
|
||||
None,
|
||||
description="List of field names to unlock. If omitted, all tracked fields will be unlocked"
|
||||
)
|
||||
clear_all: bool = Field(
|
||||
clearAll: bool = Field(
|
||||
False,
|
||||
description="True to clear all sources, False to clear only LOCKED/USER"
|
||||
)
|
||||
|
||||
@@ -30,6 +30,7 @@ logRoot = LOG_PATH_STR
|
||||
|
||||
dbFileName = "app.db"
|
||||
confFileName = "app.conf"
|
||||
defaultWebPort = 20211
|
||||
|
||||
confPath = CONFIG_PATH_WITH_TRAILING_SEP + confFileName
|
||||
dbPath = DB_PATH_WITH_TRAILING_SEP + dbFileName
|
||||
@@ -68,39 +69,46 @@ sql_devices_all = """
|
||||
"""
|
||||
|
||||
sql_appevents = """select * from AppEvents order by dateTimeCreated desc"""
|
||||
sql_devices_filters = """
|
||||
SELECT DISTINCT 'devSite' AS columnName, devSite AS columnValue
|
||||
FROM Devices WHERE devSite NOT IN ('', 'null') AND devSite IS NOT NULL
|
||||
sql_devices_filters = f"""
|
||||
SELECT DISTINCT 'devSite' AS columnName, devSite AS columnValue, devSite AS columnLabel
|
||||
FROM Devices WHERE devSite NOT IN ({NULL_EQUIVALENTS_SQL}) AND devSite IS NOT NULL
|
||||
UNION
|
||||
SELECT DISTINCT 'devSourcePlugin' AS columnName, devSourcePlugin AS columnValue
|
||||
FROM Devices WHERE devSourcePlugin NOT IN ('', 'null') AND devSourcePlugin IS NOT NULL
|
||||
SELECT DISTINCT 'devSourcePlugin' AS columnName, devSourcePlugin AS columnValue, devSourcePlugin AS columnLabel
|
||||
FROM Devices WHERE devSourcePlugin NOT IN ({NULL_EQUIVALENTS_SQL}) AND devSourcePlugin IS NOT NULL
|
||||
UNION
|
||||
SELECT DISTINCT 'devOwner' AS columnName, devOwner AS columnValue
|
||||
FROM Devices WHERE devOwner NOT IN ('', 'null') AND devOwner IS NOT NULL
|
||||
SELECT DISTINCT 'devOwner' AS columnName, devOwner AS columnValue, devOwner AS columnLabel
|
||||
FROM Devices WHERE devOwner NOT IN ({NULL_EQUIVALENTS_SQL}) AND devOwner IS NOT NULL
|
||||
UNION
|
||||
SELECT DISTINCT 'devType' AS columnName, devType AS columnValue
|
||||
FROM Devices WHERE devType NOT IN ('', 'null') AND devType IS NOT NULL
|
||||
SELECT DISTINCT 'devType' AS columnName, devType AS columnValue, devType AS columnLabel
|
||||
FROM Devices WHERE devType NOT IN ({NULL_EQUIVALENTS_SQL}) AND devType IS NOT NULL
|
||||
UNION
|
||||
SELECT DISTINCT 'devGroup' AS columnName, devGroup AS columnValue
|
||||
FROM Devices WHERE devGroup NOT IN ('', 'null') AND devGroup IS NOT NULL
|
||||
SELECT DISTINCT 'devGroup' AS columnName, devGroup AS columnValue, devGroup AS columnLabel
|
||||
FROM Devices WHERE devGroup NOT IN ({NULL_EQUIVALENTS_SQL}) AND devGroup IS NOT NULL
|
||||
UNION
|
||||
SELECT DISTINCT 'devLocation' AS columnName, devLocation AS columnValue
|
||||
FROM Devices WHERE devLocation NOT IN ('', 'null') AND devLocation IS NOT NULL
|
||||
SELECT DISTINCT 'devLocation' AS columnName, devLocation AS columnValue, devLocation AS columnLabel
|
||||
FROM Devices WHERE devLocation NOT IN ({NULL_EQUIVALENTS_SQL}) AND devLocation IS NOT NULL
|
||||
UNION
|
||||
SELECT DISTINCT 'devVendor' AS columnName, devVendor AS columnValue
|
||||
FROM Devices WHERE devVendor NOT IN ('', 'null') AND devVendor IS NOT NULL
|
||||
SELECT DISTINCT 'devVendor' AS columnName, devVendor AS columnValue, devVendor AS columnLabel
|
||||
FROM Devices WHERE devVendor NOT IN ({NULL_EQUIVALENTS_SQL}) AND devVendor IS NOT NULL
|
||||
UNION
|
||||
SELECT DISTINCT 'devSyncHubNode' AS columnName, devSyncHubNode AS columnValue
|
||||
FROM Devices WHERE devSyncHubNode NOT IN ('', 'null') AND devSyncHubNode IS NOT NULL
|
||||
SELECT DISTINCT 'devSyncHubNode' AS columnName, devSyncHubNode AS columnValue, devSyncHubNode AS columnLabel
|
||||
FROM Devices WHERE devSyncHubNode NOT IN ({NULL_EQUIVALENTS_SQL}) AND devSyncHubNode IS NOT NULL
|
||||
UNION
|
||||
SELECT DISTINCT 'devVlan' AS columnName, devVlan AS columnValue
|
||||
FROM Devices WHERE devVlan NOT IN ('', 'null') AND devVlan IS NOT NULL
|
||||
SELECT DISTINCT 'devVlan' AS columnName, devVlan AS columnValue, devVlan AS columnLabel
|
||||
FROM Devices WHERE devVlan NOT IN ({NULL_EQUIVALENTS_SQL}) AND devVlan IS NOT NULL
|
||||
UNION
|
||||
SELECT DISTINCT 'devParentRelType' AS columnName, devParentRelType AS columnValue
|
||||
FROM Devices WHERE devParentRelType NOT IN ('', 'null') AND devParentRelType IS NOT NULL
|
||||
SELECT 'devParentMAC' AS columnName, d.devParentMAC AS columnValue,
|
||||
COALESCE(p.devName, d.devParentMAC) AS columnLabel
|
||||
FROM Devices d
|
||||
LEFT JOIN Devices p ON LOWER(p.devMac) = LOWER(d.devParentMAC)
|
||||
WHERE d.devParentMAC NOT IN ({NULL_EQUIVALENTS_SQL}) AND d.devParentMAC IS NOT NULL
|
||||
GROUP BY d.devParentMAC COLLATE NOCASE
|
||||
UNION
|
||||
SELECT DISTINCT 'devSSID' AS columnName, devSSID AS columnValue
|
||||
FROM Devices WHERE devSSID NOT IN ('', 'null') AND devSSID IS NOT NULL
|
||||
SELECT DISTINCT 'devParentRelType' AS columnName, devParentRelType AS columnValue, devParentRelType AS columnLabel
|
||||
FROM Devices WHERE devParentRelType NOT IN ({NULL_EQUIVALENTS_SQL}) AND devParentRelType IS NOT NULL
|
||||
UNION
|
||||
SELECT DISTINCT 'devSSID' AS columnName, devSSID AS columnValue, devSSID AS columnLabel
|
||||
FROM Devices WHERE devSSID NOT IN ({NULL_EQUIVALENTS_SQL}) AND devSSID IS NOT NULL
|
||||
ORDER BY columnName;
|
||||
"""
|
||||
|
||||
|
||||
@@ -246,6 +246,15 @@ def importConfigs(pm, db, all_plugins):
|
||||
"[]",
|
||||
"General",
|
||||
)
|
||||
conf.DEEP_SLEEP = ccd(
|
||||
"DEEP_SLEEP",
|
||||
False,
|
||||
c_d,
|
||||
"Deep Sleep",
|
||||
"""{"dataType": "boolean","elements": [{"elementType": "input","elementOptions": [{ "type": "checkbox" }],"transformers": []}]}""",
|
||||
"[]",
|
||||
"General",
|
||||
)
|
||||
conf.DISCOVER_PLUGINS = ccd(
|
||||
"DISCOVER_PLUGINS",
|
||||
True,
|
||||
|
||||
@@ -786,6 +786,10 @@ def process_plugin_events(db, plugin, plugEventsArr):
|
||||
pluginEvents[index].status = "watched-not-changed"
|
||||
index += 1
|
||||
|
||||
# Track objects whose state actually changed this cycle
|
||||
# (only these will be recorded in Plugins_History)
|
||||
changed_this_cycle = set()
|
||||
|
||||
# Loop thru events and check if previously available objects are missing
|
||||
for tmpObj in pluginObjects:
|
||||
isMissing = True
|
||||
@@ -799,6 +803,7 @@ def process_plugin_events(db, plugin, plugEventsArr):
|
||||
if tmpObj.status != "missing-in-last-scan":
|
||||
tmpObj.changed = timeNowUTC()
|
||||
tmpObj.status = "missing-in-last-scan"
|
||||
changed_this_cycle.add(tmpObj.idsHash)
|
||||
# mylog('debug', [f'[Plugins] Missing from last scan (PrimaryID | SecondaryID): {tmpObj.primaryId} | {tmpObj.secondaryId}'])
|
||||
|
||||
# Merge existing plugin objects with newly discovered ones and update existing ones with new values
|
||||
@@ -807,6 +812,7 @@ def process_plugin_events(db, plugin, plugEventsArr):
|
||||
if tmpObjFromEvent.status == "not-processed":
|
||||
# This is a new object as it was not discovered as "exists" previously
|
||||
tmpObjFromEvent.status = "new"
|
||||
changed_this_cycle.add(tmpObjFromEvent.idsHash)
|
||||
|
||||
pluginObjects.append(tmpObjFromEvent)
|
||||
# update data of existing objects
|
||||
@@ -815,6 +821,11 @@ def process_plugin_events(db, plugin, plugEventsArr):
|
||||
for plugObj in pluginObjects:
|
||||
# find corresponding object for the event and merge
|
||||
if plugObj.idsHash == tmpObjFromEvent.idsHash:
|
||||
if (
|
||||
plugObj.status == "missing-in-last-scan"
|
||||
or tmpObjFromEvent.status == "watched-changed"
|
||||
):
|
||||
changed_this_cycle.add(tmpObjFromEvent.idsHash)
|
||||
pluginObjects[index] = combine_plugin_objects(
|
||||
plugObj, tmpObjFromEvent
|
||||
)
|
||||
@@ -871,8 +882,9 @@ def process_plugin_events(db, plugin, plugEventsArr):
|
||||
if plugObj.status in statuses_to_report_on:
|
||||
events_to_insert.append(values)
|
||||
|
||||
# combine all DB insert and update events into one for history
|
||||
history_to_insert.append(values)
|
||||
# Only record history for objects that actually changed this cycle
|
||||
if plugObj.idsHash in changed_this_cycle:
|
||||
history_to_insert.append(values)
|
||||
|
||||
mylog("debug", f"[Plugins] pluginEvents count: {len(pluginEvents)}")
|
||||
mylog("debug", f"[Plugins] pluginObjects count: {len(pluginObjects)}")
|
||||
|
||||
@@ -5,7 +5,7 @@ import ipaddress
|
||||
from helper import get_setting_value, check_IP_format
|
||||
from utils.datetime_utils import timeNowUTC, normalizeTimeStamp
|
||||
from logger import mylog, Logger
|
||||
from const import vendorsPath, vendorsPathNewest, sql_generateGuid, NULL_EQUIVALENTS
|
||||
from const import vendorsPath, vendorsPathNewest, sql_generateGuid, NULL_EQUIVALENTS, NULL_EQUIVALENTS_SQL
|
||||
from models.device_instance import DeviceInstance
|
||||
from scan.name_resolution import NameResolver
|
||||
from scan.device_heuristics import guess_icon, guess_type
|
||||
@@ -240,6 +240,29 @@ def update_devLastConnection_from_CurrentScan(db):
|
||||
""")
|
||||
|
||||
|
||||
def update_sync_hub_node(db):
|
||||
"""
|
||||
Backfill devSyncHubNode with SYNC_node_name for devices where it is empty.
|
||||
Mirrors the fallback already used in create_new_devices.
|
||||
"""
|
||||
sql = db.sql
|
||||
node_name = str(get_setting_value("SYNC_node_name") or "").strip()
|
||||
|
||||
if not node_name:
|
||||
return
|
||||
|
||||
sql.execute(
|
||||
f"""
|
||||
UPDATE Devices
|
||||
SET devSyncHubNode = ?
|
||||
WHERE COALESCE(LOWER(TRIM(devSyncHubNode)), '') IN ({NULL_EQUIVALENTS_SQL})
|
||||
""",
|
||||
(node_name,),
|
||||
)
|
||||
|
||||
db.commitDB()
|
||||
|
||||
|
||||
def update_devices_data_from_scan(db):
|
||||
sql = db.sql
|
||||
|
||||
@@ -378,11 +401,11 @@ def update_icons_and_types(db):
|
||||
|
||||
if get_setting_value("NEWDEV_replace_preset_icon"):
|
||||
query = f"""SELECT * FROM Devices
|
||||
WHERE devIcon in ('', 'null', '{default_icon}')
|
||||
WHERE devIcon in ({NULL_EQUIVALENTS_SQL}, '{default_icon}')
|
||||
OR devIcon IS NULL"""
|
||||
else:
|
||||
query = """SELECT * FROM Devices
|
||||
WHERE devIcon in ('', 'null')
|
||||
query = f"""SELECT * FROM Devices
|
||||
WHERE devIcon in ({NULL_EQUIVALENTS_SQL})
|
||||
OR devIcon IS NULL"""
|
||||
|
||||
for device in sql.execute(query):
|
||||
@@ -406,8 +429,8 @@ def update_icons_and_types(db):
|
||||
|
||||
# Guess Type
|
||||
recordsToUpdate = []
|
||||
query = """SELECT * FROM Devices
|
||||
WHERE devType in ('', 'null')
|
||||
query = f"""SELECT * FROM Devices
|
||||
WHERE devType in ({NULL_EQUIVALENTS_SQL})
|
||||
OR devType IS NULL"""
|
||||
default_type = get_setting_value("NEWDEV_devType")
|
||||
|
||||
@@ -529,7 +552,7 @@ def save_scanned_devices(db):
|
||||
def print_scan_stats(db):
|
||||
sql = db.sql # TO-DO
|
||||
|
||||
query = """
|
||||
query = f"""
|
||||
SELECT
|
||||
(SELECT COUNT(*) FROM CurrentScan) AS devices_detected,
|
||||
(SELECT COUNT(*) FROM CurrentScan WHERE NOT EXISTS (SELECT 1 FROM Devices WHERE devMac = scanMac)) AS new_devices,
|
||||
@@ -544,7 +567,7 @@ def print_scan_stats(db):
|
||||
(SELECT COUNT(*) FROM Devices, CurrentScan
|
||||
WHERE devMac = scanMac
|
||||
AND scanLastIP IS NOT NULL
|
||||
AND scanLastIP NOT IN ('', 'null', '(unknown)', '(Unknown)')
|
||||
AND scanLastIP NOT IN ({NULL_EQUIVALENTS_SQL})
|
||||
AND scanLastIP <> COALESCE(devPrimaryIPv4, '')
|
||||
AND scanLastIP <> COALESCE(devPrimaryIPv6, '')
|
||||
AND scanLastIP <> COALESCE(devLastIP, '')
|
||||
|
||||
@@ -4,6 +4,7 @@ from scan.device_handling import (
|
||||
save_scanned_devices,
|
||||
exclude_ignored_devices,
|
||||
update_devices_data_from_scan,
|
||||
update_sync_hub_node,
|
||||
update_vendors_from_mac,
|
||||
update_icons_and_types,
|
||||
update_devPresentLastScan_based_on_force_status,
|
||||
@@ -20,6 +21,10 @@ from messaging.reporting import skip_repeated_notifications
|
||||
from messaging.in_app import update_unread_notifications_count
|
||||
from const import NULL_EQUIVALENTS_SQL
|
||||
|
||||
# Predicate used in every negative-event INSERT to skip forced-online devices.
|
||||
# Centralised here so all three event paths stay in sync.
|
||||
_SQL_NOT_FORCED_ONLINE = "LOWER(COALESCE(devForceStatus, '')) != 'online'"
|
||||
|
||||
|
||||
# Make sure log level is initialized correctly
|
||||
Logger(get_setting_value("LOG_LEVEL"))
|
||||
@@ -58,6 +63,10 @@ def process_scan(db):
|
||||
mylog("verbose", "[Process Scan] Updating Devices Info")
|
||||
update_devices_data_from_scan(db)
|
||||
|
||||
# Backfill devSyncHubNode for devices where it is empty
|
||||
mylog("verbose", "[Process Scan] Updating Sync Hub Node")
|
||||
update_sync_hub_node(db)
|
||||
|
||||
# Last Connection Time stamp from CurrentScan
|
||||
mylog("verbose", "[Process Scan] Updating devLastConnection from CurrentScan")
|
||||
update_devLastConnection_from_CurrentScan(db)
|
||||
@@ -179,6 +188,7 @@ def insert_events(db):
|
||||
WHERE devAlertDown != 0
|
||||
AND devCanSleep = 0
|
||||
AND devPresentLastScan = 1
|
||||
AND {_SQL_NOT_FORCED_ONLINE}
|
||||
AND NOT EXISTS (SELECT 1 FROM CurrentScan
|
||||
WHERE devMac = scanMac
|
||||
) """)
|
||||
@@ -194,6 +204,7 @@ def insert_events(db):
|
||||
AND devCanSleep = 1
|
||||
AND devIsSleeping = 0
|
||||
AND devPresentLastScan = 0
|
||||
AND {_SQL_NOT_FORCED_ONLINE}
|
||||
AND NOT EXISTS (SELECT 1 FROM CurrentScan
|
||||
WHERE devMac = scanMac)
|
||||
AND NOT EXISTS (SELECT 1 FROM Events
|
||||
@@ -229,6 +240,7 @@ def insert_events(db):
|
||||
FROM Devices
|
||||
WHERE devAlertDown = 0
|
||||
AND devPresentLastScan = 1
|
||||
AND {_SQL_NOT_FORCED_ONLINE}
|
||||
AND NOT EXISTS (SELECT 1 FROM CurrentScan
|
||||
WHERE devMac = scanMac
|
||||
) """)
|
||||
|
||||
@@ -6,6 +6,7 @@ Import from any test subdirectory with:
|
||||
import sys, os
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
|
||||
from db_test_helpers import make_db, insert_device, minutes_ago, DummyDB, down_event_macs, make_device_dict, sync_insert_devices
|
||||
from db_test_helpers import make_plugin_db, make_plugin_dict, make_plugin_event_row, seed_plugin_object, plugin_history_rows, plugin_objects_rows, PluginFakeDB
|
||||
"""
|
||||
|
||||
import sqlite3
|
||||
@@ -171,6 +172,7 @@ def insert_device(
|
||||
can_sleep: int = 0,
|
||||
last_connection: str | None = None,
|
||||
last_ip: str = "192.168.1.1",
|
||||
force_status: str | None = None,
|
||||
) -> None:
|
||||
"""
|
||||
Insert a minimal Devices row.
|
||||
@@ -189,16 +191,19 @@ def insert_device(
|
||||
ISO-8601 UTC string; defaults to 60 minutes ago when omitted.
|
||||
last_ip:
|
||||
Value stored in devLastIP.
|
||||
force_status:
|
||||
Value for devForceStatus (``'online'``, ``'offline'``, or ``None``/
|
||||
``'dont_force'``).
|
||||
"""
|
||||
cur.execute(
|
||||
"""
|
||||
INSERT INTO Devices
|
||||
(devMac, devAlertDown, devPresentLastScan, devCanSleep,
|
||||
devLastConnection, devLastIP, devIsArchived, devIsNew)
|
||||
VALUES (?, ?, ?, ?, ?, ?, 0, 0)
|
||||
devLastConnection, devLastIP, devIsArchived, devIsNew, devForceStatus)
|
||||
VALUES (?, ?, ?, ?, ?, ?, 0, 0, ?)
|
||||
""",
|
||||
(mac, alert_down, present_last_scan, can_sleep,
|
||||
last_connection or minutes_ago(60), last_ip),
|
||||
last_connection or minutes_ago(60), last_ip, force_status),
|
||||
)
|
||||
|
||||
|
||||
@@ -347,3 +352,201 @@ class DummyDB:
|
||||
|
||||
def commitDB(self) -> None:
|
||||
self._conn.commit()
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Plugin tables DDL & helpers (used by test/server/test_plugin_history_filtering.py)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
CREATE_PLUGINS_OBJECTS = """
|
||||
CREATE TABLE IF NOT EXISTS Plugins_Objects(
|
||||
"index" INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
plugin TEXT NOT NULL,
|
||||
objectPrimaryId TEXT NOT NULL,
|
||||
objectSecondaryId TEXT NOT NULL,
|
||||
dateTimeCreated TEXT NOT NULL,
|
||||
dateTimeChanged TEXT NOT NULL,
|
||||
watchedValue1 TEXT NOT NULL,
|
||||
watchedValue2 TEXT NOT NULL,
|
||||
watchedValue3 TEXT NOT NULL,
|
||||
watchedValue4 TEXT NOT NULL,
|
||||
"status" TEXT NOT NULL,
|
||||
extra TEXT NOT NULL,
|
||||
userData TEXT NOT NULL,
|
||||
foreignKey TEXT NOT NULL,
|
||||
syncHubNodeName TEXT,
|
||||
helpVal1 TEXT,
|
||||
helpVal2 TEXT,
|
||||
helpVal3 TEXT,
|
||||
helpVal4 TEXT,
|
||||
objectGuid TEXT
|
||||
);
|
||||
"""
|
||||
|
||||
CREATE_PLUGINS_EVENTS = """
|
||||
CREATE TABLE IF NOT EXISTS Plugins_Events(
|
||||
"index" INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
plugin TEXT NOT NULL,
|
||||
objectPrimaryId TEXT NOT NULL,
|
||||
objectSecondaryId TEXT NOT NULL,
|
||||
dateTimeCreated TEXT NOT NULL,
|
||||
dateTimeChanged TEXT NOT NULL,
|
||||
watchedValue1 TEXT NOT NULL,
|
||||
watchedValue2 TEXT NOT NULL,
|
||||
watchedValue3 TEXT NOT NULL,
|
||||
watchedValue4 TEXT NOT NULL,
|
||||
"status" TEXT NOT NULL,
|
||||
extra TEXT NOT NULL,
|
||||
userData TEXT NOT NULL,
|
||||
foreignKey TEXT NOT NULL,
|
||||
syncHubNodeName TEXT,
|
||||
helpVal1 TEXT,
|
||||
helpVal2 TEXT,
|
||||
helpVal3 TEXT,
|
||||
helpVal4 TEXT,
|
||||
objectGuid TEXT
|
||||
);
|
||||
"""
|
||||
|
||||
CREATE_PLUGINS_HISTORY = """
|
||||
CREATE TABLE IF NOT EXISTS Plugins_History(
|
||||
"index" INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
plugin TEXT NOT NULL,
|
||||
objectPrimaryId TEXT NOT NULL,
|
||||
objectSecondaryId TEXT NOT NULL,
|
||||
dateTimeCreated TEXT NOT NULL,
|
||||
dateTimeChanged TEXT NOT NULL,
|
||||
watchedValue1 TEXT NOT NULL,
|
||||
watchedValue2 TEXT NOT NULL,
|
||||
watchedValue3 TEXT NOT NULL,
|
||||
watchedValue4 TEXT NOT NULL,
|
||||
"status" TEXT NOT NULL,
|
||||
extra TEXT NOT NULL,
|
||||
userData TEXT NOT NULL,
|
||||
foreignKey TEXT NOT NULL,
|
||||
syncHubNodeName TEXT,
|
||||
helpVal1 TEXT,
|
||||
helpVal2 TEXT,
|
||||
helpVal3 TEXT,
|
||||
helpVal4 TEXT,
|
||||
objectGuid TEXT
|
||||
);
|
||||
"""
|
||||
|
||||
|
||||
class PluginFakeSQL:
|
||||
"""Wraps a sqlite3.Cursor to provide the interface plugin.py expects."""
|
||||
def __init__(self, cursor):
|
||||
self._cursor = cursor
|
||||
|
||||
def execute(self, sql, params=None):
|
||||
if params:
|
||||
return self._cursor.execute(sql, params)
|
||||
return self._cursor.execute(sql)
|
||||
|
||||
def executemany(self, sql, params_list):
|
||||
return self._cursor.executemany(sql, params_list)
|
||||
|
||||
|
||||
class PluginFakeDB:
|
||||
"""Minimal DB facade expected by process_plugin_events."""
|
||||
def __init__(self, conn):
|
||||
self.sql_connection = conn
|
||||
self.sql = PluginFakeSQL(conn.cursor())
|
||||
|
||||
def get_sql_array(self, query):
|
||||
cur = self.sql_connection.cursor()
|
||||
cur.execute(query)
|
||||
return cur.fetchall()
|
||||
|
||||
def commitDB(self):
|
||||
self.sql_connection.commit()
|
||||
|
||||
|
||||
def make_plugin_db() -> tuple:
|
||||
"""
|
||||
Return a (PluginFakeDB, connection) backed by an in-memory SQLite
|
||||
database with all three plugin tables created.
|
||||
"""
|
||||
conn = sqlite3.connect(":memory:")
|
||||
conn.executescript(
|
||||
CREATE_PLUGINS_OBJECTS + CREATE_PLUGINS_EVENTS + CREATE_PLUGINS_HISTORY
|
||||
)
|
||||
conn.commit()
|
||||
db = PluginFakeDB(conn)
|
||||
return db, conn
|
||||
|
||||
|
||||
def make_plugin_dict(prefix: str, watched_columns=None) -> dict:
|
||||
"""Return a minimal plugin dict compatible with process_plugin_events."""
|
||||
return {
|
||||
"unique_prefix": prefix,
|
||||
"settings": [
|
||||
{
|
||||
"function": "WATCH",
|
||||
"value": watched_columns or ["watchedValue1"],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
def make_plugin_event_row(prefix: str, primary_id: str, secondary_id="sec",
|
||||
watched1="val1", watched2="", watched3="",
|
||||
watched4="", changed="2026-01-01 00:00:00",
|
||||
extra="", user_data="", foreign_key="",
|
||||
status="not-processed"):
|
||||
"""Build a tuple mimicking a raw plugin output row (19 columns + index)."""
|
||||
return (
|
||||
0, # index (placeholder, not used for events)
|
||||
prefix, # plugin
|
||||
primary_id,
|
||||
secondary_id,
|
||||
changed, # dateTimeCreated
|
||||
changed, # dateTimeChanged
|
||||
watched1,
|
||||
watched2,
|
||||
watched3,
|
||||
watched4,
|
||||
status,
|
||||
extra,
|
||||
user_data,
|
||||
foreign_key,
|
||||
None, # syncHubNodeName
|
||||
None, # helpVal1
|
||||
None, # helpVal2
|
||||
None, # helpVal3
|
||||
None, # helpVal4
|
||||
)
|
||||
|
||||
|
||||
def seed_plugin_object(cur, prefix: str, primary_id: str,
|
||||
secondary_id="sec", watched1="val1",
|
||||
status="watched-not-changed",
|
||||
changed="2026-01-01 00:00:00"):
|
||||
"""Insert a row into Plugins_Objects to simulate a pre-existing object."""
|
||||
cur.execute(
|
||||
"""INSERT INTO Plugins_Objects
|
||||
(plugin, objectPrimaryId, objectSecondaryId, dateTimeCreated,
|
||||
dateTimeChanged, watchedValue1, watchedValue2, watchedValue3,
|
||||
watchedValue4, status, extra, userData, foreignKey)
|
||||
VALUES (?, ?, ?, ?, ?, ?, '', '', '', ?, '', '', '')""",
|
||||
(prefix, primary_id, secondary_id, changed, changed, watched1, status),
|
||||
)
|
||||
|
||||
|
||||
def plugin_history_rows(conn, prefix: str):
|
||||
"""Return all Plugins_History rows for a given plugin prefix."""
|
||||
cur = conn.cursor()
|
||||
cur.execute(
|
||||
"SELECT * FROM Plugins_History WHERE plugin = ?", (prefix,)
|
||||
)
|
||||
return cur.fetchall()
|
||||
|
||||
|
||||
def plugin_objects_rows(conn, prefix: str):
|
||||
"""Return all Plugins_Objects rows for a given plugin prefix."""
|
||||
cur = conn.cursor()
|
||||
cur.execute(
|
||||
"SELECT * FROM Plugins_Objects WHERE plugin = ?", (prefix,)
|
||||
)
|
||||
return cur.fetchall()
|
||||
|
||||
414
test/plugins/test_fritzbox.py
Normal file
414
test/plugins/test_fritzbox.py
Normal file
@@ -0,0 +1,414 @@
|
||||
"""
|
||||
Tests for Fritz!Box plugin (fritzbox.py).
|
||||
|
||||
fritzbox.py is imported directly. Its module-level side effects
|
||||
(get_setting_value, Logger, Plugin_Objects) are patched out before the
|
||||
first import so no live config reads, log files, or result files are
|
||||
created during tests.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
from unittest.mock import patch, MagicMock
|
||||
|
||||
from utils.crypto_utils import string_to_fake_mac
|
||||
|
||||
import pytest
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Path setup
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
|
||||
_SERVER = os.path.join(_ROOT, "server")
|
||||
_PLUGIN_DIR = os.path.join(_ROOT, "front", "plugins", "fritzbox")
|
||||
|
||||
for _p in [_ROOT, _SERVER, _PLUGIN_DIR]:
|
||||
if _p not in sys.path:
|
||||
sys.path.insert(0, _p)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Import fritzbox with module-level side effects patched
|
||||
# ---------------------------------------------------------------------------
|
||||
# fritzbox.py calls get_setting_value(), Logger(), and Plugin_Objects() at
|
||||
# module level. Patching these before the first import prevents live config
|
||||
# reads, log-file creation, and result-file creation during tests.
|
||||
|
||||
with patch("helper.get_setting_value", return_value="UTC"), \
|
||||
patch("logger.Logger"), \
|
||||
patch("plugin_helper.Plugin_Objects"):
|
||||
import fritzbox # noqa: E402
|
||||
|
||||
from plugin_helper import normalize_mac # noqa: E402
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Shared helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def _make_host_entry(mac="AA:BB:CC:DD:EE:FF", ip="192.168.1.10",
|
||||
hostname="testdevice", active=1, interface="Ethernet"):
|
||||
return {
|
||||
"NewMACAddress": mac,
|
||||
"NewIPAddress": ip,
|
||||
"NewHostName": hostname,
|
||||
"NewActive": active,
|
||||
"NewInterfaceType": interface,
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_fritz_hosts():
|
||||
"""
|
||||
Patches fritzbox.FritzHosts so that get_connected_devices() uses a
|
||||
controllable mock. Yields the FritzHosts *instance* (what FritzHosts(fc)
|
||||
returns).
|
||||
"""
|
||||
hosts_instance = MagicMock()
|
||||
with patch("fritzbox.FritzHosts", return_value=hosts_instance):
|
||||
yield hosts_instance
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# get_connected_devices
|
||||
# ===========================================================================
|
||||
|
||||
class TestGetConnectedDevices:
|
||||
|
||||
def test_returns_active_device(self, mock_fritz_hosts):
|
||||
mock_fritz_hosts.host_numbers = 1
|
||||
mock_fritz_hosts.get_generic_host_entry.return_value = _make_host_entry(active=1)
|
||||
devices = fritzbox.get_connected_devices(MagicMock(), active_only=True)
|
||||
assert len(devices) == 1
|
||||
assert devices[0]["active_status"] == "Active"
|
||||
|
||||
def test_active_only_filters_inactive_device(self, mock_fritz_hosts):
|
||||
mock_fritz_hosts.host_numbers = 2
|
||||
mock_fritz_hosts.get_generic_host_entry.side_effect = [
|
||||
_make_host_entry(mac="AA:BB:CC:DD:EE:01", active=1),
|
||||
_make_host_entry(mac="AA:BB:CC:DD:EE:02", active=0),
|
||||
]
|
||||
devices = fritzbox.get_connected_devices(MagicMock(), active_only=True)
|
||||
assert len(devices) == 1
|
||||
assert devices[0]["mac_address"] == "aa:bb:cc:dd:ee:01"
|
||||
|
||||
def test_active_only_false_includes_inactive_device(self, mock_fritz_hosts):
|
||||
mock_fritz_hosts.host_numbers = 2
|
||||
mock_fritz_hosts.get_generic_host_entry.side_effect = [
|
||||
_make_host_entry(mac="AA:BB:CC:DD:EE:01", active=1),
|
||||
_make_host_entry(mac="AA:BB:CC:DD:EE:02", active=0),
|
||||
]
|
||||
devices = fritzbox.get_connected_devices(MagicMock(), active_only=False)
|
||||
assert len(devices) == 2
|
||||
assert devices[1]["active_status"] == "Inactive"
|
||||
|
||||
def test_device_without_mac_is_skipped(self, mock_fritz_hosts):
|
||||
mock_fritz_hosts.host_numbers = 2
|
||||
mock_fritz_hosts.get_generic_host_entry.side_effect = [
|
||||
_make_host_entry(mac=""),
|
||||
_make_host_entry(mac="AA:BB:CC:DD:EE:01"),
|
||||
]
|
||||
devices = fritzbox.get_connected_devices(MagicMock(), active_only=False)
|
||||
assert len(devices) == 1
|
||||
assert devices[0]["mac_address"] == "aa:bb:cc:dd:ee:01"
|
||||
|
||||
def test_ethernet_interface_maps_to_lan(self, mock_fritz_hosts):
|
||||
mock_fritz_hosts.host_numbers = 1
|
||||
mock_fritz_hosts.get_generic_host_entry.return_value = _make_host_entry(interface="Ethernet")
|
||||
devices = fritzbox.get_connected_devices(MagicMock(), active_only=False)
|
||||
assert devices[0]["interface_type"] == "LAN"
|
||||
|
||||
def test_wifi_interface_maps_to_wifi(self, mock_fritz_hosts):
|
||||
mock_fritz_hosts.host_numbers = 1
|
||||
mock_fritz_hosts.get_generic_host_entry.return_value = _make_host_entry(interface="802.11")
|
||||
devices = fritzbox.get_connected_devices(MagicMock(), active_only=False)
|
||||
assert devices[0]["interface_type"] == "WiFi"
|
||||
|
||||
def test_unknown_interface_is_preserved(self, mock_fritz_hosts):
|
||||
mock_fritz_hosts.host_numbers = 1
|
||||
mock_fritz_hosts.get_generic_host_entry.return_value = _make_host_entry(interface="SomeOtherType")
|
||||
devices = fritzbox.get_connected_devices(MagicMock(), active_only=False)
|
||||
assert devices[0]["interface_type"] == "SomeOtherType"
|
||||
|
||||
def test_mac_address_is_normalized_to_lowercase(self, mock_fritz_hosts):
|
||||
mock_fritz_hosts.host_numbers = 1
|
||||
mock_fritz_hosts.get_generic_host_entry.return_value = _make_host_entry(mac="AA:BB:CC:DD:EE:FF")
|
||||
devices = fritzbox.get_connected_devices(MagicMock(), active_only=False)
|
||||
assert devices[0]["mac_address"] == "aa:bb:cc:dd:ee:ff"
|
||||
|
||||
def test_missing_hostname_defaults_to_unknown(self, mock_fritz_hosts):
|
||||
mock_fritz_hosts.host_numbers = 1
|
||||
mock_fritz_hosts.get_generic_host_entry.return_value = _make_host_entry(hostname="")
|
||||
devices = fritzbox.get_connected_devices(MagicMock(), active_only=False)
|
||||
assert devices[0]["hostname"] == "Unknown"
|
||||
|
||||
def test_failed_host_entry_does_not_abort_remaining(self, mock_fritz_hosts):
|
||||
mock_fritz_hosts.host_numbers = 3
|
||||
mock_fritz_hosts.get_generic_host_entry.side_effect = [
|
||||
_make_host_entry(mac="AA:BB:CC:DD:EE:01"),
|
||||
Exception("TR-064 timeout"),
|
||||
_make_host_entry(mac="AA:BB:CC:DD:EE:03"),
|
||||
]
|
||||
devices = fritzbox.get_connected_devices(MagicMock(), active_only=False)
|
||||
assert len(devices) == 2
|
||||
|
||||
def test_empty_host_list_returns_empty(self, mock_fritz_hosts):
|
||||
mock_fritz_hosts.host_numbers = 0
|
||||
devices = fritzbox.get_connected_devices(MagicMock(), active_only=False)
|
||||
assert devices == []
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# check_guest_wifi_status
|
||||
# ===========================================================================
|
||||
|
||||
class TestCheckGuestWifiStatus:
|
||||
|
||||
def test_disabled_service_returns_inactive(self):
|
||||
fc = MagicMock()
|
||||
fc.call_action.return_value = {"NewEnable": False, "NewSSID": ""}
|
||||
result = fritzbox.check_guest_wifi_status(fc, guest_service_num=3)
|
||||
assert result["active"] is False
|
||||
|
||||
def test_enabled_service_returns_active(self):
|
||||
fc = MagicMock()
|
||||
fc.call_action.return_value = {"NewEnable": True, "NewSSID": "MyGuestWiFi"}
|
||||
result = fritzbox.check_guest_wifi_status(fc, guest_service_num=3)
|
||||
assert result["active"] is True
|
||||
assert result["ssid"] == "MyGuestWiFi"
|
||||
|
||||
def test_queries_correct_service_number(self):
|
||||
fc = MagicMock()
|
||||
fc.call_action.return_value = {"NewEnable": True, "NewSSID": "Guest"}
|
||||
fritzbox.check_guest_wifi_status(fc, guest_service_num=2)
|
||||
fc.call_action.assert_called_once_with("WLANConfiguration2", "GetInfo")
|
||||
|
||||
def test_service_exception_returns_inactive(self):
|
||||
fc = MagicMock()
|
||||
fc.call_action.side_effect = Exception("Service unavailable")
|
||||
result = fritzbox.check_guest_wifi_status(fc, guest_service_num=3)
|
||||
assert result["active"] is False
|
||||
|
||||
def test_empty_ssid_uses_default_label(self):
|
||||
fc = MagicMock()
|
||||
fc.call_action.return_value = {"NewEnable": True, "NewSSID": ""}
|
||||
result = fritzbox.check_guest_wifi_status(fc, guest_service_num=3)
|
||||
assert result["active"] is True
|
||||
assert result["ssid"] == "Guest WiFi"
|
||||
|
||||
def test_service1_can_be_guest(self):
|
||||
fc = MagicMock()
|
||||
fc.call_action.return_value = {"NewEnable": True, "NewSSID": "Gast"}
|
||||
result = fritzbox.check_guest_wifi_status(fc, guest_service_num=1)
|
||||
assert result["active"] is True
|
||||
fc.call_action.assert_called_once_with("WLANConfiguration1", "GetInfo")
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# create_guest_wifi_device
|
||||
# ===========================================================================
|
||||
|
||||
class TestCreateGuestWifiDevice:
|
||||
|
||||
def _fc_with_mac(self, mac):
|
||||
fc = MagicMock()
|
||||
fc.call_action.return_value = {"NewMACAddress": mac}
|
||||
return fc
|
||||
|
||||
def test_returns_device_dict(self):
|
||||
device = fritzbox.create_guest_wifi_device(self._fc_with_mac("AA:BB:CC:DD:EE:FF"))
|
||||
assert device is not None
|
||||
assert "mac_address" in device
|
||||
assert device["hostname"] == "Guest WiFi Network"
|
||||
assert device["active_status"] == "Active"
|
||||
assert device["interface_type"] == "Access Point"
|
||||
assert device["ip_address"] == ""
|
||||
# MAC must match string_to_fake_mac output (fa:ce: prefix)
|
||||
assert device["mac_address"].startswith("fa:ce:")
|
||||
|
||||
def test_guest_mac_has_locally_administered_bit(self):
|
||||
"""The locally-administered bit (0x02) must be set in the first byte.
|
||||
string_to_fake_mac uses the 'fa:ce:' prefix; 0xFA & 0x02 == 0x02."""
|
||||
device = fritzbox.create_guest_wifi_device(self._fc_with_mac("AA:BB:CC:DD:EE:FF"))
|
||||
first_byte = int(device["mac_address"].split(":")[0], 16)
|
||||
assert first_byte & 0x02 != 0
|
||||
|
||||
def test_guest_mac_format_is_valid(self):
|
||||
"""MAC must be 6 colon-separated lowercase hex pairs."""
|
||||
device = fritzbox.create_guest_wifi_device(self._fc_with_mac("AA:BB:CC:DD:EE:FF"))
|
||||
parts = device["mac_address"].split(":")
|
||||
assert len(parts) == 6
|
||||
for part in parts:
|
||||
assert len(part) == 2
|
||||
int(part, 16) # raises ValueError if not valid hex
|
||||
|
||||
def test_guest_mac_is_deterministic(self):
|
||||
"""Same Fritz!Box MAC must always produce the same guest MAC."""
|
||||
fc = self._fc_with_mac("AA:BB:CC:DD:EE:FF")
|
||||
mac1 = fritzbox.create_guest_wifi_device(fc)["mac_address"]
|
||||
mac2 = fritzbox.create_guest_wifi_device(fc)["mac_address"]
|
||||
assert mac1 == mac2
|
||||
|
||||
def test_different_fritzbox_macs_produce_different_guest_macs(self):
|
||||
mac_a = fritzbox.create_guest_wifi_device(self._fc_with_mac("AA:BB:CC:DD:EE:01"))["mac_address"]
|
||||
mac_b = fritzbox.create_guest_wifi_device(self._fc_with_mac("AA:BB:CC:DD:EE:02"))["mac_address"]
|
||||
assert mac_a != mac_b
|
||||
|
||||
def test_no_fritzbox_mac_uses_fallback(self):
|
||||
"""When DeviceInfo returns no MAC, fall back to a sentinel-derived MAC."""
|
||||
fc = MagicMock()
|
||||
fc.call_action.return_value = {"NewMACAddress": ""}
|
||||
device = fritzbox.create_guest_wifi_device(fc)
|
||||
assert device["mac_address"] == string_to_fake_mac("FRITZBOX_GUEST")
|
||||
|
||||
def test_device_info_exception_returns_none(self):
|
||||
"""If DeviceInfo call raises, create_guest_wifi_device must return None."""
|
||||
fc = MagicMock()
|
||||
fc.call_action.side_effect = Exception("Connection refused")
|
||||
device = fritzbox.create_guest_wifi_device(fc)
|
||||
assert device is None
|
||||
|
||||
def test_known_mac_produces_known_guest_mac(self):
|
||||
"""
|
||||
Regression anchor: for a fixed Fritz!Box MAC, the expected guest MAC
|
||||
is derived via string_to_fake_mac(normalize_mac(...)). If the hashing
|
||||
logic in fritzbox.py or string_to_fake_mac changes, this test fails.
|
||||
"""
|
||||
fritzbox_mac = normalize_mac("AA:BB:CC:DD:EE:FF")
|
||||
expected = string_to_fake_mac(fritzbox_mac)
|
||||
|
||||
device = fritzbox.create_guest_wifi_device(self._fc_with_mac("AA:BB:CC:DD:EE:FF"))
|
||||
assert device["mac_address"] == expected
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# get_fritzbox_connection
|
||||
# ===========================================================================
|
||||
|
||||
class TestGetFritzboxConnection:
|
||||
|
||||
def test_successful_connection(self):
|
||||
fc_instance = MagicMock()
|
||||
fc_instance.modelname = "FRITZ!Box 7590"
|
||||
fc_instance.system_version = "7.57"
|
||||
fc_class = MagicMock(return_value=fc_instance)
|
||||
|
||||
with patch("fritzbox.FritzConnection", fc_class):
|
||||
result = fritzbox.get_fritzbox_connection("fritz.box", 49443, "admin", "pass", True)
|
||||
|
||||
assert result is fc_instance
|
||||
fc_class.assert_called_once_with(
|
||||
address="fritz.box", port=49443, user="admin", password="pass", use_tls=True, timeout=10,
|
||||
)
|
||||
|
||||
def test_import_error_returns_none(self):
|
||||
with patch("fritzbox.FritzConnection", side_effect=ImportError("fritzconnection not found")):
|
||||
result = fritzbox.get_fritzbox_connection("fritz.box", 49443, "admin", "pass", True)
|
||||
|
||||
assert result is None
|
||||
|
||||
def test_connection_exception_returns_none(self):
|
||||
with patch("fritzbox.FritzConnection", side_effect=Exception("Connection refused")):
|
||||
result = fritzbox.get_fritzbox_connection("fritz.box", 49443, "admin", "pass", True)
|
||||
|
||||
assert result is None
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# main
|
||||
# ===========================================================================
|
||||
|
||||
class TestMain:
|
||||
|
||||
_SETTINGS = {
|
||||
"FRITZBOX_HOST": "fritz.box",
|
||||
"FRITZBOX_PORT": 49443,
|
||||
"FRITZBOX_USER": "admin",
|
||||
"FRITZBOX_PASS": "secret",
|
||||
"FRITZBOX_USE_TLS": True,
|
||||
"FRITZBOX_REPORT_GUEST": False,
|
||||
"FRITZBOX_GUEST_SERVICE": 3,
|
||||
"FRITZBOX_ACTIVE_ONLY": True,
|
||||
}
|
||||
|
||||
def _patch_settings(self):
|
||||
return patch.object(
|
||||
fritzbox, "get_setting_value",
|
||||
side_effect=lambda key: self._SETTINGS[key],
|
||||
)
|
||||
|
||||
def test_connection_failure_returns_1(self):
|
||||
mock_po = MagicMock()
|
||||
with self._patch_settings(), \
|
||||
patch.object(fritzbox, "get_fritzbox_connection", return_value=None), \
|
||||
patch.object(fritzbox, "plugin_objects", mock_po):
|
||||
result = fritzbox.main()
|
||||
|
||||
assert result == 1
|
||||
mock_po.write_result_file.assert_called_once()
|
||||
mock_po.add_object.assert_not_called()
|
||||
|
||||
def test_scan_processes_devices(self):
|
||||
devices = [
|
||||
{"mac_address": "aa:bb:cc:dd:ee:01", "ip_address": "192.168.1.10",
|
||||
"hostname": "device1", "active_status": "Active", "interface_type": "LAN"},
|
||||
{"mac_address": "aa:bb:cc:dd:ee:02", "ip_address": "192.168.1.11",
|
||||
"hostname": "device2", "active_status": "Active", "interface_type": "WiFi"},
|
||||
]
|
||||
mock_po = MagicMock()
|
||||
|
||||
with self._patch_settings(), \
|
||||
patch.object(fritzbox, "get_fritzbox_connection", return_value=MagicMock()), \
|
||||
patch.object(fritzbox, "get_connected_devices", return_value=devices), \
|
||||
patch.object(fritzbox, "plugin_objects", mock_po):
|
||||
result = fritzbox.main()
|
||||
|
||||
assert result == 0
|
||||
assert mock_po.add_object.call_count == 2
|
||||
mock_po.write_result_file.assert_called_once()
|
||||
|
||||
def test_guest_wifi_device_appended_when_active(self):
|
||||
devices = [
|
||||
{"mac_address": "aa:bb:cc:dd:ee:01", "ip_address": "192.168.1.10",
|
||||
"hostname": "device1", "active_status": "Active", "interface_type": "LAN"},
|
||||
]
|
||||
guest_device = {
|
||||
"mac_address": "02:a1:b2:c3:d4:e5", "ip_address": "",
|
||||
"hostname": "Guest WiFi Network", "active_status": "Active",
|
||||
"interface_type": "Access Point",
|
||||
}
|
||||
settings = {**self._SETTINGS, "FRITZBOX_REPORT_GUEST": True}
|
||||
mock_po = MagicMock()
|
||||
|
||||
with patch.object(fritzbox, "get_setting_value", side_effect=lambda k: settings[k]), \
|
||||
patch.object(fritzbox, "get_fritzbox_connection", return_value=MagicMock()), \
|
||||
patch.object(fritzbox, "get_connected_devices", return_value=devices), \
|
||||
patch.object(fritzbox, "check_guest_wifi_status", return_value={"active": True, "ssid": "Guest"}), \
|
||||
patch.object(fritzbox, "create_guest_wifi_device", return_value=guest_device), \
|
||||
patch.object(fritzbox, "plugin_objects", mock_po):
|
||||
result = fritzbox.main()
|
||||
|
||||
assert result == 0
|
||||
assert mock_po.add_object.call_count == 2 # 1 device + 1 guest
|
||||
# Verify the guest device was passed correctly
|
||||
guest_call = mock_po.add_object.call_args_list[1]
|
||||
assert guest_call.kwargs["primaryId"] == "02:a1:b2:c3:d4:e5"
|
||||
assert guest_call.kwargs["watched3"] == "Access Point"
|
||||
|
||||
def test_guest_wifi_not_appended_when_inactive(self):
|
||||
devices = [
|
||||
{"mac_address": "aa:bb:cc:dd:ee:01", "ip_address": "192.168.1.10",
|
||||
"hostname": "device1", "active_status": "Active", "interface_type": "LAN"},
|
||||
]
|
||||
settings = {**self._SETTINGS, "FRITZBOX_REPORT_GUEST": True}
|
||||
mock_po = MagicMock()
|
||||
|
||||
with patch.object(fritzbox, "get_setting_value", side_effect=lambda k: settings[k]), \
|
||||
patch.object(fritzbox, "get_fritzbox_connection", return_value=MagicMock()), \
|
||||
patch.object(fritzbox, "get_connected_devices", return_value=devices), \
|
||||
patch.object(fritzbox, "check_guest_wifi_status", return_value={"active": False, "ssid": ""}), \
|
||||
patch.object(fritzbox, "plugin_objects", mock_po):
|
||||
result = fritzbox.main()
|
||||
|
||||
assert result == 0
|
||||
assert mock_po.add_object.call_count == 1 # only the real device
|
||||
@@ -444,3 +444,122 @@ class TestDownCountSleepingSuppression:
|
||||
assert count == 1, (
|
||||
f"Expected 1 down device (sleeping device must not be counted), got {count}"
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Layer 1c: insert_events() — forced-online device suppression
|
||||
#
|
||||
# Devices with devForceStatus='online' are always considered present by the
|
||||
# operator. Generating 'Device Down' or 'Disconnected' events for them causes
|
||||
# spurious flapping detection (devFlapping counts these events in DevicesView).
|
||||
#
|
||||
# Affected queries in insert_events():
|
||||
# 1a Device Down (non-sleeping) — DevicesView query
|
||||
# 1b Device Down (sleep-expired) — DevicesView query
|
||||
# 3 Disconnected — Devices table query
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class TestInsertEventsForceOnline:
|
||||
"""
|
||||
Regression tests: forced-online devices must never generate
|
||||
'Device Down' or 'Disconnected' events.
|
||||
"""
|
||||
|
||||
def test_forced_online_no_device_down_event(self):
|
||||
"""
|
||||
devForceStatus='online', devAlertDown=1, absent from CurrentScan.
|
||||
Must NOT produce a 'Device Down' event (regression: used to fire and
|
||||
cause devFlapping=1 after the threshold was reached).
|
||||
"""
|
||||
conn = _make_db()
|
||||
cur = conn.cursor()
|
||||
_insert_device(cur, "ff:00:00:00:00:01", alert_down=1, present_last_scan=1,
|
||||
force_status="online")
|
||||
conn.commit()
|
||||
|
||||
insert_events(DummyDB(conn))
|
||||
|
||||
assert "ff:00:00:00:00:01" not in _down_event_macs(cur), (
|
||||
"forced-online device must never generate a 'Device Down' event"
|
||||
)
|
||||
|
||||
def test_forced_online_sleep_expired_no_device_down_event(self):
|
||||
"""
|
||||
devForceStatus='online', devCanSleep=1, sleep window expired.
|
||||
Must NOT produce a 'Device Down' event via the sleep-expired path.
|
||||
"""
|
||||
conn = _make_db(sleep_minutes=30)
|
||||
cur = conn.cursor()
|
||||
_insert_device(cur, "ff:00:00:00:00:02", alert_down=1, present_last_scan=0,
|
||||
can_sleep=1, last_connection=_minutes_ago(45),
|
||||
force_status="online")
|
||||
conn.commit()
|
||||
|
||||
insert_events(DummyDB(conn))
|
||||
|
||||
assert "ff:00:00:00:00:02" not in _down_event_macs(cur), (
|
||||
"forced-online sleeping device must not get 'Device Down' after sleep expires"
|
||||
)
|
||||
|
||||
def test_forced_online_no_disconnected_event(self):
|
||||
"""
|
||||
devForceStatus='online', devAlertDown=0 (Disconnected path), absent.
|
||||
Must NOT produce a 'Disconnected' event.
|
||||
"""
|
||||
conn = _make_db()
|
||||
cur = conn.cursor()
|
||||
_insert_device(cur, "ff:00:00:00:00:03", alert_down=0, present_last_scan=1,
|
||||
force_status="online")
|
||||
conn.commit()
|
||||
|
||||
insert_events(DummyDB(conn))
|
||||
|
||||
cur.execute(
|
||||
"SELECT COUNT(*) AS cnt FROM Events "
|
||||
"WHERE eveMac = 'ff:00:00:00:00:03' AND eveEventType = 'Disconnected'"
|
||||
)
|
||||
assert cur.fetchone()["cnt"] == 0, (
|
||||
"forced-online device must never generate a 'Disconnected' event"
|
||||
)
|
||||
|
||||
def test_forced_online_uppercase_no_device_down_event(self):
|
||||
"""devForceStatus='ONLINE' (uppercase) must also be suppressed."""
|
||||
conn = _make_db()
|
||||
cur = conn.cursor()
|
||||
_insert_device(cur, "ff:00:00:00:00:04", alert_down=1, present_last_scan=1,
|
||||
force_status="ONLINE")
|
||||
conn.commit()
|
||||
|
||||
insert_events(DummyDB(conn))
|
||||
|
||||
assert "ff:00:00:00:00:04" not in _down_event_macs(cur), (
|
||||
"forced-online device (uppercase) must never generate a 'Device Down' event"
|
||||
)
|
||||
|
||||
def test_dont_force_still_fires_device_down(self):
|
||||
"""devForceStatus='dont_force' must behave normally — event fires."""
|
||||
conn = _make_db()
|
||||
cur = conn.cursor()
|
||||
_insert_device(cur, "ff:00:00:00:00:05", alert_down=1, present_last_scan=1,
|
||||
force_status="dont_force")
|
||||
conn.commit()
|
||||
|
||||
insert_events(DummyDB(conn))
|
||||
|
||||
assert "ff:00:00:00:00:05" in _down_event_macs(cur), (
|
||||
"dont_force device must still generate 'Device Down' when absent"
|
||||
)
|
||||
|
||||
def test_forced_offline_still_fires_device_down(self):
|
||||
"""devForceStatus='offline' suppresses nothing — event fires."""
|
||||
conn = _make_db()
|
||||
cur = conn.cursor()
|
||||
_insert_device(cur, "ff:00:00:00:00:06", alert_down=1, present_last_scan=1,
|
||||
force_status="offline")
|
||||
conn.commit()
|
||||
|
||||
insert_events(DummyDB(conn))
|
||||
|
||||
assert "ff:00:00:00:00:06" in _down_event_macs(cur), (
|
||||
"forced-offline device must still generate 'Device Down' when absent"
|
||||
)
|
||||
|
||||
90
test/scan/test_sync_hub_node_backfill.py
Normal file
90
test/scan/test_sync_hub_node_backfill.py
Normal file
@@ -0,0 +1,90 @@
|
||||
"""Tests for update_sync_hub_node backfill."""
|
||||
|
||||
import sys
|
||||
import os
|
||||
from unittest.mock import patch
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
|
||||
from db_test_helpers import make_db, DummyDB # noqa: E402
|
||||
|
||||
from server.scan import device_handling
|
||||
|
||||
|
||||
def _make_db(devices):
|
||||
"""Create an in-memory DB with full schema and seed rows."""
|
||||
conn = make_db()
|
||||
cur = conn.cursor()
|
||||
cur.executemany(
|
||||
"INSERT INTO Devices (devMac, devSyncHubNode) VALUES (?, ?)",
|
||||
devices,
|
||||
)
|
||||
conn.commit()
|
||||
return conn
|
||||
|
||||
|
||||
def _read_nodes(conn):
|
||||
"""Return a dict of devMac -> devSyncHubNode."""
|
||||
return {
|
||||
row["devMac"]: row["devSyncHubNode"]
|
||||
for row in conn.execute("SELECT devMac, devSyncHubNode FROM Devices")
|
||||
}
|
||||
|
||||
|
||||
@patch.object(device_handling, "get_setting_value", return_value="MyNode")
|
||||
def test_backfill_empty_values(mock_setting):
|
||||
"""Empty and null devSyncHubNode should be backfilled with SYNC_node_name."""
|
||||
conn = _make_db([
|
||||
("AA:AA:AA:AA:AA:01", ""),
|
||||
("AA:AA:AA:AA:AA:02", None),
|
||||
("AA:AA:AA:AA:AA:03", "null"),
|
||||
])
|
||||
|
||||
device_handling.update_sync_hub_node(DummyDB(conn))
|
||||
nodes = _read_nodes(conn)
|
||||
|
||||
assert nodes["AA:AA:AA:AA:AA:01"] == "MyNode"
|
||||
assert nodes["AA:AA:AA:AA:AA:02"] == "MyNode"
|
||||
assert nodes["AA:AA:AA:AA:AA:03"] == "MyNode"
|
||||
|
||||
|
||||
@patch.object(device_handling, "get_setting_value", return_value="MyNode")
|
||||
def test_no_overwrite_existing(mock_setting):
|
||||
"""Devices with a real devSyncHubNode should not be overwritten."""
|
||||
conn = _make_db([
|
||||
("AA:AA:AA:AA:AA:01", "RemoteNode"),
|
||||
("AA:AA:AA:AA:AA:02", ""),
|
||||
])
|
||||
|
||||
device_handling.update_sync_hub_node(DummyDB(conn))
|
||||
nodes = _read_nodes(conn)
|
||||
|
||||
assert nodes["AA:AA:AA:AA:AA:01"] == "RemoteNode"
|
||||
assert nodes["AA:AA:AA:AA:AA:02"] == "MyNode"
|
||||
|
||||
|
||||
@patch.object(device_handling, "get_setting_value", return_value="")
|
||||
def test_noop_when_setting_empty(mock_setting):
|
||||
"""No updates when SYNC_node_name is empty."""
|
||||
conn = _make_db([
|
||||
("AA:AA:AA:AA:AA:01", ""),
|
||||
("AA:AA:AA:AA:AA:02", None),
|
||||
])
|
||||
|
||||
device_handling.update_sync_hub_node(DummyDB(conn))
|
||||
nodes = _read_nodes(conn)
|
||||
|
||||
assert nodes["AA:AA:AA:AA:AA:01"] == ""
|
||||
assert nodes["AA:AA:AA:AA:AA:02"] is None
|
||||
|
||||
|
||||
@patch.object(device_handling, "get_setting_value", return_value=None)
|
||||
def test_noop_when_setting_none(mock_setting):
|
||||
"""No updates when SYNC_node_name is None."""
|
||||
conn = _make_db([
|
||||
("AA:AA:AA:AA:AA:01", ""),
|
||||
])
|
||||
|
||||
device_handling.update_sync_hub_node(DummyDB(conn))
|
||||
nodes = _read_nodes(conn)
|
||||
|
||||
assert nodes["AA:AA:AA:AA:AA:01"] == ""
|
||||
236
test/server/test_plugin_history_filtering.py
Normal file
236
test/server/test_plugin_history_filtering.py
Normal file
@@ -0,0 +1,236 @@
|
||||
"""
|
||||
Tests for the Plugins_History selective recording introduced to prevent
|
||||
unbounded table growth.
|
||||
|
||||
Verifies that process_plugin_events() only writes history rows for objects
|
||||
whose state actually changed in the current cycle:
|
||||
- new objects
|
||||
- watched-changed objects
|
||||
- missing-in-last-scan (first transition only)
|
||||
|
||||
Objects that are watched-not-changed or already missing should NOT generate
|
||||
history entries.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
import pytest
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Path setup
|
||||
# ---------------------------------------------------------------------------
|
||||
INSTALL_PATH = os.getenv("NETALERTX_APP", "/app")
|
||||
sys.path.extend([f"{INSTALL_PATH}/front/plugins", f"{INSTALL_PATH}/server"])
|
||||
|
||||
# Test helpers (shared DDL, fake DB, factories)
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
|
||||
from db_test_helpers import ( # noqa: E402
|
||||
make_plugin_db,
|
||||
make_plugin_dict,
|
||||
make_plugin_event_row,
|
||||
seed_plugin_object,
|
||||
plugin_history_rows,
|
||||
plugin_objects_rows,
|
||||
)
|
||||
|
||||
from plugin import process_plugin_events # noqa: E402
|
||||
|
||||
PREFIX = "TESTPLG"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Fixtures
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@pytest.fixture
|
||||
def plugin_db():
|
||||
"""Yield a (PluginFakeDB, connection) backed by an in-memory SQLite database."""
|
||||
db, conn = make_plugin_db()
|
||||
yield db, conn
|
||||
conn.close()
|
||||
|
||||
|
||||
def _no_report_on(key):
|
||||
"""Monkeypatch target: return empty REPORT_ON so no events are generated."""
|
||||
return [] if key.endswith("_REPORT_ON") else ""
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Tests
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class TestHistoryOnlyRecordsChanges:
|
||||
"""Core assertion: unchanged objects must NOT appear in Plugins_History."""
|
||||
|
||||
def test_new_object_recorded_in_history(self, plugin_db, monkeypatch):
|
||||
"""A brand-new object should produce exactly one history row."""
|
||||
db, conn = plugin_db
|
||||
monkeypatch.setattr("plugin.get_setting_value", _no_report_on)
|
||||
|
||||
plugin = make_plugin_dict(PREFIX)
|
||||
events = [make_plugin_event_row(PREFIX, "device_A")]
|
||||
|
||||
process_plugin_events(db, plugin, events)
|
||||
|
||||
rows = plugin_history_rows(conn, PREFIX)
|
||||
assert len(rows) == 1
|
||||
assert rows[0][2] == "device_A" # objectPrimaryId
|
||||
|
||||
def test_unchanged_object_not_recorded(self, plugin_db, monkeypatch):
|
||||
"""An object with watched-not-changed should NOT appear in history."""
|
||||
db, conn = plugin_db
|
||||
monkeypatch.setattr("plugin.get_setting_value", _no_report_on)
|
||||
|
||||
cur = conn.cursor()
|
||||
seed_plugin_object(cur, PREFIX, "device_A", watched1="val1",
|
||||
status="watched-not-changed")
|
||||
conn.commit()
|
||||
|
||||
plugin = make_plugin_dict(PREFIX)
|
||||
events = [make_plugin_event_row(PREFIX, "device_A", watched1="val1")]
|
||||
|
||||
process_plugin_events(db, plugin, events)
|
||||
|
||||
rows = plugin_history_rows(conn, PREFIX)
|
||||
assert len(rows) == 0, (
|
||||
"watched-not-changed objects should not generate history rows"
|
||||
)
|
||||
|
||||
def test_watched_changed_recorded(self, plugin_db, monkeypatch):
|
||||
"""An object whose watched column changed should appear in history."""
|
||||
db, conn = plugin_db
|
||||
monkeypatch.setattr("plugin.get_setting_value", _no_report_on)
|
||||
|
||||
cur = conn.cursor()
|
||||
seed_plugin_object(cur, PREFIX, "device_A", watched1="old_value",
|
||||
status="watched-not-changed")
|
||||
conn.commit()
|
||||
|
||||
plugin = make_plugin_dict(PREFIX)
|
||||
events = [make_plugin_event_row(PREFIX, "device_A", watched1="new_value")]
|
||||
|
||||
process_plugin_events(db, plugin, events)
|
||||
|
||||
rows = plugin_history_rows(conn, PREFIX)
|
||||
assert len(rows) == 1
|
||||
assert rows[0][2] == "device_A"
|
||||
|
||||
def test_missing_first_time_recorded(self, plugin_db, monkeypatch):
|
||||
"""An object going missing for the first time should appear in history."""
|
||||
db, conn = plugin_db
|
||||
monkeypatch.setattr("plugin.get_setting_value", _no_report_on)
|
||||
|
||||
cur = conn.cursor()
|
||||
seed_plugin_object(cur, PREFIX, "device_A", status="watched-not-changed")
|
||||
conn.commit()
|
||||
|
||||
plugin = make_plugin_dict(PREFIX)
|
||||
events = [] # No events reported — device_A is now missing
|
||||
|
||||
process_plugin_events(db, plugin, events)
|
||||
|
||||
rows = plugin_history_rows(conn, PREFIX)
|
||||
assert len(rows) == 1
|
||||
assert rows[0][2] == "device_A"
|
||||
|
||||
def test_already_missing_not_re_recorded(self, plugin_db, monkeypatch):
|
||||
"""An object already marked missing-in-last-scan should NOT produce
|
||||
another history row on subsequent runs."""
|
||||
db, conn = plugin_db
|
||||
monkeypatch.setattr("plugin.get_setting_value", _no_report_on)
|
||||
|
||||
cur = conn.cursor()
|
||||
seed_plugin_object(cur, PREFIX, "device_A",
|
||||
status="missing-in-last-scan")
|
||||
conn.commit()
|
||||
|
||||
plugin = make_plugin_dict(PREFIX)
|
||||
events = [] # still missing
|
||||
|
||||
process_plugin_events(db, plugin, events)
|
||||
|
||||
rows = plugin_history_rows(conn, PREFIX)
|
||||
assert len(rows) == 0, (
|
||||
"already-missing objects should not generate additional history rows"
|
||||
)
|
||||
|
||||
def test_mixed_scenario(self, plugin_db, monkeypatch):
|
||||
"""Simulate a realistic mixed run: new + unchanged + changed + missing."""
|
||||
db, conn = plugin_db
|
||||
monkeypatch.setattr("plugin.get_setting_value", _no_report_on)
|
||||
|
||||
cur = conn.cursor()
|
||||
seed_plugin_object(cur, PREFIX, "unchanged", watched1="same",
|
||||
status="watched-not-changed")
|
||||
seed_plugin_object(cur, PREFIX, "will_change", watched1="old",
|
||||
status="watched-not-changed")
|
||||
seed_plugin_object(cur, PREFIX, "will_vanish",
|
||||
status="watched-not-changed")
|
||||
seed_plugin_object(cur, PREFIX, "already_gone",
|
||||
status="missing-in-last-scan")
|
||||
conn.commit()
|
||||
|
||||
plugin = make_plugin_dict(PREFIX)
|
||||
events = [
|
||||
make_plugin_event_row(PREFIX, "brand_new"), # new
|
||||
make_plugin_event_row(PREFIX, "unchanged", watched1="same"), # no change
|
||||
make_plugin_event_row(PREFIX, "will_change", watched1="new"), # changed
|
||||
# will_vanish not reported → first-time missing
|
||||
# already_gone not reported → still missing (no history)
|
||||
]
|
||||
|
||||
process_plugin_events(db, plugin, events)
|
||||
|
||||
rows = plugin_history_rows(conn, PREFIX)
|
||||
recorded_ids = {r[2] for r in rows} # objectPrimaryId
|
||||
|
||||
assert "brand_new" in recorded_ids, "new object should be in history"
|
||||
assert "will_change" in recorded_ids, "changed object should be in history"
|
||||
assert "will_vanish" in recorded_ids, "first-time missing should be in history"
|
||||
assert "unchanged" not in recorded_ids, "unchanged should NOT be in history"
|
||||
assert "already_gone" not in recorded_ids, "already-missing should NOT be in history"
|
||||
assert len(rows) == 3
|
||||
|
||||
def test_objects_table_still_updated_for_unchanged(self, plugin_db, monkeypatch):
|
||||
"""Even though history is skipped, Plugins_Objects must still be updated
|
||||
for unchanged objects (no regression)."""
|
||||
db, conn = plugin_db
|
||||
monkeypatch.setattr("plugin.get_setting_value", _no_report_on)
|
||||
|
||||
cur = conn.cursor()
|
||||
seed_plugin_object(cur, PREFIX, "device_A", watched1="val1",
|
||||
status="watched-not-changed")
|
||||
conn.commit()
|
||||
|
||||
plugin = make_plugin_dict(PREFIX)
|
||||
events = [make_plugin_event_row(PREFIX, "device_A", watched1="val1")]
|
||||
|
||||
process_plugin_events(db, plugin, events)
|
||||
|
||||
objs = plugin_objects_rows(conn, PREFIX)
|
||||
assert len(objs) == 1, "Plugins_Objects should still have the object"
|
||||
|
||||
def test_recovery_from_missing_recorded(self, plugin_db, monkeypatch):
|
||||
"""An object that was missing-in-last-scan and reappears (even with
|
||||
unchanged watched values) should produce a history row."""
|
||||
db, conn = plugin_db
|
||||
monkeypatch.setattr("plugin.get_setting_value", _no_report_on)
|
||||
|
||||
cur = conn.cursor()
|
||||
seed_plugin_object(cur, PREFIX, "device_A", watched1="val1",
|
||||
status="missing-in-last-scan")
|
||||
conn.commit()
|
||||
|
||||
plugin = make_plugin_dict(PREFIX)
|
||||
# device_A reappears with the same watched value
|
||||
events = [make_plugin_event_row(PREFIX, "device_A", watched1="val1")]
|
||||
|
||||
process_plugin_events(db, plugin, events)
|
||||
|
||||
rows = plugin_history_rows(conn, PREFIX)
|
||||
assert len(rows) == 1, (
|
||||
"recovery from missing-in-last-scan should generate a history row"
|
||||
)
|
||||
assert rows[0][2] == "device_A"
|
||||
Reference in New Issue
Block a user