Compare commits

..

140 Commits

Author SHA1 Message Date
jokob-sk
15a7779d6e Sanitize input #805
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-26 08:08:24 +10:00
jokob-sk
2784f2ebeb Sanitize input #807 2024-09-26 07:32:04 +10:00
jokob-sk
d46046beea Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-09-26 07:22:02 +10:00
jokob-sk
6233f4d646 Sanitize input #805 2024-09-26 07:21:58 +10:00
github-actions[bot]
31411e0a14 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-25 11:53:41 +00:00
Hosted Weblate
8d824af3bd Merge branch 'origin/main' into Weblate.
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-24 23:50:28 +02:00
gallegonovato
f05f0d625a Translated using Weblate (Spanish)
Currently translated at 100.0% (698 of 698 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/es/
2024-09-24 23:50:28 +02:00
jokob-sk
2fec3b6607 📚Docs 2024-09-25 07:50:13 +10:00
jokob-sk
f285a28887 Cleanup 2024-09-25 07:25:31 +10:00
github-actions[bot]
11cb47fada [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-24 11:53:56 +00:00
Anonymous
d8b413b5e7 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 96.7% (675 of 698 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/zh_Hans/
2024-09-24 13:48:15 +02:00
Anonymous
656bba7ff7 Translated using Weblate (Polish)
Currently translated at 97.4% (680 of 698 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/pl/
2024-09-24 13:48:15 +02:00
Anonymous
a2cf8c1167 Translated using Weblate (Portuguese (Brazil))
Currently translated at 34.8% (243 of 698 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/pt_BR/
2024-09-24 13:48:15 +02:00
Anonymous
737cb07403 Translated using Weblate (Italian)
Currently translated at 99.1% (692 of 698 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
2024-09-24 13:48:15 +02:00
Anonymous
3febbc21cb Translated using Weblate (Russian)
Currently translated at 99.1% (692 of 698 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ru/
2024-09-24 13:48:15 +02:00
Anonymous
7e14fae29c Translated using Weblate (Norwegian Bokmål)
Currently translated at 96.2% (672 of 698 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/nb_NO/
2024-09-24 13:48:14 +02:00
Anonymous
a16fe4561b Translated using Weblate (French)
Currently translated at 98.7% (689 of 698 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/fr/
2024-09-24 13:48:14 +02:00
Anonymous
f2afe9d681 Translated using Weblate (Spanish)
Currently translated at 99.2% (693 of 698 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/es/
2024-09-24 13:48:14 +02:00
Anonymous
f8c0a5a1ef Translated using Weblate (German)
Currently translated at 93.4% (652 of 698 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/de/
2024-09-24 13:48:14 +02:00
github-actions[bot]
631e992411 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-23 11:54:00 +00:00
jokob-sk
feafaff218 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-23 13:33:17 +10:00
jokob-sk
f6a06842cc Overridden by ENV + Icons preview #802 2024-09-23 13:32:36 +10:00
jokob-sk
0cc3ede86c Merge pull request #801 from alnviana/patch-1
Some checks are pending
docker / docker_dev (push) Waiting to run
Fixes to work using a reverse proxy
2024-09-23 11:25:39 +10:00
Allan Viana
aa277136c6 Making table_appevents and table_notifications relative 2024-09-22 21:51:49 -03:00
Allan Viana
82ccb0c0b6 Making user_notifications relative 2024-09-22 21:18:48 -03:00
jokob-sk
30750a9449 ui components defer 2024-09-23 08:39:07 +10:00
jokob-sk
5278af48c5 Sync Hub fix + overriddenByEnv 2024-09-23 08:15:35 +10:00
github-actions[bot]
77f19c3575 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-22 11:53:38 +00:00
jokob-sk
10df7363d6 Merge pull request #798 from ingoratsdorf/contrib
Some checks are pending
docker / docker_dev (push) Waiting to run
Fixes to CSS and scripts not loading properly
2024-09-22 19:16:50 +10:00
jokob-sk
06e49f7adb 📚Docs 2024-09-22 17:05:49 +10:00
Ingo Ratsdorf
9fcbd9d64e DEFER break devicedetails page
Removed DEFER from ui_components as the device details page would not populate any more and the browser console would throw errors re function not found
2024-09-22 08:18:21 +12:00
Ingo Ratsdorf
c6888a79fd Fixes CSS typo in deviceDetails 2024-09-22 08:13:09 +12:00
github-actions[bot]
ef458903b7 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-21 11:53:41 +00:00
jokob-sk
b544734209 NEWDEV_dev_Icon preview #789
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-21 17:40:41 +10:00
github-actions[bot]
815810dc7a [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-20 11:53:33 +00:00
github-actions[bot]
552d79eee8 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-19 11:53:52 +00:00
jokob-sk
2f70e2e8d8 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-19 15:45:16 +10:00
jokob-sk
4a20b66c92 Clear NEW flag setting 2024-09-19 15:43:16 +10:00
github-actions[bot]
36cec0ab38 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-18 11:53:41 +00:00
jokob-sk
6bde0f9084 🔑 Set PWD not working #793
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-18 12:56:09 +10:00
jokob-sk
f64ef5b881 🔑 Set PWD not working #793
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-18 09:57:46 +10:00
jokob-sk
1895f68233 🔄 Sync hub 2.0.1 - init Node field #788 2024-09-18 09:27:32 +10:00
jokob-sk
d2fe53bc81 🔃 Sync hub 2.0.1 #788 2024-09-18 08:48:08 +10:00
github-actions[bot]
e9e45c34ae [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-17 11:53:54 +00:00
jokob-sk
064a51acee 🩹 Handle vendor NoneType #791
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-17 08:05:17 +10:00
github-actions[bot]
7340ce6da2 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-16 11:53:54 +00:00
github-actions[bot]
703885308a [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-15 11:53:52 +00:00
jokob-sk
71856b49a4 🩹 Handle vendor NoneType #791
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-15 08:32:35 +10:00
github-actions[bot]
86c7d26107 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-14 11:53:34 +00:00
jokob-sk
d858f4f9d0 🔄Sync hub 2.0
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-14 10:37:30 +10:00
jokob-sk
aefe470d31 🔄Sync hub 2.0 2024-09-14 09:37:27 +10:00
github-actions[bot]
99fb60c1b5 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-13 11:53:38 +00:00
Hosted Weblate
ec37e4d71b Merge branch 'origin/main' into Weblate. 2024-09-13 11:09:18 +00:00
gallegonovato
e240821d6c Translated using Weblate (Spanish)
Currently translated at 100.0% (694 of 694 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/es/
2024-09-13 11:09:15 +00:00
github-actions[bot]
632e441dda [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-12 11:53:59 +00:00
jokob-sk
24f7935891 📚Docs
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-12 07:55:20 +10:00
github-actions[bot]
dcc43d1f3c [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-11 11:53:35 +00:00
github-actions[bot]
8f35bf36ff [🤖Automation] Update README with sponsors information
Some checks failed
docker / docker_dev (push) Has been cancelled
2024-09-10 11:53:40 +00:00
jokob-sk
1548168eba Lang
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-10 08:26:06 +10:00
github-actions[bot]
2e35bac6ec [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-09 11:53:47 +00:00
jokob-sk
ba348fc4c2 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-09 07:30:38 +10:00
jokob-sk
d3337e75a9 ⚙ Settings/Lang cache improvements #687 + #766 2024-09-09 07:30:33 +10:00
github-actions[bot]
9e0bc043b0 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-08 11:53:36 +00:00
jokob-sk
29fdd0b115 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-08 13:57:24 +10:00
jokob-sk
48e92a186e 🧪 Override Settings via ENV variable [experimental] #687 2024-09-08 13:57:08 +10:00
github-actions[bot]
1dcb66e972 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-07 11:53:42 +00:00
jokob-sk
fa0d6d312d Merge branch 'main' of https://github.com/jokob-sk/NetAlertX
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-07 09:28:36 +10:00
jokob-sk
a19fe342e7 🚀 Better upgarde message 2024-09-07 09:28:19 +10:00
jokob-sk
c4fc68cac8 Merge pull request #759 from elraro/fix-mtscan
chore: fixed mtscan and Dockerfile
2024-09-07 09:08:49 +10:00
jokob-sk
3a050c31a7 Update feature_request.yml 2024-09-07 09:06:29 +10:00
jokob-sk
2cd406a390 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-09-07 08:38:10 +10:00
jokob-sk
b086417686 💾 Cache update for proper status color + All display #779 2024-09-07 08:38:03 +10:00
Hosted Weblate
dbecbfc85f Merge branch 'origin/main' into Weblate.
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-06 18:09:25 +02:00
Massimo Pissarello
3f9e4c4425 Translated using Weblate (Italian)
Currently translated at 100.0% (694 of 694 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
2024-09-06 18:09:21 +02:00
Safeguard
4fd1869bde Translated using Weblate (Russian)
Currently translated at 100.0% (694 of 694 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ru/
2024-09-06 18:09:19 +02:00
github-actions[bot]
78025a376c [🤖Automation] Update README with sponsors information 2024-09-06 11:53:57 +00:00
elraro
615fd08f5b chore: changed mtscan type to device_scanner 2024-09-06 00:29:10 +02:00
elraro
4839211fe1 chore: fixed mtscan 2024-09-06 00:23:17 +02:00
jokob-sk
19aaa92fa3 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-06 07:59:38 +10:00
jokob-sk
43aa40efbb ⚙ Settings #779 2024-09-06 07:59:35 +10:00
github-actions[bot]
95f48cb70d [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-05 11:53:47 +00:00
jokob-sk
8c0da1d0df Merge branch 'main' of https://github.com/jokob-sk/NetAlertX
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-05 08:09:39 +10:00
jokob-sk
b0d07a6adc ⚙ Settings #779 2024-09-05 08:09:23 +10:00
github-actions[bot]
ee23ae19f7 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-04 11:53:54 +00:00
jokob-sk
0c73e49245 Merge pull request #783 from doctorixx/main
Some checks are pending
docker / docker_dev (push) Waiting to run
Update plugins docs after add telegram publisher(and fix typo) - thanks @doctorixx !
2024-09-04 07:23:14 +10:00
github-actions[bot]
899a0c3608 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-03 11:53:53 +00:00
Doctorixx
d188b640e4 Fix ordering in tip (in plugins readme) 2024-09-03 13:47:09 +03:00
Doctorixx
a95eb45924 Update plugins list (add telegram publisher) 2024-09-03 13:45:26 +03:00
jokob-sk
f737a71939 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-03 07:51:27 +10:00
jokob-sk
9df97e0e33 📡 Upgrade -> Show message 2024-09-03 07:51:17 +10:00
github-actions[bot]
4ce7077599 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-02 11:53:50 +00:00
jokob-sk
605a33330b 📡 Upgrade -> Show message
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-02 15:53:15 +10:00
jokob-sk
9bd5ff10b4 📡 Upgrade -> Show message
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-02 09:15:49 +10:00
jokob-sk
45d3be2439 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-09-02 08:16:20 +10:00
jokob-sk
46209e3e47 Authelia #780 2024-09-02 08:16:15 +10:00
github-actions[bot]
9b9836cae2 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-01 11:53:40 +00:00
jokob-sk
89be97bfb2 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-09-01 08:27:35 +10:00
jokob-sk
3e4f64a7c6 Refactor maintenance.php 2024-09-01 08:27:17 +10:00
github-actions[bot]
50fbd6e616 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-31 11:53:55 +00:00
jokob-sk
5a96ad2304 Refactor devices.php
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-31 17:32:10 +10:00
jokob-sk
25667014fc Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-08-31 12:57:04 +10:00
jokob-sk
955472ef5c fix HRS_TO_KEEP_NEWDEV #777 2024-08-31 12:56:46 +10:00
github-actions[bot]
e32b60cafc [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-30 11:53:37 +00:00
jokob-sk
3033c617fa Merge pull request #775 from doctorixx/main
Some checks are pending
docker / docker_dev (push) Waiting to run
Add Telegram publisher by @doctorixx 🙏
2024-08-30 07:32:07 +10:00
Doctorixx
1688836b4f Add Telegram publisher 2024-08-29 16:41:59 +03:00
github-actions[bot]
f30b6b7fc1 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-29 11:53:43 +00:00
github-actions[bot]
0c5c754f38 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-28 11:53:54 +00:00
github-actions[bot]
da21ee6477 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-27 11:53:48 +00:00
github-actions[bot]
3a268add06 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-26 11:53:54 +00:00
github-actions[bot]
03b610a6ec [🤖Automation] Update README with sponsors information
Some checks failed
docker / docker_dev (push) Has been cancelled
2024-08-25 11:53:45 +00:00
github-actions[bot]
38f70fd045 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-24 11:53:46 +00:00
jokob-sk
3473fabdbf 📚 Docs + Readme
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-24 08:23:19 +10:00
jokob-sk
46186e5d3b Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2024-08-24 08:10:08 +10:00
jokob-sk
e0dd3ab53e 📚 Docs + Readme 2024-08-24 08:10:00 +10:00
github-actions[bot]
c385ac68f4 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-23 11:53:58 +00:00
github-actions[bot]
e1c446b0df [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-22 11:53:54 +00:00
jokob-sk
0413ac5fb4 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-22 20:02:31 +10:00
jokob-sk
01f8dc5f6b Small fixes 2024-08-22 20:02:18 +10:00
Hosted Weblate
00451a6846 Merge branch 'origin/main' into Weblate.
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-21 22:09:24 +02:00
Mehdi
b181e2ada6 Translated using Weblate (French)
Currently translated at 100.0% (691 of 691 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/fr/
2024-08-21 22:09:22 +02:00
Sylvain Pichon
73a0a49934 Translated using Weblate (French)
Currently translated at 100.0% (691 of 691 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/fr/
2024-08-21 22:09:21 +02:00
github-actions[bot]
b3ad58f5f3 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-21 11:54:00 +00:00
Hosted Weblate
03e0061b03 Merge branch 'origin/main' into Weblate.
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-20 21:09:31 +02:00
Sylvain Pichon
e5a63e9caa Translated using Weblate (French)
Currently translated at 99.4% (687 of 691 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/fr/
2024-08-20 21:09:27 +02:00
github-actions[bot]
eb3a54ff1c [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-20 11:53:54 +00:00
Hosted Weblate
b3b8196b64 Merge branch 'origin/main' into Weblate.
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-19 18:35:04 +02:00
Sergey Karmanov
408d8cb7c5 Translated using Weblate (Russian)
Currently translated at 100.0% (691 of 691 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/ru/
2024-08-19 18:35:02 +02:00
Sylvain Pichon
57d94634f1 Translated using Weblate (French)
Currently translated at 75.8% (524 of 691 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/fr/
2024-08-19 18:35:01 +02:00
github-actions[bot]
3778dcb3ad [🤖Automation] Update README with sponsors information 2024-08-19 11:53:49 +00:00
github-actions[bot]
393a0d8168 [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-18 11:53:32 +00:00
Hosted Weblate
c98c22c27d Merge branch 'origin/main' into Weblate.
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-18 07:09:15 +00:00
Sylvain Pichon
54ae8a7b35 Translated using Weblate (French)
Currently translated at 74.6% (516 of 691 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/fr/
2024-08-18 07:09:12 +00:00
github-actions[bot]
a2cc2b441e [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-17 11:53:59 +00:00
jokob-sk
a3c0974e77 Merge pull request #764 from ingoratsdorf/main
Some checks are pending
docker / docker_dev (push) Waiting to run
Resolved issue with Paho V2 API
2024-08-17 12:07:29 +10:00
Ingo Ratsdorf
b7fa32f70a Resolved issue with Paho V2 API
Chnaged client creation logic to V2 API as we are already using Paho2.0. Chnaged version selection from Paho version (which should not have been a user choice) to MQTT Protocol selection, which can be v3 or v5. Most modern MQQTT brokers like Mosquitta or EMQX support v5.
2024-08-17 14:00:39 +12:00
Hosted Weblate
7fd8b039ed Merge branch 'origin/main' into Weblate.
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-16 23:09:21 +00:00
Sylvain Pichon
303cadc68c Translated using Weblate (French)
Currently translated at 69.3% (479 of 691 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/fr/
2024-08-17 01:09:13 +02:00
gallegonovato
61ab586bd6 Translated using Weblate (Spanish)
Currently translated at 100.0% (691 of 691 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/es/
2024-08-17 01:09:11 +02:00
github-actions[bot]
0c64bd392b [🤖Automation] Update README with sponsors information
Some checks are pending
docker / docker_dev (push) Waiting to run
2024-08-16 11:53:36 +00:00
elraro
ae1673c1c3 chore: fixed mtscan and Dockerfile 2024-08-11 23:55:02 +02:00
72 changed files with 2922 additions and 1231 deletions

View File

@@ -9,20 +9,6 @@ body:
options: options:
- label: I have searched the existing open and closed issues - label: I have searched the existing open and closed issues
required: true required: true
- type: checkboxes
attributes:
label: Am I willing to test this? 🧪
description: I rely on the community to test unreleased features. If you are requesting a feature, please be willing to test it within 48h of test request. Otherwise, the feature might be pulled from the code base.
options:
- label: I will do my best to test this feature on the `netlertx-dev` image when requested within 48h and report bugs to help deliver a great user experience for everyone and not to break existing installations.
required: true
- type: checkboxes
attributes:
label: Can I help implement this? 👩‍💻👨‍💻
description: The maintainer will provide guidance and help. The implementer will read the PR guidelines https://github.com/jokob-sk/NetAlertX/tree/main/docs#-pull-requests-prs
options:
- label: "Yes"
- label: "No"
- type: textarea - type: textarea
attributes: attributes:
label: Is your feature request related to a problem? Please describe label: Is your feature request related to a problem? Please describe
@@ -50,3 +36,17 @@ body:
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in. Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
validations: validations:
required: true required: true
- type: checkboxes
attributes:
label: Am I willing to test this? 🧪
description: I rely on the community to test unreleased features. If you are requesting a feature, please be willing to test it within 48h of test request. Otherwise, the feature might be pulled from the code base.
options:
- label: I will do my best to test this feature on the `netlertx-dev` image when requested within 48h and report bugs to help deliver a great user experience for everyone and not to break existing installations.
required: true
- type: checkboxes
attributes:
label: Can I help implement this? 👩‍💻👨‍💻
description: The maintainer will provide guidance and help. The implementer will read the PR guidelines https://github.com/jokob-sk/NetAlertX/tree/main/docs#-pull-requests-prs
options:
- label: "Yes"
- label: "No"

View File

@@ -1,8 +1,8 @@
FROM alpine:3.20 as builder FROM alpine:3.20 AS builder
ARG INSTALL_DIR=/app ARG INSTALL_DIR=/app
ENV PYTHONUNBUFFERED 1 ENV PYTHONUNBUFFERED=1
# Install build dependencies # Install build dependencies
RUN apk add --no-cache bash python3 python3-dev gcc musl-dev libffi-dev openssl-dev \ RUN apk add --no-cache bash python3 python3-dev gcc musl-dev libffi-dev openssl-dev \
@@ -21,7 +21,7 @@ RUN pip install netifaces tplink-omada-client pycryptodome requests paho-mqtt sc
&& bash -c "find ${INSTALL_DIR} -type f \( -name '*.sh' -o -name '*.py' -o -name 'speedtest-cli' \) -exec chmod 750 {} \;" && bash -c "find ${INSTALL_DIR} -type f \( -name '*.sh' -o -name '*.py' -o -name 'speedtest-cli' \) -exec chmod 750 {} \;"
# second stage # second stage
FROM alpine:3.20 as runner FROM alpine:3.20 AS runner
ARG INSTALL_DIR=/app ARG INSTALL_DIR=/app

View File

@@ -1,7 +1,7 @@
FROM debian:bookworm-slim FROM debian:bookworm-slim
# default UID and GID # default UID and GID
ENV USER=pi USER_ID=1000 USER_GID=1000 PORT=20211 ENV USER=pi USER_ID=1000 USER_GID=1000 PORT=20211
#TZ=Europe/London #TZ=Europe/London
# Todo, figure out why using a workdir instead of full paths don't work # Todo, figure out why using a workdir instead of full paths don't work

View File

@@ -1,12 +1,13 @@
[![GitHub Committed](https://img.shields.io/github/last-commit/jokob-sk/NetAlertX?color=40ba12&label=Committed&logo=GitHub&logoColor=fff&style=for-the-badge)](https://github.com/jokob-sk/NetAlertX)
[![Docker Size](https://img.shields.io/docker/image-size/jokobsk/netalertx?label=Size&logo=Docker&color=0aa8d2&logoColor=fff&style=for-the-badge)](https://hub.docker.com/r/jokobsk/netalertx)
[![Docker Pulls](https://img.shields.io/docker/pulls/jokobsk/netalertx?label=Pulls&logo=docker&color=0aa8d2&logoColor=fff&style=for-the-badge)](https://hub.docker.com/r/jokobsk/netalertx)
[![GitHub Release](https://img.shields.io/github/v/release/jokob-sk/NetAlertX?color=0aa8d2&logoColor=fff&logo=GitHub&style=for-the-badge)](https://github.com/jokob-sk/NetAlertX/releases)
[![Discord](https://img.shields.io/discord/1274490466481602755?color=0aa8d2&logoColor=fff&logo=Discord&style=for-the-badge)](https://discord.gg/UQnnHNYV)
# 🖧🔍 Network scanner & notification framework # 🖧🔍 Network scanner & notification framework
Get visibility of what's going on on your WIFI/LAN network. Schedule scans for devices, port changes and get alerts if unknown devices or changes are found. Write your own [Plugins](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins#readme) with auto-generated UI and in-build notification system. Build out and easily maintain your network source of truth (NSoT). Get visibility of what's going on on your WIFI/LAN network. Schedule scans for devices, port changes and get alerts if unknown devices or changes are found. Write your own [Plugins](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins#readme) with auto-generated UI and in-build notification system. Build out and easily maintain your network source of truth (NSoT).
[![GitHub Committed](https://img.shields.io/github/last-commit/jokob-sk/NetAlertX?color=40ba12&label=Committed&logo=GitHub&logoColor=fff)](https://github.com/jokob-sk/NetAlertX)
[![Docker Size](https://img.shields.io/docker/image-size/jokobsk/netalertx?label=Size&logo=Docker&color=0aa8d2&logoColor=fff)](https://hub.docker.com/r/jokobsk/netalertx)
[![Docker Pulls](https://img.shields.io/docker/pulls/jokobsk/netalertx?label=Pulls&logo=docker&color=0aa8d2&logoColor=fff)](https://hub.docker.com/r/jokobsk/netalertx)
[![GitHub Release](https://img.shields.io/github/v/release/jokob-sk/NetAlertX?color=0aa8d2&logoColor=fff&logo=GitHub)](https://github.com/jokob-sk/NetAlertX/releases)
[![GitHub Sponsors](https://img.shields.io/github/sponsors/jokob-sk?style=social)](https://github.com/sponsors/jokob-sk)
| 🐳 [Docker hub](https://registry.hub.docker.com/r/jokobsk/netalertx) | 📑 [Docker guide](https://github.com/jokob-sk/NetAlertX/blob/main/dockerfiles/README.md) |🆕 [Release notes](https://github.com/jokob-sk/NetAlertX/releases) | 📚 [All Docs](https://github.com/jokob-sk/NetAlertX/tree/main/docs) | | 🐳 [Docker hub](https://registry.hub.docker.com/r/jokobsk/netalertx) | 📑 [Docker guide](https://github.com/jokob-sk/NetAlertX/blob/main/dockerfiles/README.md) |🆕 [Release notes](https://github.com/jokob-sk/NetAlertX/releases) | 📚 [All Docs](https://github.com/jokob-sk/NetAlertX/tree/main/docs) |
|----------------------|----------------------| ----------------------| ----------------------| |----------------------|----------------------| ----------------------| ----------------------|

View File

@@ -64,7 +64,9 @@ services:
# DELETE END anyone trying to use this file: comment out / delete ABOVE lines, they are only for development purposes # DELETE END anyone trying to use this file: comment out / delete ABOVE lines, they are only for development purposes
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
environment: environment:
# - APP_CONF_OVERRIDE={"SCAN_SUBNETS":"['192.168.1.0/24 --interface=eth1']","UI_dark_mode":"True"}
- TZ=${TZ} - TZ=${TZ}
- PORT=${PORT} - PORT=${PORT}
# ❗ DANGER ZONE BELOW - Setting ALWAYS_FRESH_INSTALL=true will delete the content of the /db & /config folders # ❗ DANGER ZONE BELOW - Setting ALWAYS_FRESH_INSTALL=true will delete the content of the /db & /config folders
- ALWAYS_FRESH_INSTALL=${ALWAYS_FRESH_INSTALL} - ALWAYS_FRESH_INSTALL=${ALWAYS_FRESH_INSTALL}

View File

@@ -1,8 +1,9 @@
[![GitHub Committed](https://img.shields.io/github/last-commit/jokob-sk/NetAlertX?color=40ba12&label=Committed&logo=GitHub&logoColor=fff)](https://github.com/jokob-sk/NetAlertX) [![GitHub Committed](https://img.shields.io/github/last-commit/jokob-sk/NetAlertX?color=40ba12&label=Committed&logo=GitHub&logoColor=fff&style=for-the-badge)](https://github.com/jokob-sk/NetAlertX)
[![Docker Size](https://img.shields.io/docker/image-size/jokobsk/netalertx?label=Size&logo=Docker&color=0aa8d2&logoColor=fff)](https://hub.docker.com/r/jokobsk/netalertx) [![Docker Size](https://img.shields.io/docker/image-size/jokobsk/netalertx?label=Size&logo=Docker&color=0aa8d2&logoColor=fff&style=for-the-badge)](https://hub.docker.com/r/jokobsk/netalertx)
[![Docker Pulls](https://img.shields.io/docker/pulls/jokobsk/netalertx?label=Pulls&logo=docker&color=0aa8d2&logoColor=fff)](https://hub.docker.com/r/jokobsk/netalertx) [![Docker Pulls](https://img.shields.io/docker/pulls/jokobsk/netalertx?label=Pulls&logo=docker&color=0aa8d2&logoColor=fff&style=for-the-badge)](https://hub.docker.com/r/jokobsk/netalertx)
![GitHub Release](https://img.shields.io/github/v/release/jokob-sk/NetAlertX?color=0aa8d2&logoColor=fff&logo=GitHub) [![GitHub Release](https://img.shields.io/github/v/release/jokob-sk/NetAlertX?color=0aa8d2&logoColor=fff&logo=GitHub&style=for-the-badge)](https://github.com/jokob-sk/NetAlertX/releases)
[![GitHub Sponsors](https://img.shields.io/github/sponsors/jokob-sk?style=social)](https://github.com/sponsors/jokob-sk) [![Discord](https://img.shields.io/discord/1274490466481602755?color=0aa8d2&logoColor=fff&logo=Discord&style=for-the-badge)](https://discord.gg/UQnnHNYV)
# NetAlertX 🖧🔍 Network scanner & notification framework # NetAlertX 🖧🔍 Network scanner & notification framework
@@ -40,7 +41,8 @@ docker run -d --rm --network=host \
| `PORT` |Port of the web interface | `20211` | | `PORT` |Port of the web interface | `20211` |
| `LISTEN_ADDR` |Set the specific IP Address for the listener address for the nginx webserver (web interface). This could be useful when using multiple subnets to hide the web interface from all untrusted networks. | `0.0.0.0` | | `LISTEN_ADDR` |Set the specific IP Address for the listener address for the nginx webserver (web interface). This could be useful when using multiple subnets to hide the web interface from all untrusted networks. | `0.0.0.0` |
|`TZ` |Time zone to display stats correctly. Find your time zone [here](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) | `Europe/Berlin` | |`TZ` |Time zone to display stats correctly. Find your time zone [here](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) | `Europe/Berlin` |
|`ALWAYS_FRESH_INSTALL` | Setting to `true` will delete the content of the `/db` & `/config` folders. For testing purposes. Can be coupled with [watchtower](https://github.com/containrrr/watchtower) to have an always freshly installed `netalertx`/`-dev` image. | `N/A` | |`APP_CONF_OVERRIDE` | JSON override for settings, e.g. `{"SCAN_SUBNETS":"['192.168.1.0/24 --interface=eth1']","UI_dark_mode":"True"}` (Experimental 🧪) | `N/A` |
|`ALWAYS_FRESH_INSTALL` | If `true` will delete the content of the `/db` & `/config` folders. For testing purposes. Can be coupled with [watchtower](https://github.com/containrrr/watchtower) to have an always freshly installed `netalertx`/`netalertx-dev` image. | `N/A` |
### Docker paths ### Docker paths

View File

@@ -41,6 +41,16 @@ if [ "$ALWAYS_FRESH_INSTALL" = true ]; then
rm -rf "$INSTALL_DIR_OLD/db/"* rm -rf "$INSTALL_DIR_OLD/db/"*
fi fi
# OVERRIDE settings: Handling APP_CONF_OVERRIDE
# Check if APP_CONF_OVERRIDE is set
if [ -z "$APP_CONF_OVERRIDE" ]; then
echo "APP_CONF_OVERRIDE is not set. Skipping config file creation."
else
# Save the APP_CONF_OVERRIDE env variable as a JSON file
echo "$APP_CONF_OVERRIDE" > "${INSTALL_DIR}/config/app_conf_override.json"
echo "Config file saved to ${INSTALL_DIR}/config/app_conf_override.json"
fi
# 🔻 FOR BACKWARD COMPATIBILITY - REMOVE AFTER 12/12/2024 # 🔻 FOR BACKWARD COMPATIBILITY - REMOVE AFTER 12/12/2024
# Check if pialert.db exists, then create a symbolic link to app.db # Check if pialert.db exists, then create a symbolic link to app.db

275
docs/AUTHELIA.md Executable file
View File

@@ -0,0 +1,275 @@
(DRAFT) Authelia support
```yaml
theme: dark
default_2fa_method: "totp"
server:
address: 0.0.0.0:9091
endpoints:
enable_expvars: false
enable_pprof: false
authz:
forward-auth:
implementation: 'ForwardAuth'
authn_strategies:
- name: 'HeaderAuthorization'
schemes:
- 'Basic'
- name: 'CookieSession'
ext-authz:
implementation: 'ExtAuthz'
authn_strategies:
- name: 'HeaderAuthorization'
schemes:
- 'Basic'
- name: 'CookieSession'
auth-request:
implementation: 'AuthRequest'
authn_strategies:
- name: 'HeaderAuthRequestProxyAuthorization'
schemes:
- 'Basic'
- name: 'CookieSession'
legacy:
implementation: 'Legacy'
authn_strategies:
- name: 'HeaderLegacy'
- name: 'CookieSession'
disable_healthcheck: false
tls:
key: ""
certificate: ""
client_certificates: []
headers:
csp_template: ""
log:
## Level of verbosity for logs: info, debug, trace.
level: info
###############################################################
# The most important section
###############################################################
access_control:
## Default policy can either be 'bypass', 'one_factor', 'two_factor' or 'deny'.
default_policy: deny
networks:
- name: internal
networks:
- '192.168.0.0/18'
- '10.10.10.0/8' # Zerotier
- name: private
networks:
- '172.16.0.0/12'
rules:
- networks:
- private
domain:
- '*'
policy: bypass
- networks:
- internal
domain:
- '*'
policy: bypass
- domain:
# exclude itself from auth, should not happen as we use Traefik middleware on a case-by-case screnario
- 'auth.MYDOMAIN1.TLD'
- 'authelia.MYDOMAIN1.TLD'
- 'auth.MYDOMAIN2.TLD'
- 'authelia.MYDOMAIN2.TLD'
policy: bypass
- domain:
#All subdomains match
- 'MYDOMAIN1.TLD'
- '*.MYDOMAIN1.TLD'
policy: two_factor
- domain:
# This will not work yet as Authelio does not support multi-domain authentication
- 'MYDOMAIN2.TLD'
- '*.MYDOMAIN2.TLD'
policy: two_factor
############################################################
identity_validation:
reset_password:
jwt_secret: "[REDACTED]"
identity_providers:
oidc:
enable_client_debug_messages: true
enforce_pkce: public_clients_only
hmac_secret: [REDACTED]
lifespans:
authorize_code: 1m
id_token: 1h
refresh_token: 90m
access_token: 1h
cors:
endpoints:
- authorization
- token
- revocation
- introspection
- userinfo
allowed_origins:
- "*"
allowed_origins_from_client_redirect_uris: false
jwks:
- key: [REDACTED]
certificate_chain:
clients:
- client_id: portainer
client_name: Portainer
# generate secret with "authelia crypto hash generate pbkdf2 --random --random.length 32 --random.charset alphanumeric"
# Random Password: [REDACTED]
# Digest: [REDACTED]
client_secret: [REDACTED]
token_endpoint_auth_method: 'client_secret_post'
public: false
authorization_policy: two_factor
consent_mode: pre-configured #explicit
pre_configured_consent_duration: '6M' #Must be re-authorised every 6 Months
scopes:
- openid
#- groups #Currently not supported in Authelia V
- email
- profile
redirect_uris:
- https://portainer.MYDOMAIN1.LTD
userinfo_signed_response_alg: none
- client_id: openproject
client_name: OpenProject
# generate secret with "authelia crypto hash generate pbkdf2 --random --random.length 32 --random.charset alphanumeric"
# Random Password: [REDACTED]
# Digest: [REDACTED]
client_secret: [REDACTED]
token_endpoint_auth_method: 'client_secret_basic'
public: false
authorization_policy: two_factor
consent_mode: pre-configured #explicit
pre_configured_consent_duration: '6M' #Must be re-authorised every 6 Months
scopes:
- openid
#- groups #Currently not supported in Authelia V
- email
- profile
redirect_uris:
- https://op.MYDOMAIN.TLD
#grant_types:
# - refresh_token
# - authorization_code
#response_types:
# - code
#response_modes:
# - form_post
# - query
# - fragment
userinfo_signed_response_alg: none
##################################################################
telemetry:
metrics:
enabled: false
address: tcp://0.0.0.0:9959
totp:
disable: false
issuer: authelia.com
algorithm: sha1
digits: 6
period: 30 ## The period in seconds a one-time password is valid for.
skew: 1
secret_size: 32
webauthn:
disable: false
timeout: 60s ## Adjust the interaction timeout for Webauthn dialogues.
display_name: Authelia
attestation_conveyance_preference: indirect
user_verification: preferred
ntp:
address: "pool.ntp.org"
version: 4
max_desync: 5s
disable_startup_check: false
disable_failure: false
authentication_backend:
password_reset:
disable: false
custom_url: ""
refresh_interval: 5m
file:
path: /config/users_database.yml
watch: true
password:
algorithm: argon2
argon2:
variant: argon2id
iterations: 3
memory: 65536
parallelism: 4
key_length: 32
salt_length: 16
password_policy:
standard:
enabled: false
min_length: 8
max_length: 0
require_uppercase: true
require_lowercase: true
require_number: true
require_special: true
## zxcvbn is a well known and used password strength algorithm. It does not have tunable settings.
zxcvbn:
enabled: false
min_score: 3
regulation:
max_retries: 3
find_time: 2m
ban_time: 5m
session:
name: authelia_session
secret: [REDACTED]
expiration: 60m
inactivity: 15m
cookies:
- domain: 'MYDOMAIN1.LTD'
authelia_url: 'https://auth.MYDOMAIN1.LTD'
name: 'authelia_session'
default_redirection_url: 'https://MYDOMAIN1.LTD'
- domain: 'MYDOMAIN2.LTD'
authelia_url: 'https://auth.MYDOMAIN2.LTD'
name: 'authelia_session_other'
default_redirection_url: 'https://MYDOMAIN2.LTD'
storage:
encryption_key: [REDACTED]
local:
path: /config/db.sqlite3
notifier:
disable_startup_check: true
smtp:
address: MYOTHERDOMAIN.LTD:465
timeout: 5s
username: "USER@DOMAIN"
password: "[REDACTED]"
sender: "Authelia <postmaster@MYOTHERDOMAIN.LTD>"
identifier: NAME@MYOTHERDOMAIN.LTD
subject: "[Authelia] {title}"
startup_check_address: postmaster@MYOTHERDOMAIN.LTD
```

View File

@@ -8,10 +8,10 @@ There are 3 artifacts that can be used to backup the application:
| File | Description | Limitations | | File | Description | Limitations |
|-----------------------|-------------------------------|-------------------------------| |-----------------------|-------------------------------|-------------------------------|
| `/db/app.db` | Database file(s) | The database file might be in an uncommitted state or corrupted | | `/db/app.db` | Database file(s) | The database file might be in an uncommitted state or corrupted |
| `/config/app.conf` | Configuration file | Doesn't contain settings from the Maintenance section | | `/config/app.conf` | Configuration file | Can be overridden with the [`APP_CONF_OVERRIDE` env variable](https://github.com/jokob-sk/NetAlertX/tree/main/dockerfiles#docker-environment-variables). |
| `/config/devices.csv` | CSV file containing device information | Doesn't contain historical data | | `/config/devices.csv` | CSV file containing device information | Doesn't contain historical data |
## Data and cackup storage ## Data and backup storage
To decide on a backup strategy, check where the data is stored: To decide on a backup strategy, check where the data is stored:

View File

@@ -17,7 +17,7 @@
| Pholus_Scan | Scan results of the Pholus python network penetration script. | ![Screen8][screen8] | | Pholus_Scan | Scan results of the Pholus python network penetration script. | ![Screen8][screen8] |
| Plugins_Events | For capturing events exposed by a plugin via the `last_result.log` file. If unique then saved into the `Plugins_Objects` table. Entries are deleted once processed and stored in the `Plugins_History` and/or `Plugins_Objects` tables. | ![Screen10][screen10] | | Plugins_Events | For capturing events exposed by a plugin via the `last_result.log` file. If unique then saved into the `Plugins_Objects` table. Entries are deleted once processed and stored in the `Plugins_History` and/or `Plugins_Objects` tables. | ![Screen10][screen10] |
| Plugins_History | History of all entries from the `Plugins_Events` table | ![Screen11][screen11] | | Plugins_History | History of all entries from the `Plugins_Events` table | ![Screen11][screen11] |
| Plugins_Language_Strings | Language strings colelcted from the plugin `config.json` files used for string resolution in the frontend. | ![Screen12][screen12] | | Plugins_Language_Strings | Language strings collected from the plugin `config.json` files used for string resolution in the frontend. | ![Screen12][screen12] |
| Plugins_Objects | Unique objects detected by individual plugins. | ![Screen13][screen13] | | Plugins_Objects | Unique objects detected by individual plugins. | ![Screen13][screen13] |
| Sessions | Used to display sessions in the charts | ![Screen15][screen15] | | Sessions | Used to display sessions in the charts | ![Screen15][screen15] |
| Settings | Database representation of the sum of all settings from `app.conf` and plugins coming from `config.json` files. | ![Screen16][screen16] | | Settings | Database representation of the sum of all settings from `app.conf` and plugins coming from `config.json` files. | ![Screen16][screen16] |

View File

@@ -518,6 +518,60 @@ Required attributes are:
| (optional) `"override_value"` | Used to determine a user-defined override for the setting. Useful for template-based plugins, where you can choose to leave the current value or override it with the value defined in the setting. (Work in progress) | | (optional) `"override_value"` | Used to determine a user-defined override for the setting. Useful for template-based plugins, where you can choose to leave the current value or override it with the value defined in the setting. (Work in progress) |
| (optional) `"events"` | Used to trigger the plugin. Usually used on the `RUN` setting. Not fully tested in all scenarios. Will show a play button next to the setting. After clicking, an event is generated for the backend in the `Parameters` database table to process the front-end event on the next run. | | (optional) `"events"` | Used to trigger the plugin. Usually used on the `RUN` setting. Not fully tested in all scenarios. Will show a play button next to the setting. After clicking, an event is generated for the backend in the `Parameters` database table to process the front-end event on the next run. |
### UI Component Types Documentation
This section outlines the structure and types of UI components, primarily used to build HTML forms or interactive elements dynamically. Each UI component has a `"type"` which defines its structure, behavior, and rendering options.
#### UI Component JSON Structure
The UI component is defined as a JSON object containing a list of `elements`. Each element specifies how it should behave, with properties like `elementType`, `elementOptions`, and any associated `transformers` to modify the data. The example below demonstrates how a component with two elements (`span` and `select`) is structured:
```json
{
"function": "dev_Icon",
"type": {
"dataType": "string",
"elements": [
{
"elementType": "span",
"elementOptions": [
{ "cssClasses": "input-group-addon iconPreview" },
{ "getStringKey": "Gen_SelectToPreview" },
{ "customId": "NEWDEV_dev_Icon_preview" }
],
"transformers": []
},
{
"elementType": "select",
"elementHasInputValue": 1,
"elementOptions": [
{ "cssClasses": "col-xs-12" },
{
"onChange": "updateIconPreview(this)"
},
{ "customParams": "NEWDEV_dev_Icon,NEWDEV_dev_Icon_preview" }
],
"transformers": []
}
]
}
}
```
### Rendering Logic
The code snippet provided demonstrates how the elements are iterated over to generate their corresponding HTML. Depending on the `elementType`, different HTML tags (like `<select>`, `<input>`, `<textarea>`, `<button>`, etc.) are created with the respective attributes such as `onChange`, `my-data-type`, and `class` based on the provided `elementOptions`. Events can also be attached to elements like buttons or select inputs.
### Key Element Types
- **`select`**: Renders a dropdown list. Additional options like `isMultiSelect` and event handlers (e.g., `onChange`) can be attached.
- **`input`**: Handles various types of input fields, including checkboxes, text, and others, with customizable attributes like `readOnly`, `placeholder`, etc.
- **`button`**: Generates clickable buttons with custom event handlers (`onClick`), icons, or labels.
- **`textarea`**: Creates a multi-line input box for text input.
- **`span`**: Used for inline text or content with customizable classes and data attributes.
Each element may also have associated events (e.g., running a scan or triggering a notification) defined under `Events`.
##### Supported settings `function` values ##### Supported settings `function` values

View File

@@ -63,6 +63,7 @@ There is also an in-app Help / FAQ section that should be answering frequently a
- [Version history (legacy)](/docs/VERSIONS_HISTORY.md) - [Version history (legacy)](/docs/VERSIONS_HISTORY.md)
- [Reverse proxy (Nginx, Apache, SWAG)](/docs/REVERSE_PROXY.md) - [Reverse proxy (Nginx, Apache, SWAG)](/docs/REVERSE_PROXY.md)
- [Setting up Authelia](/docs/AUTHELIA.md) (DRAFT)
#### 👩💻For Developers👨💻 #### 👩💻For Developers👨💻

View File

@@ -15,6 +15,7 @@ You need to specify the network interface and the network mask. You can also con
* One subnet: `SCAN_SUBNETS = ['192.168.1.0/24 --interface=eth0']` * One subnet: `SCAN_SUBNETS = ['192.168.1.0/24 --interface=eth0']`
* Two subnets: `SCAN_SUBNETS = ['192.168.1.0/24 --interface=eth0','192.168.1.0/24 --interface=eth1 -vlan=107']` * Two subnets: `SCAN_SUBNETS = ['192.168.1.0/24 --interface=eth0','192.168.1.0/24 --interface=eth1 -vlan=107']`
If you get timeout messages, decrease the network mask (e.g.: from a `/16` to `/24`) or increase the `TIMEOUT` setting (e.g.: `ARPSCAN_RUN_TIMEOUT` to `300` (a timeout of 5min)) for the plugin and the interval between scans (e.g.: `ARPSCAN_RUN_SCHD` to `*/10 * * * *` (scans every 10 min)).
## Explanation ## Explanation

View File

@@ -17,7 +17,7 @@ showSpinner()
$(document).ready(function() { $(document).ready(function() {
// Load JSON data from the provided URL // Load JSON data from the provided URL
$.getJSON('/api/table_appevents.json', function(data) { $.getJSON('api/table_appevents.json', function(data) {
// Process the JSON data and generate UI dynamically // Process the JSON data and generate UI dynamically
processData(data) processData(data)

View File

@@ -745,6 +745,18 @@ height: 50px;
.infobox_label { .infobox_label {
font-size: 16px !important; font-size: 16px !important;
} }
.deviceSelector
{
display: block;
}
.deviceSelector input
{
width: 100% !important;
display: inline-grid;
}
/* --------------------------------------------------------- */ /* --------------------------------------------------------- */
/* report */ /* report */
/* --------------------------------------------------------- */ /* --------------------------------------------------------- */
@@ -1079,11 +1091,67 @@ input[readonly] {
margin-bottom:20px; margin-bottom:20px;
} }
#settingsPage .select2-selection
{
width: initial;
display: inline-block;
}
#settingsPage .form-control
{
min-height: 42px;
}
#settingsPage .select2-selection
{
background-color: rgb(96, 96, 96);
}
#settingsPage .select2-container
{
width: 100% !important;
}
#settingsPage .select2-container .selection
{
width: 100% !important;
display: inline-grid;
}
/* Basic style for the div elements */
#settingsPage .setting_overriden_by_env {
position: relative;
/* width: 300px;
height: 200px; */
background-color: #f3f3f3;
border: 1px solid #ccc;
margin: 20px;
z-index: 10;
}
/* Style for the overlay */
#settingsPage .setting_overriden_by_env::after {
content: "Overridden with ENV variable";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.6); /* semi-transparent black overlay */
color: white;
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
font-weight: 700;
z-index: 11;
}
/* ----------------------------------------------------------------- */ /* ----------------------------------------------------------------- */
/* Devices page */ /* Devices page */
/* ----------------------------------------------------------------- */ /* ----------------------------------------------------------------- */
#txtIconFA { .iconPreview {
min-width: 40px; min-width: 40px;
} }
@@ -1110,18 +1178,18 @@ input[readonly] {
cursor: -webkit-grab; cursor: -webkit-grab;
} }
.db_info_table_row .select2-container--default .select2-selection--multiple .select2-selection__choice .select2-container--default .select2-selection--multiple .select2-selection__choice
{ {
background-color:#258744; background-color:#258744 !important;
} }
.db_info_table_row .select2-container--default .select2-selection--multiple .select2-container--default .select2-selection--multiple
{ {
background-color:#606060; background-color:#606060 !important;
} }
.select2-container .select2-dropdown .select2-container .select2-dropdown
{ {
background-color:#606060; background-color:#606060 !important;
} }
.networkPageHelp{ .networkPageHelp{
@@ -1390,7 +1458,7 @@ input[readonly] {
opacity: 0.8; opacity: 0.8;
background-color: #fff; background-color: #fff;
z-index: 99; z-index: 800;
} }
.pa_spinner { .pa_spinner {
@@ -1403,7 +1471,7 @@ input[readonly] {
padding: 15px; padding: 15px;
width: 200px; width: 200px;
background-color: #fff; background-color: #fff;
z-index: 100; z-index: 801;
} }
#loadingSpinner #loadingSpinner

View File

@@ -100,7 +100,7 @@
<div class="col-lg-12 col-sm-12 col-xs-12"> <div class="col-lg-12 col-sm-12 col-xs-12">
<!-- <div class="box-transparent"> --> <!-- <div class="box-transparent"> -->
<div id="navDevice" class="nav-tabs-custom"> <div id="navDevice" class="nav-tabs-custom">
<ul class="nav nav-tabs" style="fon t-size:16px;"> <ul class="nav nav-tabs" style="font-size:16px;">
<li> <a id="tabDetails" href="#panDetails" data-toggle="tab"> <?= lang('DevDetail_Tab_Details');?> </a></li> <li> <a id="tabDetails" href="#panDetails" data-toggle="tab"> <?= lang('DevDetail_Tab_Details');?> </a></li>
<li> <a id="tabTools" href="#panTools" data-toggle="tab"> <?= lang('DevDetail_Tab_Tools');?> </a></li> <li> <a id="tabTools" href="#panTools" data-toggle="tab"> <?= lang('DevDetail_Tab_Tools');?> </a></li>
<li> <a id="tabSessions" href="#panSessions" data-toggle="tab"> <?= lang('DevDetail_Tab_Sessions');?> </a></li> <li> <a id="tabSessions" href="#panSessions" data-toggle="tab"> <?= lang('DevDetail_Tab_Sessions');?> </a></li>
@@ -197,8 +197,8 @@
</label> </label>
<div class="col-sm-9"> <div class="col-sm-9">
<div class="input-group"> <div class="input-group">
<span class="input-group-addon" id="txtIconFA"></span> <span class="input-group-addon iconPreview" id="txtIconPreview" my-customid="txtIconPreview"></span>
<input class="form-control" id="txtIcon" type="text" value="--" readonly> <input class="form-control" id="txtIcon" my-customid="txtIcon" my-customparams="txtIcon,txtIconPreview" type="text" value="--" readonly>
<span class="input-group-addon" title='<?= lang('DevDetail_button_AddIcon_Tooltip');?>'><i class="fa fa-square-plus pointer" onclick="askAddIcon();"></i></span> <span class="input-group-addon" title='<?= lang('DevDetail_button_AddIcon_Tooltip');?>'><i class="fa fa-square-plus pointer" onclick="askAddIcon();"></i></span>
<span class="input-group-addon" title='<?= lang('DevDetail_button_OverwriteIcons_Tooltip');?>'><i class="fa fa-copy pointer" onclick="askOverwriteIconType();"></i></span> <span class="input-group-addon" title='<?= lang('DevDetail_button_OverwriteIcons_Tooltip');?>'><i class="fa fa-copy pointer" onclick="askOverwriteIconType();"></i></span>
<div class="input-group-btn"> <div class="input-group-btn">
@@ -693,7 +693,6 @@ if ($ENABLED_DARKMODE === True) {
var pos = -1; var pos = -1;
var parPeriod = 'Front_Details_Period'; var parPeriod = 'Front_Details_Period';
var parTab = 'Front_Details_Tab';
var parSessionsRows = 'Front_Details_Sessions_Rows'; var parSessionsRows = 'Front_Details_Sessions_Rows';
var parEventsRows = 'Front_Details_Events_Rows'; var parEventsRows = 'Front_Details_Events_Rows';
var parEventsHide = 'Front_Details_Events_Hide'; var parEventsHide = 'Front_Details_Events_Hide';
@@ -736,7 +735,7 @@ function main () {
$('#chkHideConnectionEvents')[0].checked = eval(eventsHide == 'true'); $('#chkHideConnectionEvents')[0].checked = eval(eventsHide == 'true');
// Initialize components with parameters // Initialize components with parameters
initializeTabs(); initializeTabsNew();
initializeiCheck(); initializeiCheck();
initializeCombos(); initializeCombos();
initializeDatatables(); initializeDatatables();
@@ -756,24 +755,13 @@ function main () {
// Show device icon as it changes // Show device icon as it changes
$('#txtIcon').on('change input', function() { $('#txtIcon').on('change input', function() {
updateIconPreview('#txtIcon') updateIconPreview(this)
}); });
} }
// -----------------------------------------------------------------------------
function initializeTabs () {
// Activate panel
$('.nav-tabs a[id='+ tab +']').tab('show');
// When changed save new current tab
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
setParameter (parTab, $(e.target).attr('id'));
});
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
function initializeiCheck () { function initializeiCheck () {
// Blue // Blue
@@ -1148,7 +1136,7 @@ function initializeCalendar () {
showSpinner() showSpinner()
} else { } else {
setTimeout(() => { setTimeout(() => {
updateIconPreview('#txtIcon') updateIconPreview($('#txtIcon'))
}, 500); }, 500);
hideSpinner() hideSpinner()
@@ -1457,10 +1445,10 @@ function setDeviceData (direction='', refreshCallback='') {
// update data to server // update data to server
$.get('php/server/devices.php?action=setDeviceData&mac='+ mac $.get('php/server/devices.php?action=setDeviceData&mac='+ mac
+ '&name=' + encodeURIComponent($('#txtName').val()) + '&name=' + encodeURIComponent($('#txtName').val().replace(/'/g, ""))
+ '&owner=' + encodeURIComponent($('#txtOwner').val()) + '&owner=' + encodeURIComponent($('#txtOwner').val().replace(/'/g, ""))
+ '&type=' + $('#txtDeviceType').val() + '&type=' + $('#txtDeviceType').val()
+ '&vendor=' + encodeURIComponent($('#txtVendor').val()) + '&vendor=' + encodeURIComponent($('#txtVendor').val().replace(/'/g, ""))
+ '&icon=' + encodeURIComponent($('#txtIcon').val()) + '&icon=' + encodeURIComponent($('#txtIcon').val())
+ '&favorite=' + ($('#chkFavorite')[0].checked * 1) + '&favorite=' + ($('#chkFavorite')[0].checked * 1)
+ '&group=' + encodeURIComponent($('#txtGroup').val()) + '&group=' + encodeURIComponent($('#txtGroup').val())
@@ -1679,7 +1667,7 @@ function addAsBase64 () {
$('#txtIcon').val(iconHtmlBase64); $('#txtIcon').val(iconHtmlBase64);
updateIconPreview('#txtIcon') updateIconPreview($('#txtIcon'))
} }

View File

@@ -137,136 +137,70 @@
<!-- page script ----------------------------------------------------------- --> <!-- page script ----------------------------------------------------------- -->
<script> <script>
var deviceStatus = 'all'; var deviceStatus = 'all';
var parTableRows = 'Front_Devices_Rows'; var tableRows = getCookie ("nax_parTableRows") == "" ? 10 : getCookie ("nax_parTableRows") ;
var parTableOrder = 'Front_Devices_Order'; var tableOrder = getCookie ("nax_parTableOrder") == "" ? [[3,'desc'], [0,'asc']] : JSON.parse(getCookie ("nax_parTableOrder")) ;
var tableRows = 10;
var tableOrder = [[3,'desc'], [0,'asc']];
var tableColumnHide = []; var tableColumnHide = [];
var tableColumnOrder = []; var tableColumnOrder = [];
var tableColumnVisible = []; var tableColumnVisible = [];
// Read parameters & Initialize components // Read parameters & Initialize components
callAfterAppInitialized(main) callAfterAppInitialized(main)
showSpinner(); showSpinner();
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
function main () { function main () {
//initialize the table headers in the correct order //initialize the table headers in the correct order
var headersDefaultOrder = [ var availableColumns = getSettingOptions("UI_device_columns").split(",");
getString('Device_TableHead_Name'), var headersDefaultOrder = availableColumns.map(val => getString(val));
getString('Device_TableHead_Owner'), var selectedColumns = JSON.parse(getSetting("UI_device_columns").replace(/'/g, '"'));
getString('Device_TableHead_Type'),
getString('Device_TableHead_Icon'),
getString('Device_TableHead_Favorite'),
getString('Device_TableHead_Group'),
getString('Device_TableHead_FirstSession'),
getString('Device_TableHead_LastSession'),
getString('Device_TableHead_LastIP'),
getString('Device_TableHead_MAC'),
getString('Device_TableHead_Status'),
getString('Device_TableHead_MAC_full'),
getString('Device_TableHead_LastIPOrder'),
getString('Device_TableHead_Rowid'),
getString('Device_TableHead_Parent_MAC'),
getString('Device_TableHead_Connected_Devices'),
getString('Device_TableHead_Location'),
getString('Device_TableHead_Vendor'),
getString('Device_TableHead_Port'),
getString('Device_TableHead_GUID'),
getString('Device_TableHead_SyncHubNodeName'),
getString('Device_TableHead_NetworkSite'),
getString('Device_TableHead_SSID')
];
// generate default order lists of given length // generate default order lists of given length
var columnsStr = JSON.stringify(Array.from({ length: headersDefaultOrder.length }, (_, i) => i)); var columnsStr = JSON.stringify(Array.from({ length: headersDefaultOrder.length }, (_, i) => i));
tableColumnOrder = Array.from({ length: headersDefaultOrder.length }, (_, i) => i); tableColumnOrder = Array.from({ length: headersDefaultOrder.length }, (_, i) => i);
tableColumnVisible = tableColumnOrder; tableColumnVisible = [];
handleLoadingDialog() // Initialize tableColumnVisible by including all columns from selectedColumns, preserving their order.
tableColumnVisible = selectedColumns.map(column => availableColumns.indexOf(column)).filter(index => index !== -1);
// Add any columns from availableColumns that are not in selectedColumns to the end.
const remainingColumns = availableColumns.map((column, index) => index).filter(index => !tableColumnVisible.includes(index));
// Combine both arrays.
tableColumnOrder = tableColumnVisible.concat(remainingColumns);
// Generate the full array of numbers from 0 to totalLength - 1 of tableColumnOrder
const fullArray = Array.from({ length: tableColumnOrder.length }, (_, i) => i);
// Filter out the elements already present in inputArray
const missingNumbers = fullArray.filter(num => !tableColumnVisible.includes(num));
// Concatenate the inputArray with the missingNumbers
tableColumnOrder = [...tableColumnVisible, ...missingNumbers];
// render table headers
html = '';
for(index = 0; index < tableColumnOrder.length; index++)
{
html += '<th>' + headersDefaultOrder[tableColumnOrder[index]] + '</th>';
}
$('#tableDevices tr').html(html);
// Hide UI elements as per settings // Hide UI elements as per settings
// setTimeout(() => { // setTimeout(() => {
hideUIelements("UI_DEV_SECTIONS") hideUIelements("UI_DEV_SECTIONS")
// }, 10); // }, 10);
// Initialize components with parameters
initializeDatatable(getUrlAnchor('my_devices'));
// check if data outdated and show spinner if so
handleLoadingDialog()
// get from cookie if available (need to use decodeURI as saved as part of URI in PHP)
cookieColumnsVisibleStr = decodeURI(getCookie("Front_Devices_Columns_Visible")).replaceAll('%2C',',')
defaultValue = cookieColumnsVisibleStr == "" ? columnsStr : cookieColumnsVisibleStr;
// get visible columns
$.get('php/server/parameters.php?action=get&expireMinutes=525600&defaultValue='+defaultValue+'&parameter=Front_Devices_Columns_Visible&skipcache', function(data) {
handle_locked_DB(data)
// save which columns are in the Devices page visible
tableColumnVisible = numberArrayFromString(data);
// get from cookie if available (need to use decodeURI as saved as part of URI in PHP)
cookieColumnsOrderStr = decodeURI(getCookie("Front_Devices_Columns_Order")).replaceAll('%2C',',')
defaultValue = cookieColumnsOrderStr == "" ? columnsStr : cookieColumnsOrderStr;
// get the custom order specified by the user
$.get('php/server/parameters.php?action=get&expireMinutes=525600&defaultValue='+defaultValue+'&parameter=Front_Devices_Columns_Order&skipcache', function(data) {
handle_locked_DB(data)
// save the columns order in the Devices page
tableColumnOrder = numberArrayFromString(data);
html = '';
for(index = 0; index < tableColumnOrder.length; index++)
{
html += '<th>' + headersDefaultOrder[tableColumnOrder[index]] + '</th>';
}
$('#tableDevices tr').html(html);
// get parameter value
$.get('php/server/parameters.php?action=get&defaultValue=50&parameter='+ parTableRows, function(data) {
var result = JSON.parse(data);
result = parseInt(result, 10)
if (Number.isInteger (result) ) {
tableRows = result;
}
// get parameter value
$.get('php/server/parameters.php?action=get&defaultValue=[[3,"desc"],[0,"asc"]]&parameter='+ parTableOrder, function(data) {
var result = JSON.parse(data);
result = JSON.parse(result);
if (Array.isArray (result) ) {
tableOrder = result;
}
// Initialize components with parameters
initializeDatatable(getUrlAnchor('my_devices'));
// check if data outdated and show spinner if so
handleLoadingDialog()
});
});
});
});
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@@ -467,6 +401,11 @@ function initializeDatatable (status) {
} }
$.get('api/table_devices.json?nocache=' + Date.now(), function(result) { $.get('api/table_devices.json?nocache=' + Date.now(), function(result) {
// refresh devices cache
devicesListAll_JSON = result["data"]
devicesListAll_JSON_str = JSON.stringify(devicesListAll_JSON)
setCache('devicesListAll_JSON', devicesListAll_JSON_str)
// query data // query data
getDevicesTotals(result.data); getDevicesTotals(result.data);
@@ -515,10 +454,6 @@ function initializeDatatable (status) {
}) })
}; };
// TODO displayed columns
// Check if the DataTable already exists // Check if the DataTable already exists
if ($.fn.dataTable.isDataTable('#tableDevices')) { if ($.fn.dataTable.isDataTable('#tableDevices')) {
// The DataTable exists, so destroy it // The DataTable exists, so destroy it
@@ -526,12 +461,12 @@ function initializeDatatable (status) {
table.clear().destroy(); table.clear().destroy();
} }
var table= var table =
$('#tableDevices').DataTable({ $('#tableDevices').DataTable({
'data' : dataArray["data"], 'data' : dataArray["data"],
'paging' : true, 'paging' : true,
'lengthChange' : true, 'lengthChange' : true,
'lengthMenu' : [[10, 25, 50, 100, 500, -1], [10, 25, 50, 100, 500, getString('Device_Tablelenght_all')]], 'lengthMenu' : [[10, 25, 50, 100, 500, 100000], [10, 25, 50, 100, 500, getString('Device_Tablelenght_all')]],
'searching' : true, 'searching' : true,
'ordering' : true, 'ordering' : true,
@@ -679,11 +614,11 @@ function initializeDatatable (status) {
// Save cookie Rows displayed, and Parameters rows & order // Save cookie Rows displayed, and Parameters rows & order
$('#tableDevices').on( 'length.dt', function ( e, settings, len ) { $('#tableDevices').on( 'length.dt', function ( e, settings, len ) {
setParameter (parTableRows, len); setCookie ("nax_parTableRows", len);
} ); } );
$('#tableDevices').on( 'order.dt', function () { $('#tableDevices').on( 'order.dt', function () {
setParameter (parTableOrder, JSON.stringify (table.order()) ); setCookie ("nax_parTableOrder", JSON.stringify (table.order()) );
setCache ('devicesList', getDevicesFromTable(table) ); setCache ('devicesList', getDevicesFromTable(table) );
} ); } );
@@ -703,8 +638,6 @@ function initializeDatatable (status) {
// Check if any row is selected // Check if any row is selected
var anyRowSelected = $('#tableDevices tr.selected').length > 0; var anyRowSelected = $('#tableDevices tr.selected').length > 0;
console.log(anyRowSelected);
// Toggle visibility of element with ID 'multiEdit' // Toggle visibility of element with ID 'multiEdit'
$('#multiEdit').toggle(anyRowSelected); $('#multiEdit').toggle(anyRowSelected);
}, 200); }, 200);

View File

@@ -78,7 +78,7 @@ if (isset ($_SESSION["login"]) == FALSE || $_SESSION["login"] != 1)
<meta http-equiv="Pragma" content="no-cache" /> <meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" /> <meta http-equiv="Expires" content="0" />
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Net Alert X | Log in</title> <title>NetAlert X | Log in</title>
<!-- Tell the browser to be responsive to screen width --> <!-- Tell the browser to be responsive to screen width -->
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport"> <meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
<!-- Bootstrap 3.3.7 --> <!-- Bootstrap 3.3.7 -->
@@ -104,7 +104,7 @@ if ($ENABLED_DARKMODE === True) {
<body class="hold-transition login-page"> <body class="hold-transition login-page">
<div class="login-box login-custom"> <div class="login-box login-custom">
<div class="login-logo"> <div class="login-logo">
<a href="/index2.php">Net <b>Alert</b><sup>x</sup></a> <a href="/index2.php">Net<b>Alert</b><sup>x</sup></a>
</div> </div>
<!-- /.login-logo --> <!-- /.login-logo -->
<div class="login-box-body"> <div class="login-box-body">

View File

@@ -12,7 +12,7 @@ var timerRefreshData = ''
var emptyArr = ['undefined', "", undefined, null, 'null']; var emptyArr = ['undefined', "", undefined, null, 'null'];
var UI_LANG = "English"; var UI_LANG = "English";
const allLanguages = ["en_us", "es_es", "de_de", "fr_fr", "it_it", "ru_ru", "nb_no", "pl_pl", "zh_cn", "cs_cz"]; // needs to be same as in lang.php const allLanguages = ["en_us", "es_es", "de_de", "fr_fr", "it_it", "ru_ru", "nb_no", "pl_pl", "pt_br", "tr_tr", "zh_cn", "cs_cz"]; // needs to be same as in lang.php
var settingsJSON = {} var settingsJSON = {}
@@ -212,7 +212,8 @@ function cacheStrings() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
// Create a promise for each language // Create a promise for each language
const languagePromises = allLanguages.map((language_code) => { languagesToLoad = ['en_us', getLangCode()]
const languagePromises = languagesToLoad.map((language_code) => {
return new Promise((resolveLang, rejectLang) => { return new Promise((resolveLang, rejectLang) => {
// Fetch core strings and translations // Fetch core strings and translations
@@ -267,6 +268,29 @@ function cacheStrings() {
function getString(key) { function getString(key) {
function fetchString(key) { function fetchString(key) {
lang_code = getLangCode();
let result = getCache(`pia_lang_${key}_${lang_code}`, true);
if (isEmpty(result)) {
result = getCache(`pia_lang_${key}_en_us`, true);
}
return result;
}
if (isAppInitialized()) {
return fetchString(key);
} else {
callAfterAppInitialized(() => fetchString(key));
}
}
// -----------------------------------------------------------------------------
// Get current language ISO code
function getLangCode() {
UI_LANG = getSetting("UI_LANG"); UI_LANG = getSetting("UI_LANG");
let lang_code = 'en_us'; let lang_code = 'en_us';
@@ -310,20 +334,7 @@ function getString(key) {
break; break;
} }
let result = getCache(`pia_lang_${key}_${lang_code}`, true); return lang_code;
if (isEmpty(result)) {
result = getCache(`pia_lang_${key}_en_us`, true);
}
return result;
}
if (isAppInitialized()) {
return fetchString(key);
} else {
callAfterAppInitialized(() => fetchString(key));
}
} }
@@ -399,6 +410,7 @@ function handle_locked_DB(data)
showSpinner() showSpinner()
setTimeout(function() { setTimeout(function() {
console.warn("Database locked - reload")
location.reload(); location.reload();
}, 5000); }, 5000);
} }
@@ -618,17 +630,11 @@ function debugTimer () {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
function secondsSincePageLoad() { function secondsSincePageLoad() {
// Get the current time // Get the current time since the page was loaded
var currentTime = Date.now(); var timeSincePageLoad = performance.now();
// Get the time when the page was loaded
var pageLoadTime = performance.timeOrigin;
// Calculate the difference in milliseconds
var timeDifference = currentTime - pageLoadTime;
// Convert milliseconds to seconds // Convert milliseconds to seconds
var secondsAgo = Math.floor(timeDifference / 1000); var secondsAgo = Math.floor(timeSincePageLoad / 1000);
return secondsAgo; return secondsAgo;
} }
@@ -1134,6 +1140,54 @@ function arraysContainSameValues(arr1, arr2) {
} }
} }
// -----------------------------------------------------------------------------
// Hide elements on the page based on the supplied setting
function hideUIelements(settingKey) {
hiddenSectionsSetting = getSetting(settingKey)
if(hiddenSectionsSetting != "") // handle if settings not yet initialized
{
sectionsArray = createArray(hiddenSectionsSetting)
// remove spaces to get IDs
var newArray = $.map(sectionsArray, function(value) {
return value.replace(/\s/g, '');
});
$.each(newArray, function(index, hiddenSection) {
if($('#' + hiddenSection))
{
$('#' + hiddenSection).hide()
}
});
}
}
// -----------------------------------------------------------------------------
// apply dark mode
$(document).ready(function() {
// Assume getSetting is a function that returns true or false for dark mode
if (getSetting("UI_dark_mode") === "True") {
// Add the dark mode stylesheet
setCookie("UI_dark_mode", "True")
$('head').append('<link rel="stylesheet" href="css/dark-patch.css">');
// Set the background image for dark mode
$('body').attr('style', 'background-image: url(\'img/boxed-bg-dark.png\');');
} else {
setCookie("UI_dark_mode", "False")
// Set the background image for light mode
$('body').attr('style', 'background-image: url(\'img/background.png\');');
}
});
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// initialize // initialize
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@@ -1144,7 +1198,7 @@ const sessionStorageKey = "myScriptExecuted_common_js";
var completedCalls = [] var completedCalls = []
var completedCalls_final = ['cacheSettings', 'cacheStrings', 'cacheDevices']; var completedCalls_final = ['cacheSettings', 'cacheStrings', 'cacheDevices'];
var completedCallsCount = 0; var completedCallsCount = 0;
var completedCallsCount_final = allLanguages.length + 2; // number of language files + cacheDevices + cacheSettings var completedCallsCount_final;
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Clearing all the caches // Clearing all the caches
@@ -1153,8 +1207,9 @@ function clearCache() {
sessionStorage.clear(); sessionStorage.clear();
localStorage.clear(); localStorage.clear();
setTimeout(() => { setTimeout(() => {
window.location.reload(); console.warn("clearChache called");
}, 500); window.location.reload();
}, 500);
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@@ -1199,7 +1254,11 @@ function callAfterAppInitialized(callback) {
// Check if the code has been executed before by checking sessionStorage // Check if the code has been executed before by checking sessionStorage
function isAppInitialized() { function isAppInitialized() {
// return arraysContainSameValues(getCache("completedCalls").split(',').filter(Boolean), completedCalls_final); // return arraysContainSameValues(getCache("completedCalls").split(',').filter(Boolean), completedCalls_final);
return (parseInt(getCache("completedCallsCount")) == completedCallsCount_final);
// loading settings + 1 (or 2 language files if not english) + device cache.
completedCallsCount_final = getLangCode() == 'en_us' ? 3 : 4 ;
return (parseInt(getCache("completedCallsCount")) >= completedCallsCount_final);
} }
// Define a function that will execute the code only once // Define a function that will execute the code only once
@@ -1291,6 +1350,7 @@ setTimeout(() => {
// page refresh if configured // page refresh if configured
const refreshTime = getSetting("UI_REFRESH"); const refreshTime = getSetting("UI_REFRESH");
if (refreshTime && refreshTime !== "0" && refreshTime !== "") { if (refreshTime && refreshTime !== "0" && refreshTime !== "") {
console.log("Refreshing page becasue UI_REFRESH setting enabled.");
newTimerRefreshData(clearCache, parseInt(refreshTime)*1000); newTimerRefreshData(clearCache, parseInt(refreshTime)*1000);
} }

View File

@@ -295,6 +295,7 @@ function checkNotification() {
console.log(response); console.log(response);
// After marking the notification as read, check for the next one // After marking the notification as read, check for the next one
checkNotification(); checkNotification();
hideSpinner();
}, },
error: function(xhr, status, error) { error: function(xhr, status, error) {
console.error("Error marking notification as read:", status, error); console.error("Error marking notification as read:", status, error);

View File

@@ -304,6 +304,54 @@ function removeAllOptions(element) {
$(`#${$(element).attr("my-input-to")}`).empty(); $(`#${$(element).attr("my-input-to")}`).empty();
} }
// -------------------------------------------------------------------
// Add all options
function selectAll(element) {
settingsChanged();
// Get the <select> element with the class 'deviceSelector'
// var selectElement = $('.deviceSelector select');
var selectElement = $(`#${$(element).attr("my-input-to")}`);
// Iterate over each option within the select element
selectElement.find('option').each(function() {
// Mark each option as selected
$(this).prop('selected', true);
});
// Trigger the 'change' event to notify Bootstrap Select of the changes
selectElement.trigger('change');
}
// -----------------------------------------------------------------------------
// UN-Select All
function unselectAll(element) {
settingsChanged();
// Get the <select> element with the class 'deviceSelector'
// var selectElement = $('.deviceSelector select');
var selectElement = $(`#${$(element).attr("my-input-to")}`);
// Iterate over each option within the select element
selectElement.find('option').each(function() {
// Unselect each option
$(this).prop('selected', false);
});
// Trigger the 'change' event to notify Bootstrap Select of the changes
selectElement.trigger('change');
}
// -----------------------------------------------------------------------------
// Trigger change to open up the dropdown filed
function selectChange(element) {
settingsChanged();
// Get the <select> element with the class 'deviceSelector'
// var selectElement = $('.deviceSelector select');
var selectElement = $(`#${$(element).attr("my-input-to")}`);
selectElement.parent().find("input").focus().click();
}
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Function to initialize remove functionality on select options // Function to initialize remove functionality on select options
@@ -437,8 +485,6 @@ function filterRows(inputText) {
} }
setTimeout(() => { setTimeout(() => {
// Event listener for input change // Event listener for input change
$("#settingsSearch").on("input", function () { $("#settingsSearch").on("input", function () {
@@ -568,6 +614,10 @@ function applyTransformers(val, transformers) {
val = btoa(val); val = btoa(val);
} }
break; break;
case "getString":
// no change
val = val;
break;
default: default:
console.warn(`Unknown transformer: ${transformer}`); console.warn(`Unknown transformer: ${transformer}`);
} }
@@ -590,6 +640,10 @@ function reverseTransformers(val, transformers) {
val = atob(val); val = atob(val);
} }
break; break;
case "getString":
// retrieve string
val = getString(val);
break;
default: default:
console.warn(`Unknown transformer: ${transformer}`); console.warn(`Unknown transformer: ${transformer}`);
} }
@@ -604,6 +658,7 @@ const handleElementOptions = (codeName, elementOptions, transformers, val) => {
let inputType = "text"; let inputType = "text";
let readOnly = ""; let readOnly = "";
let isMultiSelect = false; let isMultiSelect = false;
let isOrdeable = false;
let cssClasses = ""; let cssClasses = "";
let placeholder = ""; let placeholder = "";
let suffix = ""; let suffix = "";
@@ -612,7 +667,11 @@ const handleElementOptions = (codeName, elementOptions, transformers, val) => {
let valRes = val; let valRes = val;
let sourceIds = []; let sourceIds = [];
let getStringKey = ""; let getStringKey = "";
let onClick = "alert('Not implemented');"; let onClick = "console.log('onClick - Not implemented');";
let onChange = "console.log('onChange - Not implemented');";
let customParams = "";
let customId = "";
elementOptions.forEach((option) => { elementOptions.forEach((option) => {
if (option.prefillValue) { if (option.prefillValue) {
@@ -627,6 +686,9 @@ const handleElementOptions = (codeName, elementOptions, transformers, val) => {
if (option.multiple === "true") { if (option.multiple === "true") {
isMultiSelect = true; isMultiSelect = true;
} }
if (option.ordeable === "true") {
isOrdeable = true;
}
if (option.editable === "true") { if (option.editable === "true") {
editable = true; editable = true;
} }
@@ -653,6 +715,15 @@ const handleElementOptions = (codeName, elementOptions, transformers, val) => {
if (option.onClick) { if (option.onClick) {
onClick = option.onClick; onClick = option.onClick;
} }
if (option.onChange) {
onChange = option.onChange;
}
if (option.customParams) {
customParams = option.customParams;
}
if (option.customId) {
customId = option.customId;
}
}); });
if (transformers.includes("sha256")) { if (transformers.includes("sha256")) {
@@ -663,6 +734,7 @@ const handleElementOptions = (codeName, elementOptions, transformers, val) => {
inputType, inputType,
readOnly, readOnly,
isMultiSelect, isMultiSelect,
isOrdeable,
cssClasses, cssClasses,
placeholder, placeholder,
suffix, suffix,
@@ -672,6 +744,9 @@ const handleElementOptions = (codeName, elementOptions, transformers, val) => {
valRes, valRes,
getStringKey, getStringKey,
onClick, onClick,
onChange,
customParams,
customId
}; };
}; };
@@ -698,8 +773,9 @@ function generateOptions(options, valuesArray, targetField, transformers, placeh
resultArray = [] resultArray = []
selectedArray = [] selectedArray = []
cssClass = "" cssClass = ""
// determine if options or values are used in teh listing // determine if options or values are used in the listing
if (valuesArray.length > 0 && options.length > 0){ if (valuesArray.length > 0 && options.length > 0){
// multiselect list -> options only + selected the ones in valuesArray // multiselect list -> options only + selected the ones in valuesArray
@@ -717,21 +793,31 @@ function generateOptions(options, valuesArray, targetField, transformers, placeh
resultArray = options; resultArray = options;
} }
// Create a map to track the index of each item in valuesArray
const orderMap = new Map(valuesArray.map((item, index) => [item, index]));
// Sort resultArray based on the order in valuesArray
resultArray.sort((a, b) => {
const indexA = orderMap.has(a.id) ? orderMap.get(a.id) : valuesArray.length;
const indexB = orderMap.has(b.id) ? orderMap.get(b.id) : valuesArray.length;
return indexA - indexB;
});
resultArray.forEach(function(item) { resultArray.forEach(function(item) {
let labelName = item.name;
labelName = item.name if (labelName !== '❌None') {
labelName = reverseTransformers(labelName, transformers);
if(labelName != '❌None')
{
labelName = reverseTransformers(labelName, transformers)
} }
// needs to happen always if options ued as source // Always include selected if options are used as a source
let selected = options.length != 0 && valuesArray.includes(item.id) ? 'selected' : ''; let selected = options.length !== 0 && valuesArray.includes(item.id) ? 'selected' : '';
optionsHtml += `<option class="${cssClass}" value="${item.id}" ${selected}>${labelName}</option>`; optionsHtml += `<option class="${cssClass}" value="${item.id}" ${selected}>${labelName}</option>`;
}); });
// Place the resulting HTML into the specified placeholder div // Place the resulting HTML into the specified placeholder div
$("#" + placeholder).replaceWith(optionsHtml); $("#" + placeholder).replaceWith(optionsHtml);
} }

View File

@@ -68,54 +68,65 @@ function initDeviceSelectors(devicesListAll_JSON) {
} }
// ----------------------------------------------
// Updates the icon preview
function updateIconPreview(elem) {
// Retrieve and parse custom parameters from the element
let params = $(elem).attr("my-customparams")?.split(',').map(param => param.trim());
// ----------------------------------------------------------------------------- // console.log(params);
// Hide elements on the page based on the supplied setting
function hideUIelements(settingKey) {
hiddenSectionsSetting = getSetting(settingKey) if (params && params.length >= 2) {
var inputElementID = params[0];
if(hiddenSectionsSetting != "") // handle if settings not yet initialized var targetElementID = params[1];
{ } else {
console.error("Invalid parameters passed to updateIconPreview function");
sectionsArray = createArray(hiddenSectionsSetting) return;
// remove spaces to get IDs
var newArray = $.map(sectionsArray, function(value) {
return value.replace(/\s/g, '');
});
$.each(newArray, function(index, hiddenSection) {
if($('#' + hiddenSection))
{
$('#' + hiddenSection).hide()
}
});
} }
// Get the input element using the inputElementID
let iconInput = $("#" + inputElementID);
if (iconInput.length === 0) {
console.error("Icon input element not found");
return;
}
// Get the initial value and update the target element
let value = iconInput.val();
if (!value) {
console.error("Input value is empty or not defined");
return;
}
if (!targetElementID) {
targetElementID = "txtIcon";
}
// Check if the target element exists, if not find an element with matching custom attribute
let targetElement = $('#' + targetElementID);
if (targetElement.length === 0) {
// Look for an element with my-custom-id attribute equal to targetElementID
targetElement = $('[my-customid="' + targetElementID + '"]');
if (targetElement.length === 0) {
console.error("Neither target element with ID nor element with custom attribute found");
return;
}
}
// Update the target element with decoded base64 value
targetElement.html(atob(value));
// Add event listener to update the icon on input change
iconInput.on('change input', function () {
let newValue = $(this).val();
$('#' + targetElementID).html(atob(newValue));
});
} }
// -----------------------------------------------------------------------------
// Updates the icon preview
function updateIconPreview (inputId) {
// update icon
iconInput = $(inputId)
value = iconInput.val()
iconInput.on('change input', function() {
$('#txtIconFA').html(atob(value))
});
$('#txtIconFA').html(atob(value))
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Generic function to copy text to clipboard // Generic function to copy text to clipboard
@@ -249,6 +260,7 @@ function initSelect2() {
// -------------------------------------------------------- // --------------------------------------------------------
//Initialize Select2 Elements and make them sortable //Initialize Select2 Elements and make them sortable
$(function () { $(function () {
// Iterate over each Select2 dropdown // Iterate over each Select2 dropdown
$('.select2').each(function() { $('.select2').each(function() {
@@ -283,10 +295,15 @@ function initSelect2() {
} }
} }
// try to initialize select2 // init select2 after dom laoded
setTimeout(() => { window.addEventListener("load", function() {
initSelect2() // try to initialize select2
}, 500); setTimeout(() => {
initSelect2()
}, 1000);
});
console.log("init ui_components.js") console.log("init ui_components.js")

View File

@@ -1034,7 +1034,7 @@ var mouse = $.widget("ui.mouse", {
return this.mouseDelayMet; return this.mouseDelayMet;
}, },
// These are placeholder methods, to be overriden by extending plugin // These are placeholder methods, to be overridden by extending plugin
_mouseStart: function(/* event */) {}, _mouseStart: function(/* event */) {},
_mouseDrag: function(/* event */) {}, _mouseDrag: function(/* event */) {},
_mouseStop: function(/* event */) {}, _mouseStop: function(/* event */) {},

View File

@@ -11,25 +11,7 @@
# cvc90 2023 https://github.com/cvc90 GNU GPLv3 # # cvc90 2023 https://github.com/cvc90 GNU GPLv3 #
#---------------------------------------------------------------------------------# #---------------------------------------------------------------------------------#
// Skin selector config ----------------------------------------------------
//
// For security reasons, new language files must be entered into this array.
// The files in the language directory are compared with this array and only
// then accepted.
//
$pia_installed_skins = array('skin-black-light',
'skin-black',
'skin-blue-light',
'skin-blue',
'skin-green-light',
'skin-green',
'skin-purple-light',
'skin-purple',
'skin-red-light',
'skin-red',
'skin-yellow-light',
'skin-yellow');
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
?> ?>
@@ -38,7 +20,7 @@ $pia_installed_skins = array('skin-black-light',
require 'php/templates/header.php'; require 'php/templates/header.php';
?> ?>
<!-- Page ------------------------------------------------------------------ --> <!-- Page ------------------------------------------------------------------ -->
<div class="content-wrapper"> <div class="content-wrapper" id="maintenancePage">
<!-- Content header--------------------------------------------------------- --> <!-- Content header--------------------------------------------------------- -->
<section class="content-header"> <section class="content-header">
@@ -91,34 +73,6 @@ if (count($latestfiles) > 0)
$latestbackup_date = date ("Y-m-d H:i:s", filemtime($latestbackup)); $latestbackup_date = date ("Y-m-d H:i:s", filemtime($latestbackup));
} }
// Skin selector -----------------------------------------------------------------
if (isset($_POST['submit']) && submit && isset($_POST['skinselector_set'])) {
$pia_skin_set_dir = '../db/';
$pia_skin_selector = htmlspecialchars($_POST['skinselector']);
if (in_array($pia_skin_selector, $pia_installed_skins)) {
foreach ($pia_installed_skins as $file) {
unlink ($pia_skin_set_dir.'/setting_'.$file);
}
foreach ($pia_installed_skins as $file) {
if (file_exists($pia_skin_set_dir.'/setting_'.$file)) {
$pia_skin_error = True;
break;
} else {
$pia_skin_error = False;
}
}
if ($pia_skin_error == False) {
$testskin = fopen($pia_skin_set_dir.'setting_'.$pia_skin_selector, 'w');
$pia_skin_test = '';
echo("<meta http-equiv='refresh' content='1'>");
} else {
$pia_skin_test = '';
echo("<meta http-equiv='refresh' content='1'>");
}
}
}
// Table sizes ----------------------------------------------------------------- // Table sizes -----------------------------------------------------------------
$tableSizesHTML = ""; $tableSizesHTML = "";
@@ -142,10 +96,6 @@ while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
$db->close(); $db->close();
// Language selector -----------------------------------------------------------------
?> ?>
<div class="row"> <div class="row">
@@ -219,13 +169,7 @@ $db->close();
<div class="nav-tabs-custom"> <div class="nav-tabs-custom">
<ul class="nav nav-tabs"> <ul class="nav nav-tabs">
<li class="active"> <li class="active">
<a id="tab_Settings_id" href="#tab_Settings" data-toggle="tab">
<i class="fa fa-cogs"></i>
<?= lang('Maintenance_Tools_Tab_UISettings');?>
</a>
</li>
<li>
<a id="tab_DBTools_id" href="#tab_DBTools" data-toggle="tab"> <a id="tab_DBTools_id" href="#tab_DBTools" data-toggle="tab">
<i class="fa fa-toolbox"></i> <i class="fa fa-toolbox"></i>
<?= lang('Maintenance_Tools_Tab_Tools');?> <?= lang('Maintenance_Tools_Tab_Tools');?>
@@ -251,84 +195,7 @@ $db->close();
</li> </li>
</ul> </ul>
<div class="tab-content"> <div class="tab-content">
<div class="tab-pane active" id="tab_Settings"> <div class="tab-pane active" id="tab_DBTools">
<div class="db_info_table">
<div class="db_info_table_row">
<div class="db_tools_table_cell_a" style="text-align: center;">
<form method="post" action="maintenance.php">
<div style="display: inline-block; text-align: center;">
<select name="skinselector" class="form-control bg-green" style="width:160px; margin-bottom:5px;">
<option value=""><?= lang('Maintenance_themeselector_empty');?></option>
<option value="skin-black-light">black light</option>
<option value="skin-black">black</option>
<option value="skin-blue-light">blue light</option>
<option value="skin-blue">blue</option>
<option value="skin-green-light">green light</option>
<option value="skin-green">green</option>
<option value="skin-purple-light">purple light</option>
<option value="skin-purple">purple</option>
<option value="skin-red-light">red light</option>
<option value="skin-red">red</option>
<option value="skin-yellow-light">yellow light</option>
<option value="skin-yellow">yellow</option>
</select></div>
<div style="display: block;"><input type="submit" name="skinselector_set" value="<?= lang('Maintenance_themeselector_apply');?>" class="btn bg-green" style="width:160px;">
<?php // echo $pia_skin_test; ?>
</div>
</form>
</div>
<div class="db_info_table_cell" style="padding: 10px; height:40px; text-align:left; vertical-align: middle;">
<?= lang('Maintenance_themeselector_text'); ?>
</div>
</div>
<div class="db_info_table_row">
<div class="db_tools_table_cell_a">
<button type="button" class="btn bg-green dbtools-button" id="btnToggleDarkmode" onclick="askToggleDarkmode()"><?= lang('Maintenance_Tool_darkmode');?></button>
</div>
<div class="db_tools_table_cell_b"><?= lang('Maintenance_Tool_darkmode_text');?></div>
</div>
<div class="db_info_table_row">
<div class="db_tools_table_cell_a">
<div class="form-group" >
<div class="input-group" >
<select id="columnsSelect" class="form-control select2 select2-hidden-accessible" multiple="" style="width: 100%;" tabindex="-1" aria-hidden="true">
<option value="0"><?= lang('Device_TableHead_Name');?></option>
<option value="1"><?= lang('Device_TableHead_Owner');?></option>
<option value="2"><?= lang('Device_TableHead_Type');?></option>
<option value="3"><?= lang('Device_TableHead_Icon');?></option>
<option value="4"><?= lang('Device_TableHead_Favorite');?></option>
<option value="5"><?= lang('Device_TableHead_Group');?></option>
<option value="6"><?= lang('Device_TableHead_FirstSession');?></option>
<option value="7"><?= lang('Device_TableHead_LastSession');?></option>
<option value="8"><?= lang('Device_TableHead_LastIP');?></option>
<option value="9"><?= lang('Device_TableHead_MAC');?></option>
<option value="10"><?= lang('Device_TableHead_Status');?></option>
<option value="11"><?= lang('Device_TableHead_MAC_full');?></option>
<option value="12"><?= lang('Device_TableHead_LastIPOrder');?></option>
<option value="13"><?= lang('Device_TableHead_Rowid');?></option>
<option value="14"><?= lang('Device_TableHead_Parent_MAC');?></option>
<option value="15"><?= lang('Device_TableHead_Connected_Devices');?></option>
<option value="16"><?= lang('Device_TableHead_Location');?></option>
<option value="17"><?= lang('Device_TableHead_Vendor');?></option>
<option value="18"><?= lang('Device_TableHead_Port');?></option>
<option value="19"><?= lang('Device_TableHead_GUID');?></option>
<option value="20"><?= lang('Device_TableHead_SyncHubNodeName');?></option>
<option value="21"><?= lang('Device_TableHead_NetworkSite');?></option>
<option value="22"><?= lang('Device_TableHead_SSID');?></option>
</select>
<span class="input-group-addon"><i title="<?= lang('Gen_Save');?>" class="fa fa-save pointer" onclick="saveSelectedColumns();"></i></span>
</div>
</div>
</div>
<div class="db_tools_table_cell_b"><?= lang('Maintenance_Tool_displayed_columns_text');?></div>
</div>
</div>
</div>
<div class="tab-pane" id="tab_DBTools">
<div class="db_info_table"> <div class="db_info_table">
<div class="db_info_table_row"> <div class="db_info_table_row">
<div class="db_tools_table_cell_a" > <div class="db_tools_table_cell_a" >
@@ -487,7 +354,7 @@ $db->close();
<script> <script>
var emptyArr = ['undefined', "", undefined, null]; var emptyArr = ['undefined', "", undefined, null];
var selectedTab = 'tab_Settings_id'; var selectedTab = 'tab_DBTools_id';
initializeTabs(); initializeTabs();
@@ -713,42 +580,6 @@ function ImportPastedCSV()
} }
// --------------------------------------------------------
// Switch Darkmode
function askToggleDarkmode() {
// Ask
showModalWarning('<?= lang('Maintenance_Tool_darkmode_noti');?>', '<?= lang('Maintenance_Tool_darkmode_noti_text');?>',
'<?= lang('Gen_Cancel');?>', '<?= lang('Gen_Switch');?>', 'ToggleDarkmode');
}
// --------------------------------------------------------
function ToggleDarkmode()
{
// get parameter Front_Dark_Mode_Enabled value
$.get('php/server/parameters.php?action=get&defaultValue=false&expireMinutes=525600&parameter=Front_Dark_Mode_Enabled', function(data) {
var result = JSON.parse(data);
if (result) {
darkModeEnabled = result == 'true';
// invert value
darkModeEnabled = !darkModeEnabled;
// save inverted value
$.get('php/server/parameters.php?action=set&parameter=Front_Dark_Mode_Enabled&expireMinutes=525600&value='+ darkModeEnabled,
function(data) {
if (data != "OK") {
showMessage (data);
setTimeout(function (){location.reload()}, 1000);
} else {
showMessage (data);
};
} );
}
});
}
// -------------------------------------------------------- // --------------------------------------------------------
// Clean log file // Clean log file
@@ -801,122 +632,56 @@ function scrollDown() {
} }
// --------------------------------------------------------
// Manage displayed columns
// --------------------------------------------------------
colDefaultOrder = ['0','1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16','17'];
colDefaultOrderTxt = '[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17]';
function saveSelectedColumns () {
$.get('php/server/parameters.php?action=set&expireMinutes=525600&value=['+ $('#columnsSelect').val().toString() +']&parameter=Front_Devices_Columns_Visible', function(data) {
// save full order of all columns to simplify mapping later on
colDisplayed = $('#columnsSelect').val();
colNewOrder = colDisplayed;
// append the remaining columns in the previous order
for(i = 0; i < colDefaultOrder.length; i++)
{
if(!colDisplayed.includes(colDefaultOrder[i]))
{
colNewOrder.push(colDefaultOrder[i])
}
}
// save the setting in the DB
$.get('php/server/parameters.php?action=set&expireMinutes=525600&value=['+ colNewOrder.toString() +']&parameter=Front_Devices_Columns_Order', function(data) {
showMessage(data);
});
});
}
// --------------------------------------------------------
function initializeSelectedColumns () {
$.get('php/server/parameters.php?action=get&expireMinutes=525600&defaultValue='+colDefaultOrderTxt+'&parameter=Front_Devices_Columns_Visible', function(data) {
handle_locked_DB(data)
tableColumnShow = numberArrayFromString(data);
for(i=0; i < tableColumnShow.length; i++)
{
// create the option and append to Select2
var option = new Option($('#columnsSelect option[value='+tableColumnShow[i]+']').html(), tableColumnShow[i] , true, true);
$("#columnsSelect").append(option).trigger('change');
}
});
}
// -------------------------------------------------------- // --------------------------------------------------------
// General initialization // General initialization
// -------------------------------------------------------- // --------------------------------------------------------
function initializeTabs () { function initializeTabs() {
setTimeout(() => {
setTimeout(function() { const key = "activeMaintenanceTab";
key = "activeMaintenanceTab"
// default selection // default selection
selectedTab = "tab_Settings" let selectedTab = "tab_DBTools_id";
// the #target from the url // the #target from the URL
target = window.location.hash.substr(1) let target = window.location.hash.substr(1);
console.log(selectedTab);
// get only the part between #...? // get only the part between #...?
if(target.includes('?')) if (target.includes('?')) {
{ target = target.split('?')[0];
target = target.split('?')[0]
} }
console.log(target);
// update cookie if target specified // update cookie if target specified
if(target != "") if (target) {
{ selectedTab = target.endsWith("_id") ? target : `${target}_id`;
setCache(key, selectedTab); // _id is added so it doesn't conflict with AdminLTE tab behavior
if (!selectedTab.endsWith("_id")) {
selectedTab = target + "_id";
}
setCache(key, selectedTab) // _id is added so it doesn't conflict with AdminLTE tab behavior
} }
// get the tab id from the cookie (already overriden by the target) // get the tab id from the cookie (already overridden by the target)
if(!emptyArr.includes(getCache(key))) const cachedTab = getCache(key);
{ if (cachedTab && !emptyArr.includes(cachedTab)) {
selectedTab = getCache(key); selectedTab = cachedTab;
} }
// Activate panel // Activate panel
$('.nav-tabs a[id='+ selectedTab +']').tab('show'); $('.nav-tabs a[id='+ selectedTab +']').tab('show');
// When changed save new current tab // When changed save new current tab
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) { $('a[data-toggle="tab"]').on('shown.bs.tab', (e) => {
setCache(key, $(e.target).attr('id')) const newTabId = $(e.target).attr('id');
setCache(key, newTabId);
}); });
// events on tab change // events on tab change
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) { $('a[data-toggle="tab"]').on('shown.bs.tab', (e) => {
var target = $(e.target).attr("href") // activated tab const newTarget = $(e.target).attr("href"); // activated tab
}); });
hideSpinner(); hideSpinner();
}, 50); }, 50);
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Logs render functionality // Logs render functionality
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@@ -936,7 +701,7 @@ function toggleAutoRefresh() {
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Manages thefilter application // Manages the filter application on the logs
function applyFilter() { function applyFilter() {
const filterText = $("#logsFilter").val().toLowerCase(); const filterText = $("#logsFilter").val().toLowerCase();
@@ -983,7 +748,6 @@ function renderLogs(customData) {
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Init // Init
window.onload = function asyncFooter() { window.onload = function asyncFooter() {
initializeSelectedColumns();
renderLogs(); renderLogs();
// initializeTabs(); // initializeTabs();

View File

@@ -13,7 +13,7 @@
<h3 class="box-title"><?= lang('Gen_Selected_Devices');?></h3> <h3 class="box-title"><?= lang('Gen_Selected_Devices');?></h3>
</div> </div>
<div class="deviceSelector col-md-9" style="z-index:5"></div> <div class="deviceSelector col-md-9 col-sm-12" style="z-index:5"></div>
<div class="col-md-3"> <div class="col-md-3">
<button type="button" class="btn btn-default" onclick="markAllSelected()"> <button type="button" class="btn btn-default" onclick="markAllSelected()">
@@ -101,23 +101,25 @@
for (let j = i * elementsPerColumn; j < Math.min((i + 1) * elementsPerColumn, columns.length); j++) { for (let j = i * elementsPerColumn; j < Math.min((i + 1) * elementsPerColumn, columns.length); j++) {
const setTypeObject = JSON.parse(columns[j].Type.replace(/'/g, '"')); const setTypeObject = JSON.parse(columns[j].Type.replace(/'/g, '"'));
// console.log(setTypeObject); 🔽
// const lastElementObj = setTypeObject.elements[setTypeObject.elements.length - 1]
// get the element with the input value(s) // get the element with the input value(s)
let elementsWithInputValue = setTypeObject.elements.filter(element => element.elementHasInputValue === 1); let elements = setTypeObject.elements.filter(element => element.elementHasInputValue === 1);
// if none found, take last // if none found, take last
if(elementsWithInputValue.length == 0) if(elements.length == 0)
{ {
elementsWithInputValue = setTypeObject.elements[setTypeObject.elements.length - 1] elementWithInputValue = setTypeObject.elements[setTypeObject.elements.length - 1]
} else
{
elementWithInputValue = elements[0]
} }
const { elementType, elementOptions = [], transformers = [] } = elementsWithInputValue; const { elementType, elementOptions = [], transformers = [] } = elementWithInputValue;
const { const {
inputType, inputType,
readOnly, readOnly,
isMultiSelect, isMultiSelect,
isOrdeable,
cssClasses, cssClasses,
placeholder, placeholder,
suffix, suffix,
@@ -126,26 +128,28 @@
editable, editable,
valRes, valRes,
getStringKey, getStringKey,
onClick onClick,
onChange,
customParams,
customId
} = handleElementOptions('none', elementOptions, transformers, val = ""); } = handleElementOptions('none', elementOptions, transformers, val = "");
// console.log(setTypeObject);
// console.log(inputType);
// render based on element type // render based on element type
if (elementsWithInputValue.elementType === 'select') { if (elementType === 'select') {
targetLocation = columns[j].Code_Name + "_generateSetOptions" targetLocation = columns[j].Code_Name + "_generateSetOptions"
generateOptionsOrSetOptions(columns[j].Code_Name, [], targetLocation, generateOptions) generateOptionsOrSetOptions(columns[j].Code_Name, [], targetLocation, generateOptions)
// Handle Icons as tehy need a preview console.log(columns[j].Code_Name)
// Handle Icons as they need a preview
if(columns[j].Code_Name == 'NEWDEV_dev_Icon') if(columns[j].Code_Name == 'NEWDEV_dev_Icon')
{ {
input = ` input = `
<span class="input-group-addon" id="txtIconFA"></span> <span class="input-group-addon iconPreview" my-customid="NEWDEV_dev_Icon_preview"></span>
<select class="form-control" <select class="form-control"
onChange="updateIconPreview('#NEWDEV_dev_Icon')" onChange="updateIconPreview(this)"
my-customparams="NEWDEV_dev_Icon,NEWDEV_dev_Icon_preview"
id="${columns[j].Code_Name}" id="${columns[j].Code_Name}"
data-my-column="${columns[j].Code_Name}" data-my-column="${columns[j].Code_Name}"
data-my-targetColumns="${columns[j].Code_Name.replace('NEWDEV_','')}" > data-my-targetColumns="${columns[j].Code_Name.replace('NEWDEV_','')}" >
@@ -163,7 +167,7 @@
} }
} else if (elementsWithInputValue.elementType === 'input'){ } else if (elementType === 'input'){
// Add classes specifically for checkboxes // Add classes specifically for checkboxes
inputType === 'checkbox' ? inputClass = 'checkbox' : inputClass = 'form-control'; inputType === 'checkbox' ? inputClass = 'checkbox' : inputClass = 'form-control';
@@ -171,6 +175,7 @@
input = `<input class="${inputClass}" input = `<input class="${inputClass}"
id="${columns[j].Code_Name}" id="${columns[j].Code_Name}"
my-customid="${columns[j].Code_Name}"
data-my-column="${columns[j].Code_Name}" data-my-column="${columns[j].Code_Name}"
data-my-targetColumns="${columns[j].Code_Name.replace('NEWDEV_','')}" data-my-targetColumns="${columns[j].Code_Name.replace('NEWDEV_','')}"
type="${inputType}">` type="${inputType}">`

View File

@@ -783,7 +783,7 @@
setCache(key, target.replaceAll(":","_")+'_id') // _id is added so it doesn't conflict with AdminLTE tab behavior setCache(key, target.replaceAll(":","_")+'_id') // _id is added so it doesn't conflict with AdminLTE tab behavior
} }
// get the tab id from the cookie (already overriden by the target) // get the tab id from the cookie (already overridden by the target)
if(!emptyArr.includes(getCache(key))) if(!emptyArr.includes(getCache(key)))
{ {
selectedTab = getCache(key); selectedTab = getCache(key);

View File

@@ -53,7 +53,7 @@
<link rel="stylesheet" href="lib/AdminLTE/bower_components/select2/dist/css/select2.min.css"> <link rel="stylesheet" href="lib/AdminLTE/bower_components/select2/dist/css/select2.min.css">
<!-- NetAlertX --> <!-- NetAlertX -->
<script src="js/handle_version.js"></script> <script defer src="js/handle_version.js"></script>
<script src="js/ui_components.js?v=<?php include 'php/templates/version.php'; ?>"></script> <script src="js/ui_components.js?v=<?php include 'php/templates/version.php'; ?>"></script>

View File

@@ -67,14 +67,16 @@ require dirname(__FILE__).'/security.php';
<link id="favicon" rel="icon" type="image/x-icon" href="img/NetAlertX_logo.png"> <link id="favicon" rel="icon" type="image/x-icon" href="img/NetAlertX_logo.png">
<!-- For better UX on Mobile Devices using the Shortcut on the Homescreen --> <!-- For better UX on Mobile Devices using the Shortcut on the Homescreen -->
<link rel="manifest" href="img/manifest.json"> <link rel="manifest" href="img/manifest.json" crossorigin="use-credentials">
<!-- Dark-Mode Patch --> <!-- Dark-Mode Patch -->
<?php
if ($ENABLED_DARKMODE === True) { <?php
echo '<link rel="stylesheet" href="css/dark-patch.css">'; if ($ENABLED_DARKMODE === True) {
$BACKGROUND_IMAGE_PATCH='style="background-image: url(\'img/boxed-bg-dark.png\');"'; echo '<link rel="stylesheet" href="css/dark-patch.css">';
} else { $BACKGROUND_IMAGE_PATCH='style="background-image: url(\'img/background.png\');"';} $BACKGROUND_IMAGE_PATCH='style="background-image: url(\'img/boxed-bg-dark.png\');"';
?> } else { $BACKGROUND_IMAGE_PATCH='style="background-image: url(\'img/background.png\');"';}
?>
<!-- Servertime to the right of the hostname --> <!-- Servertime to the right of the hostname -->
@@ -312,9 +314,6 @@ if ($ENABLED_DARKMODE === True) {
</span> </span>
</a> </a>
<ul class="treeview-menu" style="display: <?php if (in_array (basename($_SERVER['SCRIPT_NAME']), array('maintenance.php') ) ){ echo 'block'; } else {echo 'none';} ?>;"> <ul class="treeview-menu" style="display: <?php if (in_array (basename($_SERVER['SCRIPT_NAME']), array('maintenance.php') ) ){ echo 'block'; } else {echo 'none';} ?>;">
<li>
<a href="maintenance.php#tab_Settings" onclick="initializeTabs()"> <?= lang("Maintenance_Tools_Tab_UISettings");?> </a>
</li>
<li> <li>
<a href="maintenance.php#tab_DBTools" onclick="initializeTabs()"> <?= lang("Maintenance_Tools_Tab_Tools");?> </a> <a href="maintenance.php#tab_DBTools" onclick="initializeTabs()"> <?= lang("Maintenance_Tools_Tab_Tools");?> </a>
</li> </li>

View File

@@ -56,6 +56,8 @@
"BackDevices_Restore_okay": "", "BackDevices_Restore_okay": "",
"BackDevices_darkmode_disabled": "", "BackDevices_darkmode_disabled": "",
"BackDevices_darkmode_enabled": "", "BackDevices_darkmode_enabled": "",
"CLEAR_NEW_FLAG_description": "",
"CLEAR_NEW_FLAG_name": "",
"DAYS_TO_KEEP_EVENTS_description": "", "DAYS_TO_KEEP_EVENTS_description": "",
"DAYS_TO_KEEP_EVENTS_name": "", "DAYS_TO_KEEP_EVENTS_name": "",
"DevDetail_Copy_Device_Title": "", "DevDetail_Copy_Device_Title": "",
@@ -274,6 +276,7 @@
"Gen_AreYouSure": "", "Gen_AreYouSure": "",
"Gen_Backup": "", "Gen_Backup": "",
"Gen_Cancel": "", "Gen_Cancel": "",
"Gen_Change": "",
"Gen_Copy": "", "Gen_Copy": "",
"Gen_DataUpdatedUITakesTime": "", "Gen_DataUpdatedUITakesTime": "",
"Gen_Delete": "", "Gen_Delete": "",
@@ -292,6 +295,7 @@
"Gen_Save": "", "Gen_Save": "",
"Gen_Saved": "", "Gen_Saved": "",
"Gen_Search": "", "Gen_Search": "",
"Gen_SelectToPreview": "",
"Gen_Selected_Devices": "", "Gen_Selected_Devices": "",
"Gen_Switch": "", "Gen_Switch": "",
"Gen_Upd": "", "Gen_Upd": "",
@@ -556,6 +560,7 @@
"RandomMAC_hover": "", "RandomMAC_hover": "",
"Reports_Sent_Log": "", "Reports_Sent_Log": "",
"SCAN_SUBNETS_description": "", "SCAN_SUBNETS_description": "",
"SCAN_SUBNETS_name": "",
"SYSTEM_TITLE": "", "SYSTEM_TITLE": "",
"Setting_Override": "", "Setting_Override": "",
"Setting_Override_Description": "", "Setting_Override_Description": "",
@@ -654,6 +659,8 @@
"UI_PRESENCE_name": "", "UI_PRESENCE_name": "",
"UI_REFRESH_description": "", "UI_REFRESH_description": "",
"UI_REFRESH_name": "", "UI_REFRESH_name": "",
"VERSION_description": "",
"VERSION_name": "",
"devices_old": "", "devices_old": "",
"general_event_description": "", "general_event_description": "",
"general_event_title": "", "general_event_title": "",

View File

@@ -68,6 +68,8 @@
"BackDevices_Restore_okay": "Die Wiederherstellung wurde erfolgreich ausgeführt.", "BackDevices_Restore_okay": "Die Wiederherstellung wurde erfolgreich ausgeführt.",
"BackDevices_darkmode_disabled": "Heller Modus aktiviert.", "BackDevices_darkmode_disabled": "Heller Modus aktiviert.",
"BackDevices_darkmode_enabled": "Dunkler Modus aktiviert.", "BackDevices_darkmode_enabled": "Dunkler Modus aktiviert.",
"CLEAR_NEW_FLAG_description": "",
"CLEAR_NEW_FLAG_name": "",
"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_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": "Lösche Events älter als", "DAYS_TO_KEEP_EVENTS_name": "Lösche Events älter als",
"DevDetail_Copy_Device_Title": "<i class=\"fa fa-copy\"></i> Details von Gerät kopieren", "DevDetail_Copy_Device_Title": "<i class=\"fa fa-copy\"></i> Details von Gerät kopieren",
@@ -286,6 +288,7 @@
"Gen_AreYouSure": "Sind Sie sich sicher?", "Gen_AreYouSure": "Sind Sie sich sicher?",
"Gen_Backup": "Sichern", "Gen_Backup": "Sichern",
"Gen_Cancel": "Abbrechen", "Gen_Cancel": "Abbrechen",
"Gen_Change": "",
"Gen_Copy": "Run", "Gen_Copy": "Run",
"Gen_DataUpdatedUITakesTime": "OK - It may take a while for the UI to update if a scan is runnig", "Gen_DataUpdatedUITakesTime": "OK - It may take a while for the UI to update if a scan is runnig",
"Gen_Delete": "Löschen", "Gen_Delete": "Löschen",
@@ -304,6 +307,7 @@
"Gen_Save": "Speichern", "Gen_Save": "Speichern",
"Gen_Saved": "Gespeichert", "Gen_Saved": "Gespeichert",
"Gen_Search": "Suchen", "Gen_Search": "Suchen",
"Gen_SelectToPreview": "",
"Gen_Selected_Devices": "Ausgewählte Geräte:", "Gen_Selected_Devices": "Ausgewählte Geräte:",
"Gen_Switch": "Umschalten", "Gen_Switch": "Umschalten",
"Gen_Upd": "Aktualisierung erfolgreich", "Gen_Upd": "Aktualisierung erfolgreich",
@@ -611,6 +615,7 @@
"RandomMAC_hover": "Autodetected - indicates if the device randomizes it's MAC address.", "RandomMAC_hover": "Autodetected - indicates if the device randomizes it's MAC address.",
"Reports_Sent_Log": "Protokoll gesendeter Berichte", "Reports_Sent_Log": "Protokoll gesendeter Berichte",
"SCAN_SUBNETS_description": "", "SCAN_SUBNETS_description": "",
"SCAN_SUBNETS_name": "",
"SMTP_FORCE_SSL_description": "Force SSL when connecting to your SMTP server.", "SMTP_FORCE_SSL_description": "Force SSL when connecting to your SMTP server.",
"SMTP_FORCE_SSL_name": "Force SSL", "SMTP_FORCE_SSL_name": "Force SSL",
"SMTP_PASS_description": "The SMTP server password. ", "SMTP_PASS_description": "The SMTP server password. ",
@@ -723,6 +728,8 @@
"UI_PRESENCE_name": "Anzeige im Präsenzdiagramm", "UI_PRESENCE_name": "Anzeige im Präsenzdiagramm",
"UI_REFRESH_description": "", "UI_REFRESH_description": "",
"UI_REFRESH_name": "Automatisch Aktualisieren", "UI_REFRESH_name": "Automatisch Aktualisieren",
"VERSION_description": "",
"VERSION_name": "",
"WEBHOOK_PAYLOAD_description": "The Webhook payload data format for the <code>body</code> > <code>attachments</code> > <code>text</code> attribute in the payload json. See an example of the payload <a target=\"_blank\" href=\"https://github.com/jokob-sk/NetAlertX/blob/main/front/report_templates/webhook_json_sample.json\">here</a>. (e.g.: for discord use <code>text</code>)", "WEBHOOK_PAYLOAD_description": "The Webhook payload data format for the <code>body</code> > <code>attachments</code> > <code>text</code> attribute in the payload json. See an example of the payload <a target=\"_blank\" href=\"https://github.com/jokob-sk/NetAlertX/blob/main/front/report_templates/webhook_json_sample.json\">here</a>. (e.g.: for discord use <code>text</code>)",
"WEBHOOK_PAYLOAD_name": "Payload type", "WEBHOOK_PAYLOAD_name": "Payload type",
"WEBHOOK_REQUEST_METHOD_description": "The HTTP request method to be used for the webhook call.", "WEBHOOK_REQUEST_METHOD_description": "The HTTP request method to be used for the webhook call.",
@@ -771,4 +778,4 @@
"settings_update_item_warning": "", "settings_update_item_warning": "",
"test_event_icon": "fa-vial-circle-check", "test_event_icon": "fa-vial-circle-check",
"test_event_tooltip": "Save your changes at first before you test your settings." "test_event_tooltip": "Save your changes at first before you test your settings."
} }

View File

@@ -56,6 +56,8 @@
"BackDevices_Restore_okay": "Restore executed successfully.", "BackDevices_Restore_okay": "Restore executed successfully.",
"BackDevices_darkmode_disabled": "Darkmode Disabled", "BackDevices_darkmode_disabled": "Darkmode Disabled",
"BackDevices_darkmode_enabled": "Darkmode Enabled", "BackDevices_darkmode_enabled": "Darkmode Enabled",
"CLEAR_NEW_FLAG_description": "If enabled (<code>0</code> is disabled), devices flagged as <b>New Device</b> will be unflagged if the time limit (specified in hours) exceeds their <b>First Session</b> time.",
"CLEAR_NEW_FLAG_name": "Clear new flag",
"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_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", "DAYS_TO_KEEP_EVENTS_name": "Delete events older than",
"DevDetail_Copy_Device_Title": "<i class=\"fa fa-copy\"></i> Copy details from device", "DevDetail_Copy_Device_Title": "<i class=\"fa fa-copy\"></i> Copy details from device",
@@ -274,6 +276,7 @@
"Gen_AreYouSure": "Are you sure?", "Gen_AreYouSure": "Are you sure?",
"Gen_Backup": "Run Backup", "Gen_Backup": "Run Backup",
"Gen_Cancel": "Cancel", "Gen_Cancel": "Cancel",
"Gen_Change": "Change",
"Gen_Copy": "Run", "Gen_Copy": "Run",
"Gen_DataUpdatedUITakesTime": "OK - It may take a while for the UI to update if a scan is running.", "Gen_DataUpdatedUITakesTime": "OK - It may take a while for the UI to update if a scan is running.",
"Gen_Delete": "Delete", "Gen_Delete": "Delete",
@@ -292,6 +295,7 @@
"Gen_Save": "Save", "Gen_Save": "Save",
"Gen_Saved": "Saved", "Gen_Saved": "Saved",
"Gen_Search": "Search", "Gen_Search": "Search",
"Gen_SelectToPreview": "Select to preview",
"Gen_Selected_Devices": "Selected Devices:", "Gen_Selected_Devices": "Selected Devices:",
"Gen_Switch": "Switch", "Gen_Switch": "Switch",
"Gen_Upd": "Updated successfully", "Gen_Upd": "Updated successfully",
@@ -302,8 +306,8 @@
"Gen_Work_In_Progress": "Work in progress, good time to feedback on https://github.com/jokob-sk/NetAlertX/issues", "Gen_Work_In_Progress": "Work in progress, good time to feedback on https://github.com/jokob-sk/NetAlertX/issues",
"General_display_name": "General", "General_display_name": "General",
"General_icon": "<i class=\"fa fa-gears\"></i>", "General_icon": "<i class=\"fa fa-gears\"></i>",
"HRS_TO_KEEP_NEWDEV_description": "This is a maintenance setting. If enabled (<code>0</code> is disabled), devices marked as <b>New Device</b> will be deleted if their <b>First Session</b> time was older than the specified hours in this setting. Use this setting if you want to auto-delete <b>New Devices</b> after <code>X</code> hours.", "HRS_TO_KEEP_NEWDEV_description": "This is a maintenance setting <b>DELETING devices</b>. If enabled (<code>0</code> is disabled), devices marked as <b>New Device</b> will be deleted if their <b>First Session</b> time was older than the specified hours in this setting. Use this setting if you want to auto-delete <b>New Devices</b> after <code>X</code> hours.",
"HRS_TO_KEEP_NEWDEV_name": "Keep new devices for", "HRS_TO_KEEP_NEWDEV_name": "Delete new devices after",
"HelpFAQ_Cat_Detail": "Details", "HelpFAQ_Cat_Detail": "Details",
"HelpFAQ_Cat_Detail_300_head": "What means ", "HelpFAQ_Cat_Detail_300_head": "What means ",
"HelpFAQ_Cat_Detail_300_text_a": "means a network device (a device of the type AP, Gateway, Firewall, Hypervisor, Powerline, Switch, WLAN, PLC, Router,USB LAN Adapter, USB WIFI Adapter, or Internet). Custom types can be added via the <code>NETWORK_DEVICE_TYPES</code> setting.", "HelpFAQ_Cat_Detail_300_text_a": "means a network device (a device of the type AP, Gateway, Firewall, Hypervisor, Powerline, Switch, WLAN, PLC, Router,USB LAN Adapter, USB WIFI Adapter, or Internet). Custom types can be added via the <code>NETWORK_DEVICE_TYPES</code> setting.",
@@ -556,6 +560,7 @@
"RandomMAC_hover": "Autodetected - indicates if the device randomizes it's MAC address.", "RandomMAC_hover": "Autodetected - indicates if the device randomizes it's MAC address.",
"Reports_Sent_Log": "Sent Reports Log", "Reports_Sent_Log": "Sent Reports Log",
"SCAN_SUBNETS_description": "Most on-network scanners (ARP-SCAN, NMAP, NSLOOKUP, DIG, PHOLUS) rely on scanning specific network interfaces and subnets. Check the <a href=\"https://github.com/jokob-sk/NetAlertX/blob/main/docs/SUBNETS.md\" target=\"_blank\">subnets documentation</a> for help on this setting, especially VLANs, what VLANs are supported, or how to figure out the network mask and your interface. <br/> <br/> An alternative to on-network scanners is to enable some other Device scanners/importers that don't rely on NetAlert<sup>X</sup> having access to the network (UNIFI, dhcp.leases, PiHole, etc.). <br/> <br/> Note: The scan time itself depends on the number of IP addresses to check, so set this up carefully with the appropriate network mask and interface.", "SCAN_SUBNETS_description": "Most on-network scanners (ARP-SCAN, NMAP, NSLOOKUP, DIG, PHOLUS) rely on scanning specific network interfaces and subnets. Check the <a href=\"https://github.com/jokob-sk/NetAlertX/blob/main/docs/SUBNETS.md\" target=\"_blank\">subnets documentation</a> for help on this setting, especially VLANs, what VLANs are supported, or how to figure out the network mask and your interface. <br/> <br/> An alternative to on-network scanners is to enable some other Device scanners/importers that don't rely on NetAlert<sup>X</sup> having access to the network (UNIFI, dhcp.leases, PiHole, etc.). <br/> <br/> Note: The scan time itself depends on the number of IP addresses to check, so set this up carefully with the appropriate network mask and interface.",
"SCAN_SUBNETS_name": "Networks to scan",
"SYSTEM_TITLE": "System Information", "SYSTEM_TITLE": "System Information",
"Setting_Override": "Override value", "Setting_Override": "Override value",
"Setting_Override_Description": "Enabling this option will override an App supplied default value with the value specified above.", "Setting_Override_Description": "Enabling this option will override an App supplied default value with the value specified above.",
@@ -654,6 +659,8 @@
"UI_PRESENCE_name": "Show in presence chart", "UI_PRESENCE_name": "Show in presence chart",
"UI_REFRESH_description": "Enter number of seconds after which the UI reloads. Set to <code>0</code> to disable.", "UI_REFRESH_description": "Enter number of seconds after which the UI reloads. Set to <code>0</code> to disable.",
"UI_REFRESH_name": "Auto-refresh UI", "UI_REFRESH_name": "Auto-refresh UI",
"VERSION_description": "Version or timestamp helper value to check if app was upgraded.",
"VERSION_name": "Version or timestamp",
"devices_old": "Refreshing...", "devices_old": "Refreshing...",
"general_event_description": "The event you have triggered might take a while until background processes finish. The execution ended once the below execution queue empties (Check the <a href='/maintenance.php#tab_Logging'>error log</a> if you encounter issues). <br/> <br/> Execution queue:", "general_event_description": "The event you have triggered might take a while until background processes finish. The execution ended once the below execution queue empties (Check the <a href='/maintenance.php#tab_Logging'>error log</a> if you encounter issues). <br/> <br/> Execution queue:",
"general_event_title": "Executing an ad-hoc event", "general_event_title": "Executing an ad-hoc event",

View File

@@ -66,6 +66,8 @@
"BackDevices_Restore_okay": "Restauración ejecutado con éxito.", "BackDevices_Restore_okay": "Restauración ejecutado con éxito.",
"BackDevices_darkmode_disabled": "Darkmode Desactivado", "BackDevices_darkmode_disabled": "Darkmode Desactivado",
"BackDevices_darkmode_enabled": "Darkmode Activado", "BackDevices_darkmode_enabled": "Darkmode Activado",
"CLEAR_NEW_FLAG_description": "Si está habilitado (<code>0</code> está desactivado), los dispositivos marcados como <b>Nuevo dispositivo</b> se desmarcarán si el límite de tiempo (especificado en horas) excede su tiempo de <b>primera sesión</b>.",
"CLEAR_NEW_FLAG_name": "Eliminar la nueva bandera",
"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_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", "DAYS_TO_KEEP_EVENTS_name": "Eliminar eventos anteriores a",
"DevDetail_Copy_Device_Title": "<i class=\"fa fa-copy\"></i> Copiar detalles del dispositivo", "DevDetail_Copy_Device_Title": "<i class=\"fa fa-copy\"></i> Copiar detalles del dispositivo",
@@ -284,6 +286,7 @@
"Gen_AreYouSure": "¿Estás seguro?", "Gen_AreYouSure": "¿Estás seguro?",
"Gen_Backup": "Ejecutar copia de seguridad", "Gen_Backup": "Ejecutar copia de seguridad",
"Gen_Cancel": "Cancelar", "Gen_Cancel": "Cancelar",
"Gen_Change": "Cambiar",
"Gen_Copy": "Ejecutar", "Gen_Copy": "Ejecutar",
"Gen_DataUpdatedUITakesTime": "Correcto - La interfaz puede tardar en actualizarse si se está ejecutando un escaneo.", "Gen_DataUpdatedUITakesTime": "Correcto - La interfaz puede tardar en actualizarse si se está ejecutando un escaneo.",
"Gen_Delete": "Eliminar", "Gen_Delete": "Eliminar",
@@ -302,6 +305,7 @@
"Gen_Save": "Guardar", "Gen_Save": "Guardar",
"Gen_Saved": "Guardado", "Gen_Saved": "Guardado",
"Gen_Search": "Buscar", "Gen_Search": "Buscar",
"Gen_SelectToPreview": "Seleccionar para previsualizar",
"Gen_Selected_Devices": "Dispositivos seleccionados:", "Gen_Selected_Devices": "Dispositivos seleccionados:",
"Gen_Switch": "Cambiar", "Gen_Switch": "Cambiar",
"Gen_Upd": "Actualizado correctamente", "Gen_Upd": "Actualizado correctamente",
@@ -312,8 +316,8 @@
"Gen_Work_In_Progress": "Trabajo en curso, un buen momento para hacer comentarios en https://github.com/jokob-sk/NetAlertX/issues", "Gen_Work_In_Progress": "Trabajo en curso, un buen momento para hacer comentarios en https://github.com/jokob-sk/NetAlertX/issues",
"General_display_name": "General", "General_display_name": "General",
"General_icon": "<i class=\"fa fa-gears\"></i>", "General_icon": "<i class=\"fa fa-gears\"></i>",
"HRS_TO_KEEP_NEWDEV_description": "Esta es una configuración de mantenimiento. Si está habilitado (<code>0</code> está deshabilitado), los dispositivos marcados como <b>Nuevo dispositivo</b> se eliminarán si su <b>Primera sesión</b> el tiempo era anterior a las horas especificadas en esta configuración. Utilice esta configuración si desea eliminar automáticamente <b>Nuevos dispositivos</b> después de <code>X</code> horas.", "HRS_TO_KEEP_NEWDEV_description": "Se trata de una configuración de mantenimiento <b>BORRAR dispositivos</b>. Si está activado (<code>0</code> está desactivado), los dispositivos marcados como <b>Nuevo dispositivo</b> se eliminarán si su fecha de <b>primera sesión</b> es anterior a las horas especificadas en este ajuste. Use este ajuste si desea eliminar automáticamente <b>Nuevos dispositivos</b> después de <code>X</code> horas.",
"HRS_TO_KEEP_NEWDEV_name": "Guardar nuevos dispositivos para", "HRS_TO_KEEP_NEWDEV_name": "Eliminar nuevos dispositivos después",
"HelpFAQ_Cat_Detail": "Detalles", "HelpFAQ_Cat_Detail": "Detalles",
"HelpFAQ_Cat_Detail_300_head": "¿Qué significa? ", "HelpFAQ_Cat_Detail_300_head": "¿Qué significa? ",
"HelpFAQ_Cat_Detail_300_text_a": "significa un dispositivo de red (un dispositivo del tipo AP, Gateway, Firewall, Hypervisor, Powerline, Switch, WLAN, PLC, Router,Adaptador LAN USB, Adaptador WIFI USB o Internet). Los tipos personalizados pueden añadirse mediante el ajuste <code>NETWORK_DEVICE_TYPES</code>.", "HelpFAQ_Cat_Detail_300_text_a": "significa un dispositivo de red (un dispositivo del tipo AP, Gateway, Firewall, Hypervisor, Powerline, Switch, WLAN, PLC, Router,Adaptador LAN USB, Adaptador WIFI USB o Internet). Los tipos personalizados pueden añadirse mediante el ajuste <code>NETWORK_DEVICE_TYPES</code>.",
@@ -723,6 +727,8 @@
"UI_PRESENCE_name": "Mostrar en el gráfico de presencia", "UI_PRESENCE_name": "Mostrar en el gráfico de presencia",
"UI_REFRESH_description": "Ingrese el número de segundos después de los cuales se recarga la interfaz de usuario. Ajustado a <code> 0 </code> para desactivar.", "UI_REFRESH_description": "Ingrese el número de segundos después de los cuales se recarga la interfaz de usuario. Ajustado a <code> 0 </code> para desactivar.",
"UI_REFRESH_name": "Actualización automática de la interfaz de usuario", "UI_REFRESH_name": "Actualización automática de la interfaz de usuario",
"VERSION_description": "Valor de ayuda de versión o marca de tiempo para comprobar si la aplicación se ha actualizado.",
"VERSION_name": "Versión o marca de tiempo",
"WEBHOOK_PAYLOAD_description": "El formato de datos de carga de Webhook para el atributo <code>body</code> > <code>attachments</code> > <code>text</code> en el json de carga. Vea un ejemplo de la carga <a target=\"_blank\" href=\"https://github.com/jokob-sk/NetAlertX/blob/main/front/report_templates/webhook_json_sample.json\">aquí</a>. (por ejemplo: para discord use <code>text</code>)", "WEBHOOK_PAYLOAD_description": "El formato de datos de carga de Webhook para el atributo <code>body</code> > <code>attachments</code> > <code>text</code> en el json de carga. Vea un ejemplo de la carga <a target=\"_blank\" href=\"https://github.com/jokob-sk/NetAlertX/blob/main/front/report_templates/webhook_json_sample.json\">aquí</a>. (por ejemplo: para discord use <code>text</code>)",
"WEBHOOK_PAYLOAD_name": "Tipo de carga", "WEBHOOK_PAYLOAD_name": "Tipo de carga",
"WEBHOOK_REQUEST_METHOD_description": "El método de solicitud HTTP que se utilizará para la llamada de webhook.", "WEBHOOK_REQUEST_METHOD_description": "El método de solicitud HTTP que se utilizará para la llamada de webhook.",
@@ -735,7 +741,7 @@
"Webhooks_icon": "<i class=\"fa fa-circle-nodes\"></i>", "Webhooks_icon": "<i class=\"fa fa-circle-nodes\"></i>",
"Webhooks_settings_group": "<i class=\"fa fa-circle-nodes\"></i> Webhooks", "Webhooks_settings_group": "<i class=\"fa fa-circle-nodes\"></i> Webhooks",
"devices_old": "Volviendo a actualizar....", "devices_old": "Volviendo a actualizar....",
"general_event_description": "El evento que ha desencadenado puede tardar un tiempo hasta que finalicen los procesos en segundo plano. La ejecución finalizó una vez que se vac la siguiente cola de ejecución (compruebe el registro de errores <a href='/maintenance.php#tab_Logging'>si</a> tiene problemas). <br/> <br/> Cola de ejecución:", "general_event_description": "El evento que ha activado puede tardar un poco hasta que finalicen los procesos en segundo plano. La ejecución finalizó una vez que se vacía la cola de ejecución a continuación (consulte el <a href='/maintenance.php#tab_Logging'>registro de errores</a> si encuentra problemas). <br/> <br/> Cola de ejecución:",
"general_event_title": "Ejecutar un evento ad-hoc", "general_event_title": "Ejecutar un evento ad-hoc",
"report_guid": "Guía de las notificaciones:", "report_guid": "Guía de las notificaciones:",
"report_guid_missing": "No se ha encontrado la notificación vinculada. Hay un pequeño retraso entre las notificaciones enviadas recientemente y su disponibilidad. Actualiza tu página y la caché después de unos segundos. También es posible que la notificación seleccionada se haya eliminado durante el mantenimiento, tal y como se especifica en la configuración <code>de DBCLNP_NOTIFI_HIST</code>. <br/> <br/>En su lugar, se muestra la notificación más reciente. La notificación que falta tiene el siguiente GUID:", "report_guid_missing": "No se ha encontrado la notificación vinculada. Hay un pequeño retraso entre las notificaciones enviadas recientemente y su disponibilidad. Actualiza tu página y la caché después de unos segundos. También es posible que la notificación seleccionada se haya eliminado durante el mantenimiento, tal y como se especifica en la configuración <code>de DBCLNP_NOTIFI_HIST</code>. <br/> <br/>En su lugar, se muestra la notificación más reciente. La notificación que falta tiene el siguiente GUID:",
@@ -770,4 +776,4 @@
"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>", "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_icon": "fa-vial-circle-check", "test_event_icon": "fa-vial-circle-check",
"test_event_tooltip": "Guarda tus cambios antes de probar nuevos ajustes." "test_event_tooltip": "Guarda tus cambios antes de probar nuevos ajustes."
} }

View File

@@ -1,40 +1,40 @@
{ {
"API_CUSTOM_SQL_description": "Vous pouvez specifier votre propre requête SQL qui retournera un fichier JSON et l'exposer via <a href=\"/api/table_custom_endpoint.json\" target=\"_blank\"><code>table_custom_endpoint.json</code> file endpoint</a>.", "API_CUSTOM_SQL_description": "Vous pouvez spécifier votre propre requête SQL qui retournera un fichier JSON et l'exposer via <a href=\"/api/table_custom_endpoint.json\" target=\"_blank\"><code>table_custom_endpoint.json</code> le point de terminaison de fichier</a>.",
"API_CUSTOM_SQL_name": "Point de terminaison personnalisé", "API_CUSTOM_SQL_name": "Point de terminaison personnalisé",
"API_display_name": "API", "API_display_name": "API",
"API_icon": "<i class=\"fa fa-arrow-down-up-across-line\"></i>", "API_icon": "<i class=\"fa fa-arrow-down-up-across-line\"></i>",
"About_Design": "Conçu pour:", "About_Design": "Conçu pour:",
"About_Exit": "Quitter", "About_Exit": "Se déconnecter",
"About_Title": "Analyse de la sécurité du réseau et cadre de notification", "About_Title": "Analyse de la sécurité du réseau et cadre de notification",
"AppEvents_DateTimeCreated": "Journalisé", "AppEvents_DateTimeCreated": "Connecté",
"AppEvents_Extra": "Extra", "AppEvents_Extra": "Extra",
"AppEvents_GUID": "GUID dévénement dapplication", "AppEvents_GUID": "GUID dévénements de l'application",
"AppEvents_Helper1": "Assistant 1", "AppEvents_Helper1": "Assistant 1",
"AppEvents_Helper2": "Assistant 2", "AppEvents_Helper2": "Assistant 2",
"AppEvents_Helper3": "Assistant 3", "AppEvents_Helper3": "Assistant 3",
"AppEvents_ObjectForeignKey": "Clé étrangère", "AppEvents_ObjectForeignKey": "Clé étrangère",
"AppEvents_ObjectIndex": "Index", "AppEvents_ObjectIndex": "Index",
"AppEvents_ObjectIsArchived": "Est archivé (au moment de l'enregistrement)", "AppEvents_ObjectIsArchived": "Est archivé (au moment de l'enregistrement)",
"AppEvents_ObjectIsNew": "nouveau (au moment de l'enregistrement dans le journal)", "AppEvents_ObjectIsNew": "Nouveau (au moment de l'enregistrement)",
"AppEvents_ObjectPlugin": "Greffon lié", "AppEvents_ObjectPlugin": "Plugin lié",
"AppEvents_ObjectPrimaryID": "Identité primaire", "AppEvents_ObjectPrimaryID": "Identité primaire",
"AppEvents_ObjectSecondaryID": "Indentité secondaire", "AppEvents_ObjectSecondaryID": "Identité secondaire",
"AppEvents_ObjectStatus": "Status (au moment de l'enregistrement)", "AppEvents_ObjectStatus": "État (au moment de l'enregistrement)",
"AppEvents_ObjectStatusColumn": "Colonne d'état", "AppEvents_ObjectStatusColumn": "Colonne d'état",
"AppEvents_ObjectType": "Type d'objet", "AppEvents_ObjectType": "Type d'objet",
"AppEvents_Plugin": "Greffon", "AppEvents_Plugin": "Plugin",
"AppEvents_Type": "Type", "AppEvents_Type": "Type",
"BackDevDetail_Actions_Ask_Run": "Voulez vous executer cette commande?", "BackDevDetail_Actions_Ask_Run": "Voulez-vous exécuter cette action?",
"BackDevDetail_Actions_Not_Registered": "Action non enregistrée ", "BackDevDetail_Actions_Not_Registered": "Action non enregistrée: ",
"BackDevDetail_Actions_Title_Run": "Execute Action", "BackDevDetail_Actions_Title_Run": "Lancer l'action",
"BackDevDetail_Copy_Ask": "Copie les details des objets selectioné dans la liste (tout ce qui est sur cette page sura remplacé)?", "BackDevDetail_Copy_Ask": "Copier les détails des objets sélectionnés dans la liste (tout ce qui est présent sur cette page sera remplacé)?",
"BackDevDetail_Copy_Title": "Copier les détails", "BackDevDetail_Copy_Title": "Copier les détails",
"BackDevDetail_Tools_WOL_error": "Cette commande N'A PAS été exécutée.", "BackDevDetail_Tools_WOL_error": "Cette commande N'A PAS été exécutée.",
"BackDevDetail_Tools_WOL_okay": "Commande Exécutée.", "BackDevDetail_Tools_WOL_okay": "Commande exécutée.",
"BackDevices_Arpscan_disabled": "Arp-Scan Suspendu", "BackDevices_Arpscan_disabled": "Scan ARP suspendu",
"BackDevices_Arpscan_enabled": "Apr-Scan Activé", "BackDevices_Arpscan_enabled": "Scan ARP activé",
"BackDevices_Backup_CopError": "La base de donnée initiale n'a pas pu être sauvegardée.", "BackDevices_Backup_CopError": "La base de données initiale n'a pas pu être sauvegardée.",
"BackDevices_Backup_Failed": "La sauvegarde a été partiellement complétée. L'archive n'a pas pu être crée ou est vide.", "BackDevices_Backup_Failed": "La sauvegarde a été partiellement réalisée. L'archive n'a pas pu être créée ou est vide.",
"BackDevices_Backup_okay": "La sauvegarde s'est déroulée avec succès avec la nouvelle archive", "BackDevices_Backup_okay": "La sauvegarde s'est déroulée avec succès avec la nouvelle archive",
"BackDevices_DBTools_DelDevError_a": "Erreur lors de la suppression de l'appareil", "BackDevices_DBTools_DelDevError_a": "Erreur lors de la suppression de l'appareil",
"BackDevices_DBTools_DelDevError_b": "Erreur lors de la suppression des appareils", "BackDevices_DBTools_DelDevError_b": "Erreur lors de la suppression des appareils",
@@ -42,7 +42,7 @@
"BackDevices_DBTools_DelDev_b": "Appareils supprimés", "BackDevices_DBTools_DelDev_b": "Appareils supprimés",
"BackDevices_DBTools_DelEvents": "Événements supprimés", "BackDevices_DBTools_DelEvents": "Événements supprimés",
"BackDevices_DBTools_DelEventsError": "Erreur lors de la suppression des événements", "BackDevices_DBTools_DelEventsError": "Erreur lors de la suppression des événements",
"BackDevices_DBTools_ImportCSV": "Les appareils du fichier CSV ont été importés avec succès.", "BackDevices_DBTools_ImportCSV": "Les appareils ont été importés depuis le fichier CSV avec succès.",
"BackDevices_DBTools_ImportCSVError": "Le fichier CSV n'a pas pu être importé. Assurez-vous que le format est correct.", "BackDevices_DBTools_ImportCSVError": "Le fichier CSV n'a pas pu être importé. Assurez-vous que le format est correct.",
"BackDevices_DBTools_ImportCSVMissing": "Le fichier CSV est introuvable sous <b>/config/devices.csv.</b>", "BackDevices_DBTools_ImportCSVMissing": "Le fichier CSV est introuvable sous <b>/config/devices.csv.</b>",
"BackDevices_DBTools_Purge": "Les sauvegardes les plus anciennes ont été supprimées", "BackDevices_DBTools_Purge": "Les sauvegardes les plus anciennes ont été supprimées",
@@ -50,32 +50,34 @@
"BackDevices_DBTools_UpdDevError": "Erreur lors de la mise à jour de l'appareil", "BackDevices_DBTools_UpdDevError": "Erreur lors de la mise à jour de l'appareil",
"BackDevices_DBTools_Upgrade": "Base de données mise à niveau avec succès", "BackDevices_DBTools_Upgrade": "Base de données mise à niveau avec succès",
"BackDevices_DBTools_UpgradeError": "La mise à niveau de la base de données a échoué", "BackDevices_DBTools_UpgradeError": "La mise à niveau de la base de données a échoué",
"BackDevices_Device_UpdDevError": "Erreur de mise à jour des appareils, essayez plus tard. La base de données est probablement bloquée en raison d'une tâche en cours.", "BackDevices_Device_UpdDevError": "Erreur de mise à jour des appareils, essayez plus tard. La base de données est probablement verrouillée en raison d'une tâche en cours.",
"BackDevices_Restore_CopError": "La base de données originale n'a pas pu être sauvegardée.", "BackDevices_Restore_CopError": "La base de données originale n'a pas pu être sauvegardée.",
"BackDevices_Restore_Failed": "Échec de la restauration. Veuillez restaurer la sauvegarde manuellement.", "BackDevices_Restore_Failed": "Échec de la restauration. Veuillez restaurer la sauvegarde manuellement.",
"BackDevices_Restore_okay": "Restauration exécutée avec succès.", "BackDevices_Restore_okay": "Restauration exécutée avec succès.",
"BackDevices_darkmode_disabled": "Mode sombre désactivé", "BackDevices_darkmode_disabled": "Mode sombre désactivé",
"BackDevices_darkmode_enabled": "Mode sombre activé", "BackDevices_darkmode_enabled": "Mode sombre activé",
"CLEAR_NEW_FLAG_description": "",
"CLEAR_NEW_FLAG_name": "",
"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_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", "DAYS_TO_KEEP_EVENTS_name": "Supprimer les événements plus anciens que",
"DevDetail_Copy_Device_Title": "<i class=\"fa fa-copy\"></i> Copier les détails de l'appareil", "DevDetail_Copy_Device_Title": "<i class=\"fa fa-copy\"></i> Copier les détails de l'appareil",
"DevDetail_Copy_Device_Tooltip": "Copier les détails de l'appareil dans la liste déroulante. Tout ce qui se trouve sur cette page sera écrasé", "DevDetail_Copy_Device_Tooltip": "Copier les détails de l'appareil dans la liste déroulante. Tout ce qui se trouve sur cette page sera remplacé",
"DevDetail_EveandAl_AlertAllEvents": "Alerter tous les événements", "DevDetail_EveandAl_AlertAllEvents": "Alerter de tous les événements",
"DevDetail_EveandAl_AlertDown": "Alerte de panne", "DevDetail_EveandAl_AlertDown": "Alerte de panne",
"DevDetail_EveandAl_Archived": "Archivés", "DevDetail_EveandAl_Archived": "Archivés",
"DevDetail_EveandAl_NewDevice": "Nouvel appareil", "DevDetail_EveandAl_NewDevice": "Nouvel appareil",
"DevDetail_EveandAl_NewDevice_Tooltip": "Affiche le statut Nouveau pour l'appareil et l'inclut dans les listes lorsque le filtre Nouveaux Appareils est actif. N'affecte pas les notifications.", "DevDetail_EveandAl_NewDevice_Tooltip": "Affiche l'état Nouveau pour l'appareil et l'inclut dans les listes lorsque le filtre Nouveaux appareils est actif. N'affecte pas les notifications.",
"DevDetail_EveandAl_RandomMAC": "MAC aléatoire", "DevDetail_EveandAl_RandomMAC": "MAC aléatoire",
"DevDetail_EveandAl_ScanCycle": "Scanner l'appareil", "DevDetail_EveandAl_ScanCycle": "Scanner l'appareil",
"DevDetail_EveandAl_ScanCycle_a": "Scanner l'appareil", "DevDetail_EveandAl_ScanCycle_a": "Scanner l'appareil",
"DevDetail_EveandAl_ScanCycle_z": "Ne pas scanner l'appareil", "DevDetail_EveandAl_ScanCycle_z": "Ne pas scanner l'appareil",
"DevDetail_EveandAl_Skip": "Passer les notifications répétées durant", "DevDetail_EveandAl_Skip": "Passer les notifications répétées durant",
"DevDetail_EveandAl_Title": "<i class=\"fa fa-bolt\"></i> Config des événements & Alerted", "DevDetail_EveandAl_Title": "<i class=\"fa fa-bolt\"></i> Configuration des événements & Alertes",
"DevDetail_Events_CheckBox": "Masquer les événements de connexion", "DevDetail_Events_CheckBox": "Masquer les événements de connexion",
"DevDetail_GoToNetworkNode": "Naviguer à la page Réseau pour le noeud sélectionné", "DevDetail_GoToNetworkNode": "Naviguer à la page Réseau pour le noeud sélectionné",
"DevDetail_Icon": "Icône", "DevDetail_Icon": "Icône",
"DevDetail_Icon_Descr": "Renseigner le nom d'une icône Font Awesome sans le préfixe fa- ou la classe complète; par ex. fa fa-brands fa-apple.", "DevDetail_Icon_Descr": "Renseigner le nom d'une icône Font Awesome sans le préfixe fa- ou la classe complète; par ex. fa fa-brands fa-apple.",
"DevDetail_Loading": "Chargement …", "DevDetail_Loading": "Chargement…",
"DevDetail_MainInfo_Comments": "Observations", "DevDetail_MainInfo_Comments": "Observations",
"DevDetail_MainInfo_Favorite": "Favori", "DevDetail_MainInfo_Favorite": "Favori",
"DevDetail_MainInfo_Group": "Groupe", "DevDetail_MainInfo_Group": "Groupe",
@@ -85,20 +87,20 @@
"DevDetail_MainInfo_Network_Port": "<i class=\"fa fa-ethernet\"></i> Port", "DevDetail_MainInfo_Network_Port": "<i class=\"fa fa-ethernet\"></i> Port",
"DevDetail_MainInfo_Network_Site": "Site", "DevDetail_MainInfo_Network_Site": "Site",
"DevDetail_MainInfo_Network_Title": "<i class=\"fa fa-network-wired\"></i> Réseau", "DevDetail_MainInfo_Network_Title": "<i class=\"fa fa-network-wired\"></i> Réseau",
"DevDetail_MainInfo_Owner": "Propriétaire", "DevDetail_MainInfo_Owner": "Possesseur",
"DevDetail_MainInfo_SSID": "SSID", "DevDetail_MainInfo_SSID": "SSID",
"DevDetail_MainInfo_Title": "<i class=\"fa fa-pencil\"></i> Informations principales", "DevDetail_MainInfo_Title": "<i class=\"fa fa-pencil\"></i> Informations principales",
"DevDetail_MainInfo_Type": "Type", "DevDetail_MainInfo_Type": "Type",
"DevDetail_MainInfo_Vendor": "Fabriquant", "DevDetail_MainInfo_Vendor": "Fabricant",
"DevDetail_MainInfo_mac": "MAC", "DevDetail_MainInfo_mac": "MAC",
"DevDetail_Network_Node_hover": "Sélectionner l'appareil du réseau principal auquel cet appareil est connecté afin de compléter l'arbre Réseau.", "DevDetail_Network_Node_hover": "Sélectionner l'appareil du réseau principal auquel cet appareil est connecté afin de compléter l'arborescence du Réseau.",
"DevDetail_Network_Port_hover": "Le port auquel cet appareil est connecté sur l'appareil du réseau principal. Si vide, une icône Wifi est affichée dans l'arbre Réseau.", "DevDetail_Network_Port_hover": "Le port auquel cet appareil est connecté sur l'appareil du réseau principal. Si vide, une icône Wifi est affichée dans l'arborescence du Réseau.",
"DevDetail_Nmap_Scans": "Scans NMAP manuels", "DevDetail_Nmap_Scans": "Scans NMAP manuels",
"DevDetail_Nmap_Scans_desc": "Vous pouvez lancer des scans NMAP manuels. Vous pouvez aussi programmer des sans réguliers via le plugin Services & Ports (NMAP). Aller dans les <a href='/settings.php' target='_blank'>Paramètres</a> pour plus de details", "DevDetail_Nmap_Scans_desc": "Vous pouvez lancer des scans NMAP manuels. Vous pouvez aussi programmer des sans réguliers via le plugin Services & Ports (NMAP). Aller dans les <a href='/settings.php' target='_blank'>Paramètres</a> pour plus de details",
"DevDetail_Nmap_buttonDefault": "Scan par défaut", "DevDetail_Nmap_buttonDefault": "Scan par défaut",
"DevDetail_Nmap_buttonDefault_text": "Scan par défaut: NMAP scanne les 1 000 premiers ports pour chaque demande de scan de protocole. Cela couvre environ 93% des ports TCP et 49% des ports UDP (environ 5 secondes).", "DevDetail_Nmap_buttonDefault_text": "Scan par défaut: NMAP scanne les 1 000 premiers ports pour chaque demande de scan de protocole. Cela couvre environ 93% des ports TCP et 49% des ports UDP (environ 5 secondes).",
"DevDetail_Nmap_buttonDetail": "Scan détaillé", "DevDetail_Nmap_buttonDetail": "Scan détaillé",
"DevDetail_Nmap_buttonDetail_text": "Scan détaillé: scan par défaut avec la détection de système d'exploitation, la détection de version, l'analyse de script et le tracé route (jusqu'à 30 secondes ou plus)", "DevDetail_Nmap_buttonDetail_text": "Scan détaillé: scan par défaut avec la détection de système d'exploitation, la détection de version, l'analyse de script et le traceroute (jusqu'à 30 secondes ou plus)",
"DevDetail_Nmap_buttonFast": "Scan rapide", "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_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": "Passer la découverte d'hôtes",
@@ -114,13 +116,13 @@
"DevDetail_Run_Actions_Tooltip": "Lancer une action sur l'appareil depuis la liste déroulante.", "DevDetail_Run_Actions_Tooltip": "Lancer une action sur l'appareil depuis la liste déroulante.",
"DevDetail_SessionInfo_FirstSession": "Première session", "DevDetail_SessionInfo_FirstSession": "Première session",
"DevDetail_SessionInfo_LastIP": "Dernière IP", "DevDetail_SessionInfo_LastIP": "Dernière IP",
"DevDetail_SessionInfo_LastSession": "Dernière session", "DevDetail_SessionInfo_LastSession": "Hors ligne depuis",
"DevDetail_SessionInfo_StaticIP": "IP statique", "DevDetail_SessionInfo_StaticIP": "IP statique",
"DevDetail_SessionInfo_Status": "État", "DevDetail_SessionInfo_Status": "État",
"DevDetail_SessionInfo_Title": "<i class=\"fa fa-calendar\"></i> Info de session", "DevDetail_SessionInfo_Title": "<i class=\"fa fa-calendar\"></i> Info de session",
"DevDetail_SessionTable_Additionalinfo": "Informations supplémentaires", "DevDetail_SessionTable_Additionalinfo": "Informations supplémentaires",
"DevDetail_SessionTable_Connection": "Connexion", "DevDetail_SessionTable_Connection": "Connexion",
"DevDetail_SessionTable_Disconnection": "Déconnection", "DevDetail_SessionTable_Disconnection": "Déconnexion",
"DevDetail_SessionTable_Duration": "Durée", "DevDetail_SessionTable_Duration": "Durée",
"DevDetail_SessionTable_IP": "IP", "DevDetail_SessionTable_IP": "IP",
"DevDetail_SessionTable_Order": "Ordre", "DevDetail_SessionTable_Order": "Ordre",
@@ -137,7 +139,7 @@
"DevDetail_Tab_Nmap": "<i class=\"fa fa-ethernet\"></i> NMAP", "DevDetail_Tab_Nmap": "<i class=\"fa fa-ethernet\"></i> NMAP",
"DevDetail_Tab_NmapEmpty": "Aucun port détecté par NMAP sur cet appareil.", "DevDetail_Tab_NmapEmpty": "Aucun port détecté par NMAP sur cet appareil.",
"DevDetail_Tab_NmapTableExtra": "Extra", "DevDetail_Tab_NmapTableExtra": "Extra",
"DevDetail_Tab_NmapTableHeader": "Résultats des scans programmés", "DevDetail_Tab_NmapTableHeader": "Résultats du scan programmé",
"DevDetail_Tab_NmapTableIndex": "Index", "DevDetail_Tab_NmapTableIndex": "Index",
"DevDetail_Tab_NmapTablePort": "Port", "DevDetail_Tab_NmapTablePort": "Port",
"DevDetail_Tab_NmapTableService": "Service", "DevDetail_Tab_NmapTableService": "Service",
@@ -148,40 +150,40 @@
"DevDetail_Tab_Presence": "<i class=\"fa fa-calendar\"></i> Présence", "DevDetail_Tab_Presence": "<i class=\"fa fa-calendar\"></i> Présence",
"DevDetail_Tab_Sessions": "<i class=\"fa fa-list-ol\"></i> Sessions", "DevDetail_Tab_Sessions": "<i class=\"fa fa-list-ol\"></i> Sessions",
"DevDetail_Tab_Tools": "<i class=\"fa fa-screwdriver-wrench\"></i> Outils", "DevDetail_Tab_Tools": "<i class=\"fa fa-screwdriver-wrench\"></i> Outils",
"DevDetail_Tab_Tools_Internet_Info_Description": "", "DevDetail_Tab_Tools_Internet_Info_Description": "L'outil Infos Internet affiche les informations sur la connexion Internet, comme l'adresse IP, la ville, la région, le code région et le fuseau horaire.",
"DevDetail_Tab_Tools_Internet_Info_Error": "Une erreur est survenue", "DevDetail_Tab_Tools_Internet_Info_Error": "Une erreur est survenue",
"DevDetail_Tab_Tools_Internet_Info_Start": "", "DevDetail_Tab_Tools_Internet_Info_Start": "Lancer les informations Internet",
"DevDetail_Tab_Tools_Internet_Info_Title": "Informations Internet", "DevDetail_Tab_Tools_Internet_Info_Title": "Informations Internet",
"DevDetail_Tab_Tools_Nslookup_Description": "Nslookup est un outil utilisé pour chercher dans les Domain Name System (DNS). DNS est un système qui traduit les noms de domaine, comme www.google.com, en adresses IP, comme 172.217.0.142.", "DevDetail_Tab_Tools_Nslookup_Description": "Nslookup est un outil utilisé pour chercher dans les Domain Name System (DNS). DNS est un système qui traduit les noms de domaine, comme www.google.com, en adresses IP, comme 172.217.0.142.",
"DevDetail_Tab_Tools_Nslookup_Error": "Erreur: adresse IP invalide", "DevDetail_Tab_Tools_Nslookup_Error": "Erreur: adresse IP invalide",
"DevDetail_Tab_Tools_Nslookup_Start": "Lancer Nslookup", "DevDetail_Tab_Tools_Nslookup_Start": "Lancer Nslookup",
"DevDetail_Tab_Tools_Nslookup_Title": "Nslookup", "DevDetail_Tab_Tools_Nslookup_Title": "Nslookup",
"DevDetail_Tab_Tools_Speedtest_Description": "L'outil Speedtest mesure la vitesse de la connexion descendante, montante, et de la latence de la connexion Internet.", "DevDetail_Tab_Tools_Speedtest_Description": "L'outil Speedtest de test de débit mesure la vitesse de la connexion descendante, montante, et de la latence de la connexion Internet.",
"DevDetail_Tab_Tools_Speedtest_Start": "Démarrer le test de débit", "DevDetail_Tab_Tools_Speedtest_Start": "Démarrer le test de débit",
"DevDetail_Tab_Tools_Speedtest_Title": "Test de débit en ligne", "DevDetail_Tab_Tools_Speedtest_Title": "Test de débit en ligne",
"DevDetail_Tab_Tools_Traceroute_Description": "", "DevDetail_Tab_Tools_Traceroute_Description": "Traceroute est une commande de diagnostic réseau utilisée pour suivre/tracer la route réseau utilisée par un paquet de données d'un hôte vers un autre.<br><br>Cette commande utilise ICMP (Internet Control Message Protocol) pour envoyer des paquets via les nœuds intermédiaires du réseau, chaque noeud intermédiaire répondant avec un paquet time-out ICMP (TTL timed out).<br><br>La commande affiche en retour l'adresse IP de chaque noeud intermédiaire de la route .<br><br>La commande Traceroute peut être utilisé pour diagnostiquer des problèmes réseau, comme des ralentissements, des pertes de paquets et des routes bloquées.<br><br>Elle peut aussi être utilisée pour identifier l'emplacement d'un nœud intermédiaire du réseau.",
"DevDetail_Tab_Tools_Traceroute_Error": "L'adresse IP n'est pas valide", "DevDetail_Tab_Tools_Traceroute_Error": "Erreur: l'adresse IP n'est pas valide",
"DevDetail_Tab_Tools_Traceroute_Start": "Lancer Traceroute", "DevDetail_Tab_Tools_Traceroute_Start": "Lancer Traceroute",
"DevDetail_Tab_Tools_Traceroute_Title": "Traceroute", "DevDetail_Tab_Tools_Traceroute_Title": "Traceroute",
"DevDetail_Tools_WOL": "Envoyer une commande WoL à ", "DevDetail_Tools_WOL": "Envoyer une commande WoL à ",
"DevDetail_Tools_WOL_noti": "Wake-on-LAN", "DevDetail_Tools_WOL_noti": "Wake-on-LAN",
"DevDetail_Tools_WOL_noti_text": "La commande Wake-on-LAN (WoL) est envoyé à l'adresse de broadcasting. Si la cible n'est pas dans le sous-réseau / VLAN de NetAlertX, l'appareil cible ne répondra pas.", "DevDetail_Tools_WOL_noti_text": "La commande Wake-on-LAN (WoL) est envoyé à l'adresse de broadcasting. Si la cible n'est pas dans le sous-réseau / VLAN de NetAlertX, l'appareil cible ne répondra pas.",
"DevDetail_Type_hover": "Le type d'appareil. Si vous sélectionnez un appareil réseau prédéfini (ex. AP, Firewall, Routeur, Switch...), ils apparaitront dans la configuration de l'arbre Réseau comme nœud de réseau principal potentiel.", "DevDetail_Type_hover": "Le type d'appareil. Si vous sélectionnez un appareil réseau prédéfini (ex. AP, Firewall, Routeur, Switch...), ils apparaitront dans la configuration de l'arborescence du Réseau comme nœud de réseau principal potentiel.",
"DevDetail_Vendor_hover": "Le Vendeur est détecté automatiquement. Vous pouvez changer la valeur ou ajouter une valeur libre.", "DevDetail_Vendor_hover": "Le fabricant est détecté automatiquement. Vous pouvez changer la valeur ou ajouter une valeur libre.",
"DevDetail_WOL_Title": "<i class=\"fa fa-power-off\"></i> Wake-on-LAN", "DevDetail_WOL_Title": "<i class=\"fa fa-power-off\"></i> Wake-on-LAN",
"DevDetail_button_AddIcon": "Ajouter une nouvelle icône", "DevDetail_button_AddIcon": "Ajouter une nouvelle icône",
"DevDetail_button_AddIcon_Help": "", "DevDetail_button_AddIcon_Help": "Coller l'emplacement HTML d'un SVG, ou d'une icône Font Awesome. Plus d'informations dans la <a href=\"https://github.com/jokob-sk/NetAlertX/blob/main/docs/ICONS.md\" target=\"_blank\">Documentation des icônes</a>.",
"DevDetail_button_AddIcon_Tooltip": "Ajouter une nouvelle icône, non encore disponible dans la liste déroulante, pour cet appareil.", "DevDetail_button_AddIcon_Tooltip": "Ajouter une nouvelle icône, non encore disponible dans la liste déroulante, pour cet appareil.",
"DevDetail_button_Delete": "Supprimer l'appareil", "DevDetail_button_Delete": "Supprimer l'appareil",
"DevDetail_button_DeleteEvents": "Supprimer les événements", "DevDetail_button_DeleteEvents": "Supprimer les événements",
"DevDetail_button_DeleteEvents_Warning": "Êtes-vous sûr de vouloir supprimer tous les Événements de cet appareil?<br><br>(cela supprimera l'<b>Historique des événements</b> et les <b>Sessions</b> et peur aider pour les notifications persistantes)", "DevDetail_button_DeleteEvents_Warning": "Êtes-vous sûr de vouloir supprimer tous les Événements de cet appareil?<br><br>(cela supprimera l'<b>Historique des événements</b> et les <b>Sessions</b> et peur aider pour les notifications persistantes)",
"DevDetail_button_OverwriteIcons": "Remplacer les icônes", "DevDetail_button_OverwriteIcons": "Remplacer les icônes",
"DevDetail_button_OverwriteIcons_Tooltip": "Remplacer les icônes de tous les appareils de ce type", "DevDetail_button_OverwriteIcons_Tooltip": "Remplacer les icônes de tous les appareils de ce type",
"DevDetail_button_OverwriteIcons_Warning": "", "DevDetail_button_OverwriteIcons_Warning": "Êtes-vous sûr de vouloir remplacer toutes les icônes de tous les appareils du même type que l'appareil actuel?",
"DevDetail_button_Reset": "Réinitialiser les modifications", "DevDetail_button_Reset": "Réinitialiser les modifications",
"DevDetail_button_Save": "Enregistrer", "DevDetail_button_Save": "Enregistrer",
"Device_MultiEdit": "Édition multiple", "Device_MultiEdit": "Édition multiple",
"Device_MultiEdit_Backup": "", "Device_MultiEdit_Backup": "Attention, renseigner des valeurs non cohérentes ci-dessous peut bloquer votre paramétrage. Veillez à faire une sauvegarde de votre base de données ou de la configuration de vos appareils en premier lieu (<a href=\"php/server/devices.php?action=ExportCSV\">clisuer ici pour la télécharger <i class=\"fa-solid fa-download fa-bounce\"></i></a>). Renseignez-vous sur comment remettre les appareils depuis ce fichier via la <a href=\"https://github.com/jokob-sk/NetAlertX/blob/main/docs/BACKUPS.md#scenario-2-corrupted-database\" target=\"_blank\">documentation des sauvegardes</a>.",
"Device_MultiEdit_Fields": "Champs modifiables:", "Device_MultiEdit_Fields": "Champs modifiables:",
"Device_MultiEdit_MassActions": "Actions en masse:", "Device_MultiEdit_MassActions": "Actions en masse:",
"Device_MultiEdit_Tooltip": "Attention. Ceci va appliquer la valeur de gauche à tous les appareils sélectionnés au-dessus.", "Device_MultiEdit_Tooltip": "Attention. Ceci va appliquer la valeur de gauche à tous les appareils sélectionnés au-dessus.",
@@ -203,7 +205,7 @@
"Device_TableHead_Icon": "Icône", "Device_TableHead_Icon": "Icône",
"Device_TableHead_LastIP": "Dernière IP", "Device_TableHead_LastIP": "Dernière IP",
"Device_TableHead_LastIPOrder": "Ordre dernière IP", "Device_TableHead_LastIPOrder": "Ordre dernière IP",
"Device_TableHead_LastSession": "Dernière session", "Device_TableHead_LastSession": "Hors ligne depuis",
"Device_TableHead_Location": "Emplacement", "Device_TableHead_Location": "Emplacement",
"Device_TableHead_MAC": "MAC aléatoire", "Device_TableHead_MAC": "MAC aléatoire",
"Device_TableHead_MAC_full": "Adresse MAC", "Device_TableHead_MAC_full": "Adresse MAC",
@@ -223,7 +225,7 @@
"Device_Table_info": "Affiche de _START_ à _END_ sur _TOTAL_ entrées", "Device_Table_info": "Affiche de _START_ à _END_ sur _TOTAL_ entrées",
"Device_Table_nav_next": "Suivant", "Device_Table_nav_next": "Suivant",
"Device_Table_nav_prev": "Précédent", "Device_Table_nav_prev": "Précédent",
"Device_Tablelenght": "Afficher _MENU_ entrées", "Device_Tablelenght": "Afficher les entrées _MENU_",
"Device_Tablelenght_all": "Tous", "Device_Tablelenght_all": "Tous",
"Device_Title": "Appareils", "Device_Title": "Appareils",
"Donations_Others": "Autres", "Donations_Others": "Autres",
@@ -274,6 +276,7 @@
"Gen_AreYouSure": "Êtes-vous sûr?", "Gen_AreYouSure": "Êtes-vous sûr?",
"Gen_Backup": "Lancer la sauvegarde", "Gen_Backup": "Lancer la sauvegarde",
"Gen_Cancel": "Annuler", "Gen_Cancel": "Annuler",
"Gen_Change": "",
"Gen_Copy": "Lancer", "Gen_Copy": "Lancer",
"Gen_DataUpdatedUITakesTime": "OK - cela peut prendre du temps à l'interface pour se mettre à jour si un scan est en cours.", "Gen_DataUpdatedUITakesTime": "OK - cela peut prendre du temps à l'interface pour se mettre à jour si un scan est en cours.",
"Gen_Delete": "Supprimer", "Gen_Delete": "Supprimer",
@@ -292,6 +295,7 @@
"Gen_Save": "Enregistrer", "Gen_Save": "Enregistrer",
"Gen_Saved": "Enregistré", "Gen_Saved": "Enregistré",
"Gen_Search": "Recherche", "Gen_Search": "Recherche",
"Gen_SelectToPreview": "",
"Gen_Selected_Devices": "Appareils sélectionnés:", "Gen_Selected_Devices": "Appareils sélectionnés:",
"Gen_Switch": "Basculer", "Gen_Switch": "Basculer",
"Gen_Upd": "Mise à jour réussie", "Gen_Upd": "Mise à jour réussie",
@@ -303,139 +307,139 @@
"General_display_name": "Général", "General_display_name": "Général",
"General_icon": "<i class=\"fa fa-gears\"></i>", "General_icon": "<i class=\"fa fa-gears\"></i>",
"HRS_TO_KEEP_NEWDEV_description": "Paramétrage de maintenance. S'il est activé (<code>0</code> s'il est désactivé), les appareils marqués comme <b>Nouvel appareil</b> seront supprimés si leur durée depuis la <b>première session</b> est plus ancienne que le nombre d'heures paramétré. Utilisez ce paramétrage si vous voulez supprimer automatiquement les <b>Nouveaux appareils</b> après <code>X</code> heures.", "HRS_TO_KEEP_NEWDEV_description": "Paramétrage de maintenance. S'il est activé (<code>0</code> s'il est désactivé), les appareils marqués comme <b>Nouvel appareil</b> seront supprimés si leur durée depuis la <b>première session</b> est plus ancienne que le nombre d'heures paramétré. Utilisez ce paramétrage si vous voulez supprimer automatiquement les <b>Nouveaux appareils</b> après <code>X</code> heures.",
"HRS_TO_KEEP_NEWDEV_name": "", "HRS_TO_KEEP_NEWDEV_name": "Garder les appareils en Nouveau pendant",
"HelpFAQ_Cat_Detail": "Détails", "HelpFAQ_Cat_Detail": "Détails",
"HelpFAQ_Cat_Detail_300_head": "", "HelpFAQ_Cat_Detail_300_head": "Que signifie ",
"HelpFAQ_Cat_Detail_300_text_a": "", "HelpFAQ_Cat_Detail_300_text_a": "signifie que cela représente un équipement réseau (Access Point, Gateway, Firewall, Hyperviseur, Powerline, Switch, WLAN, CPL, adaptateur Ethernet USB, adaptateur Wifi USB, Internet). Les types d'appareils personnalisés peuvent être ajoutés via le paramètre <code>NETWORK_DEVICE_TYPES</code>.",
"HelpFAQ_Cat_Detail_300_text_b": "", "HelpFAQ_Cat_Detail_300_text_b": "désigne le numéro de port auquel l'appareil modifié est connecté à cet appareil réseau. Lire <a target=\"_blank\" href=\"https://github.com/jokob-sk/NetAlertX/blob/main/docs/NETWORK_TREE.md\">ce guide</a> pour plus d'infos.",
"HelpFAQ_Cat_Detail_301_head_a": "", "HelpFAQ_Cat_Detail_301_head_a": "Quand le scan se lance-t-il? À ",
"HelpFAQ_Cat_Detail_301_head_b": "", "HelpFAQ_Cat_Detail_301_head_b": " indique 1 min mais le graphique affiche des intervalles de 5 min.",
"HelpFAQ_Cat_Detail_301_text": "", "HelpFAQ_Cat_Detail_301_text": "L'intervalle de temps entre les scans est défini par les \"Cronjob\", défini à 5 min par défaut. L'indication \"1min\" fait référence à la durée attendue du scan. En fonction de la configuration réseau, cette durée peut varier. Pour modifier le cronjob, vous pouvez utiliser la commande suivante dans un terminal: <span class=\"text-danger help_faq_code\">crontab -e</span> et changer cet intervalle.",
"HelpFAQ_Cat_Detail_302_head_a": "", "HelpFAQ_Cat_Detail_302_head_a": "Que signifie ",
"HelpFAQ_Cat_Detail_302_head_b": "et pourquoi je ne peux pas sélectionner cela?", "HelpFAQ_Cat_Detail_302_head_b": "et pourquoi je ne peux pas sélectionner cela?",
"HelpFAQ_Cat_Detail_302_text": "", "HelpFAQ_Cat_Detail_302_text": "Certains appareils modernes génèrent des adresses MAC aléatoires pour améliorer la vie privée. Elles ne peuvent pas être associées à un fabricant, et peuvent changer à chaque nouvelle connexion. NetAlertX détecte si c'est une telle adresse MAC aléatoire et \"propose\" ce champ automatiquement. Pour enlever ces adresses MAC aléatoires, reportez-vous à votre appareil pour désactiver ce fonctionnement.",
"HelpFAQ_Cat_Detail_303_head": "Qu'est-ce que NMAP et à quoi cela sert-il?", "HelpFAQ_Cat_Detail_303_head": "Qu'est-ce que NMAP et à quoi cela sert-il?",
"HelpFAQ_Cat_Detail_303_text": "NMAP est un scanner réseau aux multiples possibilités.<br>Quand un nouvel appareil apparaît dans la liste, vous avez la possibilité d'avoir des informations détaillées sur l'appareil avec un scan NMAP.", "HelpFAQ_Cat_Detail_303_text": "NMAP est un scanner réseau aux multiples possibilités.<br>Quand un nouvel appareil apparaît dans la liste, vous avez la possibilité d'avoir des informations détaillées sur l'appareil avec un scan NMAP.",
"HelpFAQ_Cat_Device_200_head": "", "HelpFAQ_Cat_Device_200_head": "J'ai des appareils dans ma liste, que je ne connais pas. Après les avoir supprimés, ils réapparaissent toujours.",
"HelpFAQ_Cat_Device_200_text": "", "HelpFAQ_Cat_Device_200_text": "Si vous utilisez Pi-hole, sachez que NetAlertX peut récupérer les informations depuis Pi-hole. Pour cela, mettez en pause NetAlertX, allez dans les paramètres de Pi-hole, et supprimez les baux DHCP si nécessaire. Ensuite, toujours dans Pi-hole, allez dans Outils -> Réseau pour voir si vous pouvez identifier les hôtes réguliers. Si c'est le cas, supprimez-les de même. Vous pouvez alors réactiver NetAlertX. Maintenant, les appareils ne devraient plus apparaître.",
"HelpFAQ_Cat_General": "Général", "HelpFAQ_Cat_General": "Général",
"HelpFAQ_Cat_General_100_head": "L'horloge en haut à droite et les heures des événements/présence ne sont pas correctes (décalage horaire).", "HelpFAQ_Cat_General_100_head": "L'horloge en haut à droite et les heures des événements/présence ne sont pas correctes (décalage horaire).",
"HelpFAQ_Cat_General_100_text_a": "", "HelpFAQ_Cat_General_100_text_a": "Sur votre appareil, le fuseau horaire suivant est défini dans votre environnement PHP:",
"HelpFAQ_Cat_General_100_text_b": "", "HelpFAQ_Cat_General_100_text_b": "Si cela ne correspond pas à votre fuseau horaire, vous devriez le changer dans le fichier de configuration PHP. Vous pouvez le trouver dans le répertoire:",
"HelpFAQ_Cat_General_100_text_c": "", "HelpFAQ_Cat_General_100_text_c": "Chercher dans ce fichier l'élément \"date.timezone\", supprimer du nécessaire le \";\" en début de ligne et renseigner le fuseau horaire voulu. Une liste des fuseaux horaires supportés est présente ici (<a href=\"https://www.php.net/manual/en/timezones.php\" target=\"blank\">Lien</a>)",
"HelpFAQ_Cat_General_101_head": "", "HelpFAQ_Cat_General_101_head": "Mon réseau semble être ralenti, le streaming \"se fige\".",
"HelpFAQ_Cat_General_101_text": "", "HelpFAQ_Cat_General_101_text": "Les appareils à performance limitée peuvent atteindre leurs limited avec la manière dont NetAlertX détecte les nouveaux appareils sur le réseau. Cela est amplifié si les appareils communiquent via un LWAN. Une solution dans ce cas est de passer sur une connexion filaire si possible, ou, si l'appareil est utilisé temporairement, d'utiliser un scan ARP, puis de mettre en pause le scan ARP sur la page de maintenance.",
"HelpFAQ_Cat_General_102_head": "", "HelpFAQ_Cat_General_102_head": "Un message m'indique que la base de données est en lecture seule.",
"HelpFAQ_Cat_General_102_text": "", "HelpFAQ_Cat_General_102_text": "Vérifiez dans le répertoire de NetAlertX si la base de données (db) possède les bonnes permissions:<br> <span class=\"text-danger help_faq_code\">drwxrwx--- 2 (votre nom d'utilisateur) www-data</span><br> Si la permission n'est pas correcte, vous pouvez la modifier en passant les commandes suivantes dans le terminal:<br> <span class=\"text-danger help_faq_code\">sudo chgrp -R www-data /app/db<br>chmod -R 770 /app/db</span><br>Si la base de données est encore en lecture seule, tentez de la réinstaller ou de restaurer une sauvegarde de la base à partir de la page de maintenance.",
"HelpFAQ_Cat_General_102docker_head": "", "HelpFAQ_Cat_General_102docker_head": "Erreur de base de données (erreurs AJAX, lecture seule, non trouvé)",
"HelpFAQ_Cat_General_102docker_text": "", "HelpFAQ_Cat_General_102docker_text": "Vérifiez avec attention que vous avez suivi les instructions dans le <a target=\"_blank\" href=\"https://github.com/jokob-sk/NetAlertX/tree/main/dockerfiles\">lisez-moi (readme) Docker (contient les infos les plus récentes)</a>. <br/> <br/> <ul data-sourcepos=\"49:4-52:146\" dir=\"auto\"><li data-sourcepos=\"49:4-49:106\"> Télécharger la <a target=\"_blank\" href=\"https://github.com/jokob-sk/NetAlertX/blob/main/db/app.db\">base de données originelle depuis GitHub</a>.</li><li data-sourcepos=\"50:4-50:195\">Relier le fichier <code>app.db</code> (<g-emoji class=\"g-emoji\" alias=\"warning\" fallback-src=\"https://github.githubassets.com/images/icons/emoji/unicode/26a0.png\">⚠</g-emoji> pas le dossier) au-dessus avec <code>/app/db/app.db</code> (plus de détails dans les <a target=\"_blank\" href=\"https://github.com/jokob-sk/NetAlertX/tree/main/dockerfiles#-examples\">Exemples</a>).</li><li data-sourcepos=\"51:4-51:161\">. Si vous rencontrez des erreurs (erreurs Ajax, impossible d'écrire dans la base, etc.), vérifiez que les permissions sont correctement définies, éventuellement regarder dans les blogs présents dans <code>/app/front/log</code>.</li><li data-sourcepos=\"52:4-52:146\">. Pour résoudre les problèmes de permission, vous pouvez aussi essayer de créer une sauvegarde de la base de données et lancer une restauration via la section <strong>Maintenance &gt; Sauvegarde/Restauration</strong>.</li><li data-sourcepos=\"53:4-53:228\">Si la base de données est en lecture seule, vous pouvez résoudre cela en définissant le propriétaire et le groupe en lançant la commande suivante depuis le système hôte: <code>docker exec netalertx chown -R www-data:www-data /app/db/app.db</code>.</li></ul>",
"HelpFAQ_Cat_General_103_head": "", "HelpFAQ_Cat_General_103_head": "La page d'authentification n'apparaît pas, même après avoir changé le mot de passe.",
"HelpFAQ_Cat_General_103_text": "", "HelpFAQ_Cat_General_103_text": "En plus du mot de passe, le fichier de configuration doit contenir <span class=\"text-danger help_faq_code\">/app/config/app.conf</span>. De plus, le paramètre <span class=\"text-danger help_faq_code\">PIALERT_WEB_PROTECTION</span> doit être à la valeur<span class=\"text-danger help_faq_code\">True</span>.",
"HelpFAQ_Cat_Network_600_head": "", "HelpFAQ_Cat_Network_600_head": "A quoi sert cette page?",
"HelpFAQ_Cat_Network_600_text": "", "HelpFAQ_Cat_Network_600_text": "Cette page offre la possibilité de définir le paramétrage des appareils du réseau. Pour cela, vous pouvez créer un ou plusieurs switchs, WLANs, routeurs, etc.; leur indiquer un numéro de port si nécessaire et leur assigner des appareils déjà détectés. Cette assignation est faite dans la vue détaillée de l'appareil à assigner. Cela permet de rapidement identifier quel hôte est connecté à quel port, et s'il est en ligne. Plus d'informations dans <a target=\"_blank\" href=\"https://github.com/jokob-sk/NetAlertX/blob/main/docs/NETWORK_TREE.md\">ce guide</a>.",
"HelpFAQ_Cat_Network_601_head": "", "HelpFAQ_Cat_Network_601_head": "Y a-t-il d'autre documentation?",
"HelpFAQ_Cat_Network_601_text": "", "HelpFAQ_Cat_Network_601_text": "Oui! Consulter <a target=\"_blank\" href=\"https://github.com/jokob-sk/NetAlertX/blob/main/docs/\">tous les documents</a> pour plus d'infos.",
"HelpFAQ_Cat_Presence_400_head": "", "HelpFAQ_Cat_Presence_400_head": "Les appareils apparaissent avec un symbole jaune et le message \"événement manquant\".",
"HelpFAQ_Cat_Presence_400_text": "", "HelpFAQ_Cat_Presence_400_text": "Si cela arrive, vous pouvez supprimer tous les événements de l'appareil en question (vue détaillée). Une autre possibilité est d'allumer l'appareil et d'attendre que NetAlertX le détecte comme \"en ligne\" lors du prochain scan; puis éteindre l'appareil à nouveau. NetAlertX devrait alors afficher normalement son état dans la base lors du prochain scan.",
"HelpFAQ_Cat_Presence_401_head": "Un appareil est affiché comme présent bien qu'il soit \"Hors ligne\".", "HelpFAQ_Cat_Presence_401_head": "Un appareil est affiché comme présent bien qu'il soit \"Hors ligne\".",
"HelpFAQ_Cat_Presence_401_text": "", "HelpFAQ_Cat_Presence_401_text": "Si cela arrive, vous avez la possibilité de supprimer les événements pour les appareils concernés (vue détaillée). Vous pouvez aussi allumer l'appareil, attendre que NetAlertX le détecte comme en ligne, puis simplement éteindre l'appareil à nouveau. NetAlertX devait maintenant correctement détecter l'état de l'appareil lors du prochain scan.",
"HelpFAQ_Title": "Aide / FAQ", "HelpFAQ_Title": "Aide / FAQ",
"LOADED_PLUGINS_description": "", "LOADED_PLUGINS_description": "Affiche les plugins chargés. Ajouter des plugins peut ralentir l'application. Obtenez plus d'informations dur quels plugins dont à activer, ou les options de scan dans la <a target=\"_blank\" href=\"https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins#readme\">documentation des plugins</a>. Décharger des plugins leur fait perdre leurs paramètres. Seuls les plugins <code>désactivés</code> peuvent être déchargés.",
"LOADED_PLUGINS_name": "", "LOADED_PLUGINS_name": "Plugins chargés",
"LOG_LEVEL_description": "", "LOG_LEVEL_description": "Ce paramètre active une journalisation dans les logs plus verbeuse. Cela est utile pour identifier les événements écrivant dans la base de données.",
"LOG_LEVEL_name": "", "LOG_LEVEL_name": "Afficher des journaux de log additionnels",
"Loading": "Chargement …", "Loading": "Chargement...",
"Login_Box": "", "Login_Box": "Saisir votre mot de passe",
"Login_Default_PWD": "", "Login_Default_PWD": "Le mot de passe par défaut \"123456\" est encore actif.",
"Login_Psw-box": "Mot de passe", "Login_Psw-box": "Mot de passe",
"Login_Psw_alert": "", "Login_Psw_alert": "Alerte de mot de passe!",
"Login_Psw_folder": "", "Login_Psw_folder": "dans le dossier de configuration.",
"Login_Psw_new": "", "Login_Psw_new": "nouveau mot de passe",
"Login_Psw_run": "", "Login_Psw_run": "Pour changer le mot de passe, lancer:",
"Login_Remember": "", "Login_Remember": "Se rappeler",
"Login_Remember_small": "", "Login_Remember_small": "(valide durant 7 jours)",
"Login_Submit": "", "Login_Submit": "Se connecter",
"Login_Toggle_Alert_headline": "", "Login_Toggle_Alert_headline": "Alerte de mot de passe!",
"Login_Toggle_Info": "", "Login_Toggle_Info": "Information sur le mot de passe",
"Login_Toggle_Info_headline": "", "Login_Toggle_Info_headline": "Information sur le mot de passe",
"Maint_PurgeLog": "", "Maint_PurgeLog": "Nettoyer les logs",
"Maint_RestartServer": "", "Maint_RestartServer": "Relancer le serveur",
"Maint_Restart_Server_noti_text": "", "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_Running_Version": "Version installée", "Maintenance_Running_Version": "Version installée",
"Maintenance_Status": "État", "Maintenance_Status": "État",
"Maintenance_Title": "Outils d'entretien", "Maintenance_Title": "Outils de maintenance",
"Maintenance_Tool_ExportCSV": "Exportation CSV", "Maintenance_Tool_ExportCSV": "Export en CSV",
"Maintenance_Tool_ExportCSV_noti": "Exportation CSV", "Maintenance_Tool_ExportCSV_noti": "Export en CSV",
"Maintenance_Tool_ExportCSV_noti_text": "Êtes-vous sûr de vouloir générer un fichier CSV?", "Maintenance_Tool_ExportCSV_noti_text": "Êtes-vous sûr de vouloir générer un fichier CSV?",
"Maintenance_Tool_ExportCSV_text": "", "Maintenance_Tool_ExportCSV_text": "Génère un fichier CSV (valeurs séparées par des virgules), contenant la liste des appareils, dont les liens entre nœuds Réseaux et les appareils connectés. Vous pouvez aussi lancer cet export depuis l'URL <code>votre URL de NetAlertX/php/server/devices.php?action=ExportCSV</code> ou en activant le plugin <a href=\"settings.php#CSVBCKP_header\">CSV Backup</a>.",
"Maintenance_Tool_ImportCSV": "Importation CSV", "Maintenance_Tool_ImportCSV": "Import CSV",
"Maintenance_Tool_ImportCSV_noti": "Importation CSV", "Maintenance_Tool_ImportCSV_noti": "Import CSV",
"Maintenance_Tool_ImportCSV_noti_text": "Êtes-vous sûr de vouloir importer le fichier CSV? Cela écrasera complètement les appareils de votre base de données.", "Maintenance_Tool_ImportCSV_noti_text": "Êtes-vous sûr de vouloir importer le fichier CSV? Cela écrasera complètement les appareils de votre base de données.",
"Maintenance_Tool_ImportCSV_text": "", "Maintenance_Tool_ImportCSV_text": "Avant d'utiliser cette fonctionnalité, il est recommandé de faire une sauvegarde. La fonctionnalité importe un fichier CSV (valeurs séparées par des virgules) contenant la liste des appareils, dont les liens réseau entre les nœuds du réseau et ces appareils. Pour cela, placer un fichier CSV nommé <b>devices.csv</b> dans votre répertoire <b>/config</b>.",
"Maintenance_Tool_ImportPastedCSV": "", "Maintenance_Tool_ImportPastedCSV": "Import CSV (coller)",
"Maintenance_Tool_ImportPastedCSV_noti_text": "", "Maintenance_Tool_ImportPastedCSV_noti_text": "Êtes-vous sûr de vouloir importer les CSV copié? Cela va complètement <b>remplacer</b> les appareils de votre base de données.",
"Maintenance_Tool_ImportPastedCSV_text": "", "Maintenance_Tool_ImportPastedCSV_text": "Avant d'utiliser cette fonctionnalité, il est recommandé de faire une sauvegarde. Importe un fichier CSV (valeurs séparées par des virgules) contenant la liste des appareils, dont les liens réseaux entre les nœuds du réseau et les appareils connectés.",
"Maintenance_Tool_arpscansw": "Basculer l'arp-Scan (activé/désactivé)", "Maintenance_Tool_arpscansw": "Basculer l'arp-Scan (activé/désactivé)",
"Maintenance_Tool_arpscansw_noti": "Activer ou désactiver l'arp-Scan", "Maintenance_Tool_arpscansw_noti": "Activer ou désactiver l'arp-Scan",
"Maintenance_Tool_arpscansw_noti_text": "Une fois le scan désactivé, il reste désactivé jusqu'à ce qu'il soit réactivé.", "Maintenance_Tool_arpscansw_noti_text": "Une fois le scan désactivé, il reste désactivé jusqu'à ce qu'il soit réactivé.",
"Maintenance_Tool_arpscansw_text": "", "Maintenance_Tool_arpscansw_text": "Bascule entre le scan ARP activé ou désactivé. Quand le scan est désactivé, il le reste jusqu'à ce qu'il soit activé à nouveau. Les scans en cours ne sont pas annulés.",
"Maintenance_Tool_backup": "", "Maintenance_Tool_backup": "Sauvegarde de la base de données",
"Maintenance_Tool_backup_noti": "", "Maintenance_Tool_backup_noti": "Sauvegarde de base de données",
"Maintenance_Tool_backup_noti_text": "", "Maintenance_Tool_backup_noti_text": "Êtes-vous sûr de vouloir lancer la sauvegarde de la base de données? Assurez-vous de ne pas avoir de scan en cours.",
"Maintenance_Tool_backup_text": "", "Maintenance_Tool_backup_text": "Les sauvegardes de base de données sont situées dans le répertoire de la base de données, soir forme d'archive ZIP, nommé selon la date de création. Il n'y a pas de limite de nombre de sauvegarde.",
"Maintenance_Tool_check_visible": "", "Maintenance_Tool_check_visible": "Décocher pour masquer la colonne.",
"Maintenance_Tool_darkmode": "", "Maintenance_Tool_darkmode": "Basculer de mode (clair/sombre)",
"Maintenance_Tool_darkmode_noti": "", "Maintenance_Tool_darkmode_noti": "Basculer de mode",
"Maintenance_Tool_darkmode_noti_text": "", "Maintenance_Tool_darkmode_noti_text": "Après le changement de thème, la page tente de se rafraîchir pour activer le changement. Si besoin, le cache doit être supprimé.",
"Maintenance_Tool_darkmode_text": "", "Maintenance_Tool_darkmode_text": "Bascule entre le mode sombre et clair. Si la bascule ne fonctionne pas correctement, essayez de vider le cache de votre navigateur. Le changement s'effectue côté serveur, donc il s'applique à tous les appareils utilisant l'interface.",
"Maintenance_Tool_del_ActHistory": "", "Maintenance_Tool_del_ActHistory": "Suppression de l'activité réseau",
"Maintenance_Tool_del_ActHistory_noti": "", "Maintenance_Tool_del_ActHistory_noti": "Supprimer l'activité réseau",
"Maintenance_Tool_del_ActHistory_noti_text": "", "Maintenance_Tool_del_ActHistory_noti_text": "Êtes-vous sûr de vouloir supprimer l'activité réseau?",
"Maintenance_Tool_del_ActHistory_text": "", "Maintenance_Tool_del_ActHistory_text": "Le graphique d'activité réseau est remis à zéro. Cela ne modifie pas les événements.",
"Maintenance_Tool_del_alldev": "", "Maintenance_Tool_del_alldev": "Supprimer tous les appareils",
"Maintenance_Tool_del_alldev_noti": "", "Maintenance_Tool_del_alldev_noti": "Supprimer l'appareil",
"Maintenance_Tool_del_alldev_noti_text": "", "Maintenance_Tool_del_alldev_noti_text": "Êtes-vous sûr de vouloir supprimer tous les appareils?",
"Maintenance_Tool_del_alldev_text": "Avant d'utiliser cette fonction, veuillez effectuer une sauvegarde. La suppression ne peut pas être annulée. Tous les appareils seront supprimés de la base de données.", "Maintenance_Tool_del_alldev_text": "Avant d'utiliser cette fonction, veuillez effectuer une sauvegarde. La suppression ne peut pas être annulée. Tous les appareils seront supprimés de la base de données.",
"Maintenance_Tool_del_allevents": "", "Maintenance_Tool_del_allevents": "Supprimer les événements (réinitialiser la présence)",
"Maintenance_Tool_del_allevents30": "", "Maintenance_Tool_del_allevents30": "Supprimer tous les événements de plus de 30 jours",
"Maintenance_Tool_del_allevents30_noti": "", "Maintenance_Tool_del_allevents30_noti": "Supprimer les événements",
"Maintenance_Tool_del_allevents30_noti_text": "", "Maintenance_Tool_del_allevents30_noti_text": "Êtes-vous sûr de vouloir supprimer tous les événements de plus de 30 jours? Cela réinitialise la présence de tous les appareils.",
"Maintenance_Tool_del_allevents30_text": "Avant d'utiliser cette fonction, veuillez effectuer une sauvegarde. La suppression ne peut pas être annulée. Tous les événements datant de plus de 30 jours dans la base de données seront supprimés. À ce moment-là, la présence de tous les appareils sera réinitialisée. Cela peut conduire à des sessions invalides. Cela signifie que les appareils sont affichés comme « présents » bien qu'ils soient hors ligne. Une analyse pendant que l'appareil en question est en ligne résout le problème.", "Maintenance_Tool_del_allevents30_text": "Avant d'utiliser cette fonction, veuillez effectuer une sauvegarde. La suppression ne peut pas être annulée. Tous les événements datant de plus de 30 jours dans la base de données seront supprimés. À ce moment-là, la présence de tous les appareils sera réinitialisée. Cela peut conduire à des sessions invalides. Cela signifie que les appareils sont affichés comme « présent » bien qu'ils soient hors ligne. Un scan pendant que l'appareil en question est en ligne résout le problème.",
"Maintenance_Tool_del_allevents_noti": "", "Maintenance_Tool_del_allevents_noti": "Supprimer les événements",
"Maintenance_Tool_del_allevents_noti_text": "", "Maintenance_Tool_del_allevents_noti_text": "Êtes-vous sûr de vouloir supprimer tous les événements? Cela réinitialise la présence de tous les appareils.",
"Maintenance_Tool_del_allevents_text": "Avant d'utiliser cette fonction, veuillez effectuer une sauvegarde. La suppression ne peut pas être annulée. Tous les événements de la base de données seront supprimés. À ce moment-là, la présence de tous les appareils sera réinitialisée. Cela peut conduire à des sessions invalides. Cela signifie que les appareils sont affichés comme « présents » bien qu'ils soient hors ligne. Une analyse pendant que l'appareil en question est en ligne résout le problème.", "Maintenance_Tool_del_allevents_text": "Avant d'utiliser cette fonction, veuillez effectuer une sauvegarde. La suppression ne peut pas être annulée. Tous les événements de la base de données seront supprimés. À ce moment-là, la présence de tous les appareils sera réinitialisée. Cela peut conduire à des sessions invalides. Cela signifie que les appareils sont affichés comme « présent » bien qu'ils soient hors ligne. Un scan pendant que l'appareil en question est en ligne résout le problème.",
"Maintenance_Tool_del_empty_macs": "", "Maintenance_Tool_del_empty_macs": "Supprimer les appareils avec une adresse MAC vide",
"Maintenance_Tool_del_empty_macs_noti": "", "Maintenance_Tool_del_empty_macs_noti": "Supprimer les appareils",
"Maintenance_Tool_del_empty_macs_noti_text": "", "Maintenance_Tool_del_empty_macs_noti_text": "Êtes-vous sûr de vouloir supprimer tous les appareils avec une adresse MAC vide? <br>(Vous pourriez préférer les archiver)",
"Maintenance_Tool_del_empty_macs_text": "Avant d'utiliser cette fonction, veuillez effectuer une sauvegarde. La suppression ne peut pas être annulée. Tous les appareils sans MAC seront supprimés de la base de données.", "Maintenance_Tool_del_empty_macs_text": "Avant d'utiliser cette fonction, veuillez effectuer une sauvegarde. La suppression ne peut pas être annulée. Tous les appareils sans MAC seront supprimés de la base de données.",
"Maintenance_Tool_del_selecteddev": "", "Maintenance_Tool_del_selecteddev": "Supprimer les appareils sélectionnés",
"Maintenance_Tool_del_selecteddev_text": "", "Maintenance_Tool_del_selecteddev_text": "Avant d'utiliser cette fonctionnalité, il est recommandé de faire une sauvegarde. Cette suppression est définitive. Les appareils sélectionnés seront supprimés de la base de données.",
"Maintenance_Tool_del_unknowndev": "", "Maintenance_Tool_del_unknowndev": "Supprimer les appareils inconnus",
"Maintenance_Tool_del_unknowndev_noti": "", "Maintenance_Tool_del_unknowndev_noti": "Supprimer les appareils inconnus",
"Maintenance_Tool_del_unknowndev_noti_text": "", "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_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_displayed_columns_text": "", "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_drag_me": "", "Maintenance_Tool_drag_me": "Déplacez-moi pour réordonner les colonnes.",
"Maintenance_Tool_order_columns_text": "", "Maintenance_Tool_order_columns_text": "Maintenance_Tool_order_columns_text",
"Maintenance_Tool_purgebackup": "", "Maintenance_Tool_purgebackup": "Supprimer les sauvegardes",
"Maintenance_Tool_purgebackup_noti": "", "Maintenance_Tool_purgebackup_noti": "Supprimer les sauvegardes",
"Maintenance_Tool_purgebackup_noti_text": "", "Maintenance_Tool_purgebackup_noti_text": "Êtes-vous sûr de vouloir supprimer toutes les sauvegardes sauf les 3 dernières?",
"Maintenance_Tool_purgebackup_text": "", "Maintenance_Tool_purgebackup_text": "A l'exception des 3 dernières sauvegardes, toutes les autres sauvegardes seront supprimées.",
"Maintenance_Tool_restore": "", "Maintenance_Tool_restore": "Restauration de la base de données",
"Maintenance_Tool_restore_noti": "", "Maintenance_Tool_restore_noti": "Restauration de la base de données",
"Maintenance_Tool_restore_noti_text": "", "Maintenance_Tool_restore_noti_text": "Êtes-vous sûr de vouloir lancer la restauration de la base données? Assurez-vous qu'aucun scan ne soit en cours.",
"Maintenance_Tool_restore_text": "", "Maintenance_Tool_restore_text": "La dernière sauvegarde peut être restaurée à l'aide du bouton, mais les sauvegardes plus anciennes ne peuvent être restaurées que manuellement. Après la restauration, faites un contrôle d'intégrité de la base de donnes par sécurité, au cas où elle était en cours d'ecriture lorsque la sauvegarde a été réalisée.",
"Maintenance_Tool_upgrade_database_noti": "", "Maintenance_Tool_upgrade_database_noti": "Mise à jour de la base de données",
"Maintenance_Tool_upgrade_database_noti_text": "", "Maintenance_Tool_upgrade_database_noti_text": "Êtes-vous sûr de vouloir mettre à jour la base de données?<br>(il peut être préférable de l'archiver)",
"Maintenance_Tool_upgrade_database_text": "", "Maintenance_Tool_upgrade_database_text": "Ce bouton va mettre à jour la base de données pour activer le graphique de l'activité réseau sur les 12 dernières heures. Veillez à faire une sauvegarde de la base de données en cas de problème.",
"Maintenance_Tools_Tab_BackupRestore": "", "Maintenance_Tools_Tab_BackupRestore": "Sauvegarde / Restauration",
"Maintenance_Tools_Tab_Logging": "Journaux", "Maintenance_Tools_Tab_Logging": "Journaux",
"Maintenance_Tools_Tab_Settings": "Paramètres", "Maintenance_Tools_Tab_Settings": "Paramètres",
"Maintenance_Tools_Tab_Tools": "Outils", "Maintenance_Tools_Tab_Tools": "Outils",
"Maintenance_Tools_Tab_UISettings": "Paramètres de l'interface", "Maintenance_Tools_Tab_UISettings": "Paramètres de l'interface",
"Maintenance_arp_status": "", "Maintenance_arp_status": "État du scan",
"Maintenance_arp_status_off": "est actuellement désactivé", "Maintenance_arp_status_off": "est actuellement désactivé",
"Maintenance_arp_status_on": "", "Maintenance_arp_status_on": "scan(s) actuellement en cours",
"Maintenance_built_on": "Construit sur", "Maintenance_built_on": "Construit sur",
"Maintenance_current_version": "Vous êtes à jour. Découvrez sur quoi <a href=\"https://github.com/jokob-sk/NetAlertX/issues/138\" target=\"_blank\">je travaille</a>.", "Maintenance_current_version": "Vous êtes à jour. Découvrez sur quoi <a href=\"https://github.com/jokob-sk/NetAlertX/issues/138\" target=\"_blank\">je travaille</a>.",
"Maintenance_database_backup": "Sauvegardes de base de données", "Maintenance_database_backup": "Sauvegardes de base de données",
@@ -443,96 +447,96 @@
"Maintenance_database_backup_total": "utilisation totale du disque", "Maintenance_database_backup_total": "utilisation totale du disque",
"Maintenance_database_lastmod": "Dernière modification", "Maintenance_database_lastmod": "Dernière modification",
"Maintenance_database_path": "Chemin de la base de données", "Maintenance_database_path": "Chemin de la base de données",
"Maintenance_database_rows": "", "Maintenance_database_rows": "Table (Colonnes)",
"Maintenance_database_size": "", "Maintenance_database_size": "Taille de la base de données",
"Maintenance_lang_selector_apply": "Appliquer", "Maintenance_lang_selector_apply": "Appliquer",
"Maintenance_lang_selector_empty": "", "Maintenance_lang_selector_empty": "Choix de la langue",
"Maintenance_lang_selector_lable": "", "Maintenance_lang_selector_lable": "Sélectionner une langue",
"Maintenance_lang_selector_text": "", "Maintenance_lang_selector_text": "Le changement est effectué côté client, cela ne concerne donc que le navigateur actuel.",
"Maintenance_new_version": "", "Maintenance_new_version": "🆕 Une nouvelle version est disponible. Consulter les <a href=\"https://github.com/jokob-sk/NetAlertX/releases\" target=\"_blank\">notes de version</a>.",
"Maintenance_themeselector_apply": "Appliquer", "Maintenance_themeselector_apply": "Appliquer",
"Maintenance_themeselector_empty": "", "Maintenance_themeselector_empty": "Choisir un thème",
"Maintenance_themeselector_lable": "", "Maintenance_themeselector_lable": "Sélectionner un thème",
"Maintenance_themeselector_text": "", "Maintenance_themeselector_text": "Le changement s'effectue côté serveur, il s'applique donc à tous les appareils connectés à l'interface graphique.",
"Maintenance_version": "", "Maintenance_version": "Mises à jour de l'application",
"NETWORK_DEVICE_TYPES_description": "", "NETWORK_DEVICE_TYPES_description": "Les types d'appareils autorisés à verre utilisés comme appareils réseau dans la vue Réseau. Le type d'appareils doit être identique au paramètre <code>Type</code> d'un appareil dans le détail des appareils. Ne pas supprimer de valeurs, seulement en ajouter de nouvelles.",
"NETWORK_DEVICE_TYPES_name": "", "NETWORK_DEVICE_TYPES_name": "Type d'appareil réseau",
"Navigation_About": "À propos", "Navigation_About": "À propos",
"Navigation_Devices": "Appareils", "Navigation_Devices": "Appareils",
"Navigation_Donations": "Dons", "Navigation_Donations": "Dons",
"Navigation_Events": "Évènements", "Navigation_Events": "Évènements",
"Navigation_HelpFAQ": "Aide / FAQ", "Navigation_HelpFAQ": "Aide / FAQ",
"Navigation_Integrations": "", "Navigation_Integrations": "Intégrations",
"Navigation_Maintenance": "", "Navigation_Maintenance": "Maintenance",
"Navigation_Monitoring": "Surveillance", "Navigation_Monitoring": "Surveillance",
"Navigation_Network": "Réseau", "Navigation_Network": "Réseau",
"Navigation_Notifications": "", "Navigation_Notifications": "Notifications",
"Navigation_Plugins": "Greffons", "Navigation_Plugins": "Greffons",
"Navigation_Presence": "Présence", "Navigation_Presence": "Présence",
"Navigation_Report": "", "Navigation_Report": "Rapports transmis",
"Navigation_Settings": "Paramètres", "Navigation_Settings": "Paramètres",
"Navigation_SystemInfo": "Infos système", "Navigation_SystemInfo": "Infos système",
"Navigation_Workflows": "Flux de travail", "Navigation_Workflows": "Flux de travail",
"Network_Assign": "", "Network_Assign": "Se connecter à ce <i class=\"fa fa-server\"></i> nœud réseau",
"Network_Cant_Assign": "", "Network_Cant_Assign": "Impossible d'assigner le noeud racine Internet comme enfant d'un noeud.",
"Network_Configuration_Error": "", "Network_Configuration_Error": "Erreur de configuration",
"Network_Connected": "Appareils connectés", "Network_Connected": "Appareils connectés",
"Network_ManageAdd": "", "Network_ManageAdd": "Ajouter un appareil",
"Network_ManageAdd_Name": "", "Network_ManageAdd_Name": "Nom de l'appareil",
"Network_ManageAdd_Name_text": "", "Network_ManageAdd_Name_text": "Nom sans caractère spécial",
"Network_ManageAdd_Port": "", "Network_ManageAdd_Port": "Nombre de ports",
"Network_ManageAdd_Port_text": "", "Network_ManageAdd_Port_text": "laisser vide pour le wifi et le courant porteur (CPL)",
"Network_ManageAdd_Submit": "", "Network_ManageAdd_Submit": "Ajouter un appareil",
"Network_ManageAdd_Type": "", "Network_ManageAdd_Type": "Type d'appareil",
"Network_ManageAdd_Type_text": "", "Network_ManageAdd_Type_text": "-- Selectionner un type --",
"Network_ManageAssign": "Assigner", "Network_ManageAssign": "Assigner",
"Network_ManageDel": "", "Network_ManageDel": "Supprimer un appareil",
"Network_ManageDel_Name": "", "Network_ManageDel_Name": "Appareil à supprimer",
"Network_ManageDel_Name_text": "", "Network_ManageDel_Name_text": "-- Selectionner un appareil --",
"Network_ManageDel_Submit": "Supprimer", "Network_ManageDel_Submit": "Supprimer",
"Network_ManageDevices": "", "Network_ManageDevices": "Gérer les appareils",
"Network_ManageEdit": "", "Network_ManageEdit": "Mettre à jour un appareil",
"Network_ManageEdit_ID": "", "Network_ManageEdit_ID": "Appareil à mettre à jour",
"Network_ManageEdit_ID_text": "", "Network_ManageEdit_ID_text": "-- Sélectionner l'appareil à modifier --",
"Network_ManageEdit_Name": "", "Network_ManageEdit_Name": "Nouveau nom de l'appareil",
"Network_ManageEdit_Name_text": "", "Network_ManageEdit_Name_text": "Nom sans caractère spécial",
"Network_ManageEdit_Port": "", "Network_ManageEdit_Port": " Nouveau nombre de ports",
"Network_ManageEdit_Port_text": "", "Network_ManageEdit_Port_text": "laisser vide pour le wifi et le courant porteur (CPL)",
"Network_ManageEdit_Submit": "", "Network_ManageEdit_Submit": "Enregistrer les changements",
"Network_ManageEdit_Type": "", "Network_ManageEdit_Type": "Type du nouvel appareil",
"Network_ManageEdit_Type_text": "", "Network_ManageEdit_Type_text": "-- Sélectionner le type --",
"Network_ManageLeaf": "", "Network_ManageLeaf": "Gérer l'assignation",
"Network_ManageUnassign": "", "Network_ManageUnassign": "Désassigner",
"Network_NoAssignedDevices": "", "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": "", "Network_NoDevices": "Pas d'appareil à configurer",
"Network_Node": "", "Network_Node": "Nœud réseau",
"Network_Node_Name": "", "Network_Node_Name": "Nom du nœud",
"Network_Parent": "", "Network_Parent": "Appareil du réseau principal",
"Network_Root": "", "Network_Root": "Noeud racine",
"Network_Root_Not_Configured": "", "Network_Root_Not_Configured": "Pour commencer la configuration de cet écran, sélectionner un type d'appareil réseau, par exemple une <b>Gateway</b>, dans le champ <b>Type</b> de <a href=\"deviceDetails.php?mac=Internet\">l'appareil racine pour Internet</a> <br/><br/> Plus d'informations dans le guide <a href=\"https://github.com/jokob-sk/NetAlertX/blob/main/docs/NETWORK_TREE.md\" target=\"_blank\">Comment configurer votre page Réseau</a>",
"Network_Root_Unconfigurable": "", "Network_Root_Unconfigurable": "Racine non configurable",
"Network_Table_Hostname": "Nom de hôte", "Network_Table_Hostname": "Nom de hôte",
"Network_Table_IP": "IP", "Network_Table_IP": "IP",
"Network_Table_State": "État", "Network_Table_State": "État",
"Network_Title": "", "Network_Title": "Vue générale du réseau",
"Network_UnassignedDevices": "", "Network_UnassignedDevices": "Appareils non assignés",
"Notifications_All": "", "Notifications_All": "Toutes les notifications",
"Notifications_Mark_All_Read": "", "Notifications_Mark_All_Read": "Tout marquer comme lu",
"PIALERT_WEB_PASSWORD_description": "", "PIALERT_WEB_PASSWORD_description": "Le mot de passe par défaut est <code>123456</code>. Pour changer ce mot de passe, lancez depuis le container <code>/app/back/pialert-cli</code> ou utilisez le <a onclick=\"toggleAllSettings()\" href=\"#SETPWD_RUN\"><code>SETPWD_RUN</code>Plugin de définition de mot de passe (Set password)</a>.",
"PIALERT_WEB_PASSWORD_name": "", "PIALERT_WEB_PASSWORD_name": "Mot de passe de connexion",
"PIALERT_WEB_PROTECTION_description": "", "PIALERT_WEB_PROTECTION_description": "Quand activé, une fenêtre de connexion est affichée. Lisez attentivement ci-dessous dans le cas où vous ne pourriez plus vous connecter à votre instance.",
"PIALERT_WEB_PROTECTION_name": "", "PIALERT_WEB_PROTECTION_name": "Activer la connexion par login",
"PLUGINS_KEEP_HIST_description": "", "PLUGINS_KEEP_HIST_description": "Combien d'entrées de résultats de scan doivent être conservés dans l'historique des plugins (par plugin, pas par appareil).",
"PLUGINS_KEEP_HIST_name": "", "PLUGINS_KEEP_HIST_name": "Historique des plugins",
"Plugins_DeleteAll": "", "Plugins_DeleteAll": "Tout supprimer (ne prend pas en compte les filtres)",
"Plugins_Filters_Mac": "", "Plugins_Filters_Mac": "Filtrer par MAC",
"Plugins_History": "", "Plugins_History": "Historique des événements",
"Plugins_Objects": "", "Plugins_Objects": "Objets des plugins",
"Plugins_Out_of": "", "Plugins_Out_of": "sur",
"Plugins_Unprocessed_Events": "Événements non traités", "Plugins_Unprocessed_Events": "Événements non traités",
"Plugins_no_control": "", "Plugins_no_control": "Pas de formulaire trouvé pour afficher cette valeur.",
"Presence_CalHead_day": "jour", "Presence_CalHead_day": "jour",
"Presence_CalHead_lang": "", "Presence_CalHead_lang": "fr-fr",
"Presence_CalHead_month": "mois", "Presence_CalHead_month": "mois",
"Presence_CalHead_quarter": "trimestre", "Presence_CalHead_quarter": "trimestre",
"Presence_CalHead_week": "semaine", "Presence_CalHead_week": "semaine",
@@ -545,24 +549,25 @@
"Presence_Shortcut_Devices": "Appareils", "Presence_Shortcut_Devices": "Appareils",
"Presence_Shortcut_DownAlerts": "Alertes de panne", "Presence_Shortcut_DownAlerts": "Alertes de panne",
"Presence_Shortcut_Favorites": "Favoris", "Presence_Shortcut_Favorites": "Favoris",
"Presence_Shortcut_NewDevices": "", "Presence_Shortcut_NewDevices": "Nouveaux appareils",
"Presence_Title": "", "Presence_Title": "Présence par appareil",
"REPORT_DASHBOARD_URL_description": "", "REPORT_DASHBOARD_URL_description": "Cette URL est utilisée comme base pour générer les liens des rapports HTML (par ex. les courriels). Renseignez l'adresse complète, commençant par <code>http://</code> et incluznt le numero de port (sans slash <code>/</code> à la fin).",
"REPORT_DASHBOARD_URL_name": "", "REPORT_DASHBOARD_URL_name": "URL de NetAlertX",
"REPORT_ERROR": "", "REPORT_ERROR": "La page que vous cherchez est temporairement indisponible. Merci de réessayer dans quelques secondes",
"REPORT_MAIL_description": "", "REPORT_MAIL_description": "Si activé, un courriel est envoyé, avec la liste des changements pour lesquels on a souscrit. Cela nécessite de renseigner les paramètres associés au paramétrage SMTP plus bas. Si vous rencontrez des problèmes, positionnez le <code>LOG_LEVEL</code> au niveau <code>debug</code> et vérifiez les <a href=\"/maintenance.php#tab_Logging\">journaux d'erreurs</a>.",
"REPORT_MAIL_name": "", "REPORT_MAIL_name": "Activer les courriels",
"REPORT_TITLE": "", "REPORT_TITLE": "Rapport",
"RandomMAC_hover": "", "RandomMAC_hover": "Détecté automatiquement - indique si l'appareil dispose d'une adresse MAC générée aléatoirement.",
"Reports_Sent_Log": "", "Reports_Sent_Log": "Rapports de log transmis",
"SCAN_SUBNETS_description": "", "SCAN_SUBNETS_description": "La plupart des scanners sur le réseau (scan ARP, NMAP, Nslookup, DIG, Pholud) se base sur le scan d'une partie spécifique des interfaces réseau ou de sous-réseau. Consulter la <a href=\"https://github.com/jokob-sk/NetAlertX/blob/main/docs/SUBNETS.md\" target=\"_blank\">documentation des sous-réseaux</a> pour plus d'aide sur ce paramètre, notamment pour des VLAN, lesquels sont supportés ou sur comment identifier le masque réseau et votre interface réseau. <br/> <br/> Une alternative à ces scanner sur le réseau et d'activer d'autres scanners d'appareils ou des importe, qui ne dépendent pas du fait de laisser NetAlert<sup>X</sup> accéder au réseau (Unifié, baux DHCP, Pi-hole, etc.).<br/><br/> Remarque: la durée du scan en lui-même dépend du nombre d'adresses IP à scanner, renseignez donc soigneusement avec le bon masque réseau et la bonne interface réseau.",
"SCAN_SUBNETS_name": "",
"SYSTEM_TITLE": "Informations système", "SYSTEM_TITLE": "Informations système",
"Setting_Override": "", "Setting_Override": "Remplacer la valeur",
"Setting_Override_Description": "", "Setting_Override_Description": "Activer cette option va remplacer la valeur fournie par défaut par une application par la valeur renseignée au-dessus.",
"Settings_Metadata_Toggle": "", "Settings_Metadata_Toggle": "Afficher/masquer les méta données pour le paramètre sélectionné.",
"Settings_device_Scanners_desync": "", "Settings_device_Scanners_desync": "⚠ La planification des différents scanners d'appareils est désynchronisée.",
"Settings_device_Scanners_desync_popup": "", "Settings_device_Scanners_desync_popup": "La planification des scanners (<code>*_RUN_SCHD</code>) n'est pas identique entre scanners. Cela va entraîner des notifications en ligne/hors-ligne non cohérentes. À moins que cela soit attendu, utilisez la même planification pour tous les <b>🔍scanners d'appareils</b> activés.",
"Speedtest_Results": "", "Speedtest_Results": "Résultats du test de débit",
"Systeminfo_CPU": "Processeur", "Systeminfo_CPU": "Processeur",
"Systeminfo_CPU_Cores": "Cœurs de processeur:", "Systeminfo_CPU_Cores": "Cœurs de processeur:",
"Systeminfo_CPU_Name": "Nom du processeur:", "Systeminfo_CPU_Name": "Nom du processeur:",
@@ -578,7 +583,7 @@
"Systeminfo_General_TimeZone": "Fuseau horaire:", "Systeminfo_General_TimeZone": "Fuseau horaire:",
"Systeminfo_Memory": "Mémoire", "Systeminfo_Memory": "Mémoire",
"Systeminfo_Memory_Total_Memory": "Mémoire totale:", "Systeminfo_Memory_Total_Memory": "Mémoire totale:",
"Systeminfo_Memory_Usage": "Utilisation de la mémoire:", "Systeminfo_Memory_Usage": "Utilisation de la mémoire:",
"Systeminfo_Memory_Usage_Percent": "% de la mémoire:", "Systeminfo_Memory_Usage_Percent": "% de la mémoire:",
"Systeminfo_Motherboard": "Carte mère", "Systeminfo_Motherboard": "Carte mère",
"Systeminfo_Motherboard_BIOS": "BIOS:", "Systeminfo_Motherboard_BIOS": "BIOS:",
@@ -595,10 +600,10 @@
"Systeminfo_Network_HTTP_Referer": "Référent HTTP:", "Systeminfo_Network_HTTP_Referer": "Référent HTTP:",
"Systeminfo_Network_HTTP_Referer_String": "Pas de référent HTTP", "Systeminfo_Network_HTTP_Referer_String": "Pas de référent HTTP",
"Systeminfo_Network_Hardware": "Matériel réseau", "Systeminfo_Network_Hardware": "Matériel réseau",
"Systeminfo_Network_Hardware_Interface_Mask": "", "Systeminfo_Network_Hardware_Interface_Mask": "Masque réseau",
"Systeminfo_Network_Hardware_Interface_Name": "", "Systeminfo_Network_Hardware_Interface_Name": "Nom de l'interface réseau",
"Systeminfo_Network_Hardware_Interface_RX": "", "Systeminfo_Network_Hardware_Interface_RX": "Reçu",
"Systeminfo_Network_Hardware_Interface_TX": "", "Systeminfo_Network_Hardware_Interface_TX": "Émis",
"Systeminfo_Network_IP": "IP Internet:", "Systeminfo_Network_IP": "IP Internet:",
"Systeminfo_Network_IP_Connection": "Connexion IP:", "Systeminfo_Network_IP_Connection": "Connexion IP:",
"Systeminfo_Network_IP_Server": "IP du serveur:", "Systeminfo_Network_IP_Server": "IP du serveur:",
@@ -607,7 +612,7 @@
"Systeminfo_Network_Request_Time": "Heure de la demande:", "Systeminfo_Network_Request_Time": "Heure de la demande:",
"Systeminfo_Network_Request_URI": "URI de la demande:", "Systeminfo_Network_Request_URI": "URI de la demande:",
"Systeminfo_Network_Secure_Connection": "Connexion sécurisée:", "Systeminfo_Network_Secure_Connection": "Connexion sécurisée:",
"Systeminfo_Network_Secure_Connection_String": "", "Systeminfo_Network_Secure_Connection_String": "Non (HTTP)",
"Systeminfo_Network_Server_Name": "Nom du serveur:", "Systeminfo_Network_Server_Name": "Nom du serveur:",
"Systeminfo_Network_Server_Name_String": "Nom du serveur introuvable", "Systeminfo_Network_Server_Name_String": "Nom du serveur introuvable",
"Systeminfo_Network_Server_Query": "Requête du serveur:", "Systeminfo_Network_Server_Query": "Requête du serveur:",
@@ -621,73 +626,75 @@
"Systeminfo_Storage_Mount": "Point de montage:", "Systeminfo_Storage_Mount": "Point de montage:",
"Systeminfo_Storage_Size": "Taille:", "Systeminfo_Storage_Size": "Taille:",
"Systeminfo_Storage_Type": "Type:", "Systeminfo_Storage_Type": "Type:",
"Systeminfo_Storage_Usage": "", "Systeminfo_Storage_Usage": "Utilisation du stockage",
"Systeminfo_Storage_Usage_Free": "Libre:", "Systeminfo_Storage_Usage_Free": "Libre:",
"Systeminfo_Storage_Usage_Mount": "", "Systeminfo_Storage_Usage_Mount": "Point de montage:",
"Systeminfo_Storage_Usage_Total": "Total:", "Systeminfo_Storage_Usage_Total": "Total:",
"Systeminfo_Storage_Usage_Used": "Utilisé:", "Systeminfo_Storage_Usage_Used": "Utilisé:",
"Systeminfo_System": "Système", "Systeminfo_System": "Système",
"Systeminfo_System_AVG": "", "Systeminfo_System_AVG": "Charge moyenne:",
"Systeminfo_System_Architecture": "Architecture:", "Systeminfo_System_Architecture": "Architecture:",
"Systeminfo_System_Kernel": "Noyau:", "Systeminfo_System_Kernel": "Noyau:",
"Systeminfo_System_OSVersion": "", "Systeminfo_System_OSVersion": "Système d'exploitation:",
"Systeminfo_System_Running_Processes": "Processus en cours:", "Systeminfo_System_Running_Processes": "Processus en cours:",
"Systeminfo_System_System": "Système:", "Systeminfo_System_System": "Système:",
"Systeminfo_System_Uname": "", "Systeminfo_System_Uname": "Uname:",
"Systeminfo_System_Uptime": "", "Systeminfo_System_Uptime": "Durée d'activité:",
"Systeminfo_This_Client": "", "Systeminfo_This_Client": "Ce client",
"Systeminfo_USB_Devices": "", "Systeminfo_USB_Devices": "Appareils USB",
"TICKER_MIGRATE_TO_NETALERTX": "", "TICKER_MIGRATE_TO_NETALERTX": "⚠ Emplacement de point de montage obsolète détecté. Suivez <a href=\"https://github.com/jokob-sk/NetAlertX/blob/main/docs/MIGRATION.md\" target=\"_blank\">ce guide</a> pour migrer vers les nouveaux dossiers <code>/app/config</code> and <code>/app/db</code> et le container <code>netalertx</code>.",
"TIMEZONE_description": "", "TIMEZONE_description": "Fuseau horaire pour afficher correctement les statistiques. Trouvez votre fuseau horaire <a target=\"_blank\" href=\"https://en.wikipedia.org/wiki/List_of_tz_database_time_zones\" rel=\"nofollow\">ici</a>.",
"TIMEZONE_name": "", "TIMEZONE_name": "Fuseau horaire",
"UI_DEV_SECTIONS_description": "", "UI_DEV_SECTIONS_description": "Slecetionnez quels éléments de l'interface graphique masquer dans les pages des appareils.",
"UI_DEV_SECTIONS_name": "", "UI_DEV_SECTIONS_name": "Masquer des sections pour les appareils",
"UI_ICONS_description": "", "UI_ICONS_description": "Une liste d'icônes prédéfinies. Attention, la manière recommandée d'ajouter des icônes est décrite dans la <a href=\"https://github.com/jokob-sk/NetAlertX/blob/main/docs/ICONS.md\" target=\"_blank\">documentation des icônes</a>. Vous pouvez ajouter un lien HTML encodé en base 64 vers un SVG ou une étiquette d'icône Font Awesome.",
"UI_ICONS_name": "", "UI_ICONS_name": "Icones prédéfinies",
"UI_LANG_description": "Sélectionnez votre langue préféré de linterface. Aidez à traduire ou suggérez des langues dans le portail en ligne de <a href=\"https://hosted.weblate.org/projects/pialert/core/\" target=\"_blank\">Weblate</a>.", "UI_LANG_description": "Sélectionnez votre langue préféré de linterface. Aidez à traduire ou suggérez des langues dans le portail en ligne de <a href=\"https://hosted.weblate.org/projects/pialert/core/\" target=\"_blank\">Weblate</a>.",
"UI_LANG_name": "", "UI_LANG_name": "Langue de l'interface graphique",
"UI_MY_DEVICES_description": "", "UI_MY_DEVICES_description": "Les états autorisant les appareils à être affichés par défaut dans la vue <b>Mes appareils</b>. (<code>CTRL + Clic</code> pour sélectionner/desélectionner",
"UI_MY_DEVICES_name": "", "UI_MY_DEVICES_name": "Afficher dans la vue de mes appareils",
"UI_NOT_RANDOM_MAC_description": "", "UI_NOT_RANDOM_MAC_description": "Les préfixes d'adresses MAC à ne pas considérer comme généré aléatoirement pour les appareils. Renseignez par exemple <code>52</code> pour que les appareils commençant par <code>52:xx:xx:xx:xx:xx</code> ne soient pas considérés comme disposant d'une adresse MAC aléatoire.",
"UI_NOT_RANDOM_MAC_name": "Ne pas marquer comme aléatoire", "UI_NOT_RANDOM_MAC_name": "Ne pas marquer comme aléatoire",
"UI_PRESENCE_description": "", "UI_PRESENCE_description": "Sélectionner les états qui doivent être affichés dans le graphique de <b>Présence des appareils</b> de la page <a href=\"/devices.php\" target=\"_blank\">Appareils</a>. (<code>CTRL + Clic</code> pour sélectionner/désélectionner)",
"UI_PRESENCE_name": "", "UI_PRESENCE_name": "Afficher dans le graphique de présence",
"UI_REFRESH_description": "", "UI_REFRESH_description": "Renseignez le nombre de secondes après lequel rafraîchir l'interface graphique. Renseignez <code>0</code> pour désactiver.",
"UI_REFRESH_name": "", "UI_REFRESH_name": "Rafraîchir automatiquement l'interface graphique",
"devices_old": "", "VERSION_description": "",
"general_event_description": "", "VERSION_name": "",
"general_event_title": "", "devices_old": "Rafraichissement...",
"report_guid": "", "general_event_description": "L'événement que vous avez lancé peut prendre du temps avant que les tâches de fond ne soit terminées. La durée d'exécution finira une fois que la file d'exécution ci-dessous sera vide (consulter les <a href='/maintenance.php#tab_Logging'>journaux d'erreur</a> si vous rencontrez des erreurs). <br/> <br/> File d'exécution:",
"report_guid_missing": "", "general_event_title": "Lancement d'un événement sur mesure",
"report_select_format": "", "report_guid": "GUID de la notification:",
"report_time": "", "report_guid_missing": "La notification associée n'a pas été trouvée. Un petit délai existe entre l'envoi d'une notification et sa disponibilité réelle pour affichage. Rafraichissez la page et votre cache après quelques secondes. Il est aussi possible que la notification sélectionnée ait été supprimée durant une opération de maintenance, comme renseigné dans le paramètre <code>DBCLNP_NOTIFI_HIST</code>. <br/> <br/> La dernière notification est affichée à sa place. La notification manquante dispose du GUID suivant:",
"run_event_icon": "", "report_select_format": "Sélectionner un format:",
"run_event_tooltip": "", "report_time": "Heure de la notification:",
"settings_core_icon": "", "run_event_icon": "fa-play",
"settings_core_label": "", "run_event_tooltip": "Activez le paramètre et enregistrez vos changements avant de le lancer.",
"settings_device_scanners": "", "settings_core_icon": "fa-solid fa-gem",
"settings_device_scanners_icon": "", "settings_core_label": "Principal",
"settings_device_scanners_info": "", "settings_device_scanners": "Les scanners d'appareils utilisés pour découvrir des appareils, qui écrivent dans la table CurrentScan (scan actuel) de la base de données.",
"settings_device_scanners_icon": "fa-solid fa-magnifying-glass-plus",
"settings_device_scanners_info": "Chargez plus de scanners d'appareils avec le paramètre <a href=\"/settings.php#LOADED_PLUGINS\">LOADED_PLUGINS</a>",
"settings_device_scanners_label": "Scanners d'appareils", "settings_device_scanners_label": "Scanners d'appareils",
"settings_enabled": "Paramètres activés", "settings_enabled": "Paramètres activés",
"settings_enabled_icon": "", "settings_enabled_icon": "fa-solid fa-toggle-on",
"settings_expand_all": "Tout développer", "settings_expand_all": "Tout développer",
"settings_imported": "", "settings_imported": "Dernier import des paramètres depuis le fichier app.conf",
"settings_imported_label": "Paramètres importés", "settings_imported_label": "Paramètres importés",
"settings_missing": "", "settings_missing": "Tous les paramètres n'ont pas été chargés! La base de données est trop sollicitée, ou bien la séquence de démarrage de l'application est trop lourde. Cliquez sur le bouton de rafraîchissement 🔄 en haut.",
"settings_missing_block": "", "settings_missing_block": "Erreur: les paramètres ne sont pas correctement chargés. Cliquer sur le bouton de rafraîchissement 🔄 en haut; sinon, vous pouvez vérifier les journaux du navigateur pour plus de détails (F12).",
"settings_old": "Importation des paramètres et réinitialisation...", "settings_old": "Importation des paramètres et réinitialisation...",
"settings_other_scanners": "", "settings_other_scanners": "Autres plugins activés, hors scanners d'appareils.",
"settings_other_scanners_icon": "", "settings_other_scanners_icon": "fa-solid fa-recycle",
"settings_other_scanners_label": "", "settings_other_scanners_label": "Autres scanners",
"settings_publishers": "", "settings_publishers": "Activer les passerelles de publication de notifications, qui enverront une notification en fonction de vos paramètres renseignés.",
"settings_publishers_icon": "", "settings_publishers_icon": "fa-solid fa-paper-plane",
"settings_publishers_info": "", "settings_publishers_info": "Charger plus de passerelles de publication avec le paramètre <a href=\"/settings.php#LOADED_PLUGINS\">LOADED_PLUGINS</a>",
"settings_publishers_label": "Éditeurs", "settings_publishers_label": "Passerelles de publication",
"settings_saved": "", "settings_saved": "<br/>Paramètres enregistrés. <br/> Rechargement... <br/><i class=\"ion ion-ios-loop-strong fa-spin fa-2x fa-fw\"></i> <br/>",
"settings_system_icon": "", "settings_system_icon": "fa-solid fa-gear",
"settings_system_label": "Système", "settings_system_label": "Système",
"settings_update_item_warning": "", "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_icon": "", "test_event_icon": "fa-vial-circle-check",
"test_event_tooltip": "" "test_event_tooltip": "Enregistrer d'abord vos modifications avant de tester vôtre paramétrage."
} }

View File

@@ -56,6 +56,8 @@
"BackDevices_Restore_okay": "Ripristino eseguito correttamente.", "BackDevices_Restore_okay": "Ripristino eseguito correttamente.",
"BackDevices_darkmode_disabled": "Modalità scura disabilitata", "BackDevices_darkmode_disabled": "Modalità scura disabilitata",
"BackDevices_darkmode_enabled": "Modalità scura abilitata", "BackDevices_darkmode_enabled": "Modalità scura abilitata",
"CLEAR_NEW_FLAG_description": "",
"CLEAR_NEW_FLAG_name": "",
"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_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", "DAYS_TO_KEEP_EVENTS_name": "Elimina eventi più vecchi di",
"DevDetail_Copy_Device_Title": "<i class=\"fa fa-copy\"></i> Copia dettagli dal dispositivo", "DevDetail_Copy_Device_Title": "<i class=\"fa fa-copy\"></i> Copia dettagli dal dispositivo",
@@ -274,6 +276,7 @@
"Gen_AreYouSure": "Sei sicuro?", "Gen_AreYouSure": "Sei sicuro?",
"Gen_Backup": "Esegui backup", "Gen_Backup": "Esegui backup",
"Gen_Cancel": "Annulla", "Gen_Cancel": "Annulla",
"Gen_Change": "Modifica",
"Gen_Copy": "Esegui", "Gen_Copy": "Esegui",
"Gen_DataUpdatedUITakesTime": "OK: l'aggiornamento dell'interfaccia utente potrebbe richiedere del tempo se è in esecuzione una scansione.", "Gen_DataUpdatedUITakesTime": "OK: l'aggiornamento dell'interfaccia utente potrebbe richiedere del tempo se è in esecuzione una scansione.",
"Gen_Delete": "Elimina", "Gen_Delete": "Elimina",
@@ -292,6 +295,7 @@
"Gen_Save": "Salva", "Gen_Save": "Salva",
"Gen_Saved": "Salvato", "Gen_Saved": "Salvato",
"Gen_Search": "Cerca", "Gen_Search": "Cerca",
"Gen_SelectToPreview": "",
"Gen_Selected_Devices": "Dispositivi selezionati:", "Gen_Selected_Devices": "Dispositivi selezionati:",
"Gen_Switch": "Cambia", "Gen_Switch": "Cambia",
"Gen_Upd": "Aggiornato correttamente", "Gen_Upd": "Aggiornato correttamente",
@@ -556,6 +560,7 @@
"RandomMAC_hover": "Rilevato automaticamente: indica se il dispositivo genera il suo indirizzo MAC casualmente.", "RandomMAC_hover": "Rilevato automaticamente: indica se il dispositivo genera il suo indirizzo MAC casualmente.",
"Reports_Sent_Log": "Log rapporti inviati", "Reports_Sent_Log": "Log rapporti inviati",
"SCAN_SUBNETS_description": "La maggior parte degli scanner di rete (ARP-SCAN, NMAP, NSLOOKUP, DIG, PHOLUS) si basano sulla scansione di interfacce di rete e sottoreti specifiche. Consulta la <a href=\"https://github.com/jokob-sk/NetAlertX/blob/main/docs/SUBNETS.md\" target=\"_blank\">documentazione sulle sottoreti</a> per assistenza su questa impostazione, in particolare VLAN, quali VLAN sono supportate o come individuare la maschera di rete e l'interfaccia. <br/> <br/> Un'alternativa agli scanner in rete è abilitare altri scanner/importatori di dispositivi che non si affidano a NetAlert<sup>X</sup> che hanno accesso alla rete (UNIFI, dhcp.leases , PiHole, ecc.). <br/> <br/> Nota: il tempo di scansione stesso dipende dal numero di indirizzi IP da controllare, quindi impostalo attentamente con la maschera di rete e l'interfaccia appropriate.", "SCAN_SUBNETS_description": "La maggior parte degli scanner di rete (ARP-SCAN, NMAP, NSLOOKUP, DIG, PHOLUS) si basano sulla scansione di interfacce di rete e sottoreti specifiche. Consulta la <a href=\"https://github.com/jokob-sk/NetAlertX/blob/main/docs/SUBNETS.md\" target=\"_blank\">documentazione sulle sottoreti</a> per assistenza su questa impostazione, in particolare VLAN, quali VLAN sono supportate o come individuare la maschera di rete e l'interfaccia. <br/> <br/> Un'alternativa agli scanner in rete è abilitare altri scanner/importatori di dispositivi che non si affidano a NetAlert<sup>X</sup> che hanno accesso alla rete (UNIFI, dhcp.leases , PiHole, ecc.). <br/> <br/> Nota: il tempo di scansione stesso dipende dal numero di indirizzi IP da controllare, quindi impostalo attentamente con la maschera di rete e l'interfaccia appropriate.",
"SCAN_SUBNETS_name": "",
"SYSTEM_TITLE": "Informazioni sistema", "SYSTEM_TITLE": "Informazioni sistema",
"Setting_Override": "Sovrascrivi valore", "Setting_Override": "Sovrascrivi valore",
"Setting_Override_Description": "L'abilitazione di questa opzione sovrascriverà il valore predefinito fornito dall'app con il valore specificato sopra.", "Setting_Override_Description": "L'abilitazione di questa opzione sovrascriverà il valore predefinito fornito dall'app con il valore specificato sopra.",
@@ -654,6 +659,8 @@
"UI_PRESENCE_name": "Mostra nel grafico delle presenze", "UI_PRESENCE_name": "Mostra nel grafico delle presenze",
"UI_REFRESH_description": "Inserisci il numero di secondi dopo il quale la UI si ricarica. Imposta a <code>0</code> per disabilitare.", "UI_REFRESH_description": "Inserisci il numero di secondi dopo il quale la UI si ricarica. Imposta a <code>0</code> per disabilitare.",
"UI_REFRESH_name": "Aggiorna automaticamente la UI", "UI_REFRESH_name": "Aggiorna automaticamente la UI",
"VERSION_description": "Valore di supporto della versione o della marca temporale per verificare se l'app è stata aggiornata.",
"VERSION_name": "Versione o marca temporale",
"devices_old": "Aggiornamento...", "devices_old": "Aggiornamento...",
"general_event_description": "L'evento che hai attivato potrebbe richiedere del tempo prima che i processi in background vengano completati. L'esecuzione è terminata una volta che la coda di esecuzione sottostante si è svuotata (controlla il <a href='/maintenance.php#tab_Logging'>log degli errori</a> se riscontri problemi). <br/> <br/> Coda di esecuzione:", "general_event_description": "L'evento che hai attivato potrebbe richiedere del tempo prima che i processi in background vengano completati. L'esecuzione è terminata una volta che la coda di esecuzione sottostante si è svuotata (controlla il <a href='/maintenance.php#tab_Logging'>log degli errori</a> se riscontri problemi). <br/> <br/> Coda di esecuzione:",
"general_event_title": "Esecuzione di un evento ad-hoc", "general_event_title": "Esecuzione di un evento ad-hoc",
@@ -690,4 +697,4 @@
"settings_update_item_warning": "Aggiorna il valore qui sotto. Fai attenzione a seguire il formato precedente. <b>La convalida non viene eseguita.</b>", "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_icon": "fa-vial-circle-check", "test_event_icon": "fa-vial-circle-check",
"test_event_tooltip": "Salva le modifiche prima di provare le nuove impostazioni." "test_event_tooltip": "Salva le modifiche prima di provare le nuove impostazioni."
} }

View File

@@ -5,7 +5,8 @@
// ################################### // ###################################
$defaultLang = "en_us"; $defaultLang = "en_us";
$allLanguages = ["en_us","es_es","de_de", "nb_no", "pl_pl", "pt_br", "ru_ru", "fr_fr", "it_it", "zh_cn", "cs_cz"]; $allLanguages = ["en_us", "es_es", "de_de", "fr_fr", "it_it", "ru_ru", "nb_no", "pl_pl", "pt_br", "tr_tr", "zh_cn", "cs_cz"];
global $db; global $db;

View File

@@ -56,6 +56,8 @@
"BackDevices_Restore_okay": "Gjenoppretting utført.", "BackDevices_Restore_okay": "Gjenoppretting utført.",
"BackDevices_darkmode_disabled": "Mørk modus Deaktivert", "BackDevices_darkmode_disabled": "Mørk modus Deaktivert",
"BackDevices_darkmode_enabled": "Mørk modus Aktivert", "BackDevices_darkmode_enabled": "Mørk modus Aktivert",
"CLEAR_NEW_FLAG_description": "",
"CLEAR_NEW_FLAG_name": "",
"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_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", "DAYS_TO_KEEP_EVENTS_name": "Slett hendelser eldre enn",
"DevDetail_Copy_Device_Title": "<i class=\"fa fa-copy\"></i> Kopier detaljer fra enhet", "DevDetail_Copy_Device_Title": "<i class=\"fa fa-copy\"></i> Kopier detaljer fra enhet",
@@ -274,6 +276,7 @@
"Gen_AreYouSure": "Er du sikker?", "Gen_AreYouSure": "Er du sikker?",
"Gen_Backup": "Kjør sikkerhetskopiering", "Gen_Backup": "Kjør sikkerhetskopiering",
"Gen_Cancel": "Avbryt", "Gen_Cancel": "Avbryt",
"Gen_Change": "",
"Gen_Copy": "Kjør", "Gen_Copy": "Kjør",
"Gen_DataUpdatedUITakesTime": "OK - Det kan ta litt tid før brukergrensesnittet oppdateres hvis en skanning kjøres.", "Gen_DataUpdatedUITakesTime": "OK - Det kan ta litt tid før brukergrensesnittet oppdateres hvis en skanning kjøres.",
"Gen_Delete": "Slett", "Gen_Delete": "Slett",
@@ -292,6 +295,7 @@
"Gen_Save": "Lagre", "Gen_Save": "Lagre",
"Gen_Saved": "Lagret", "Gen_Saved": "Lagret",
"Gen_Search": "Søk", "Gen_Search": "Søk",
"Gen_SelectToPreview": "",
"Gen_Selected_Devices": "Valgte Enheter:", "Gen_Selected_Devices": "Valgte Enheter:",
"Gen_Switch": "Bytt", "Gen_Switch": "Bytt",
"Gen_Upd": "Oppdatering vellykket", "Gen_Upd": "Oppdatering vellykket",
@@ -556,6 +560,7 @@
"RandomMAC_hover": "Autodetektert - indikerer om enheten randomiserer MAC-adressen sin.", "RandomMAC_hover": "Autodetektert - indikerer om enheten randomiserer MAC-adressen sin.",
"Reports_Sent_Log": "Sendte rapport logger", "Reports_Sent_Log": "Sendte rapport logger",
"SCAN_SUBNETS_description": "De fleste skannere på nettet (ARP-Scan, NMAP, NSlookup, Dig, Pholus) er avhengige av å skanne spesifikke nettverksgrensesnitt og undernett. Sjekk <a href=\"https://github.com/jokob-sk/NetAlertX/blob/main/docs/SUBNETS.md\" target=\"_blank\">subnett dokumentasjonen</a> for hjelp på denne innstillingen, spesielt VLAN-er, hvilke VLAN-er som støttes, eller hvordan du kan finne ut nettverksmasken og grensesnittet ditt. <br/> <br/> Et alternativ til skannere på nettet er å aktivere noen andre enhetsskannere/importører som ikke er avhengige av Netalert<sup>X</sup> med tilgang til nettverket (UniFi, DHCP-Leaser, Pihole, osv.). <br/> <br/> Merk: Selve skanningstiden avhenger av antall IP -adresser som skal sjekkes, så sett dette opp nøye med riktig nettverksmaske og grensesnitt.", "SCAN_SUBNETS_description": "De fleste skannere på nettet (ARP-Scan, NMAP, NSlookup, Dig, Pholus) er avhengige av å skanne spesifikke nettverksgrensesnitt og undernett. Sjekk <a href=\"https://github.com/jokob-sk/NetAlertX/blob/main/docs/SUBNETS.md\" target=\"_blank\">subnett dokumentasjonen</a> for hjelp på denne innstillingen, spesielt VLAN-er, hvilke VLAN-er som støttes, eller hvordan du kan finne ut nettverksmasken og grensesnittet ditt. <br/> <br/> Et alternativ til skannere på nettet er å aktivere noen andre enhetsskannere/importører som ikke er avhengige av Netalert<sup>X</sup> med tilgang til nettverket (UniFi, DHCP-Leaser, Pihole, osv.). <br/> <br/> Merk: Selve skanningstiden avhenger av antall IP -adresser som skal sjekkes, så sett dette opp nøye med riktig nettverksmaske og grensesnitt.",
"SCAN_SUBNETS_name": "",
"SYSTEM_TITLE": "Systeminformasjon", "SYSTEM_TITLE": "Systeminformasjon",
"Setting_Override": "Overstyr verdi", "Setting_Override": "Overstyr verdi",
"Setting_Override_Description": "Aktivering av dette alternativet vil overstyre en App som leveres standard-verdi med verdien som er spesifisert ovenfor.", "Setting_Override_Description": "Aktivering av dette alternativet vil overstyre en App som leveres standard-verdi med verdien som er spesifisert ovenfor.",
@@ -654,6 +659,8 @@
"UI_PRESENCE_name": "Vis i tilstedeværelse-diagrammet", "UI_PRESENCE_name": "Vis i tilstedeværelse-diagrammet",
"UI_REFRESH_description": "Skriv inn antall sekunder før UI laster inn på nytt. Sett til <code>0</code> for å deaktivere.", "UI_REFRESH_description": "Skriv inn antall sekunder før UI laster inn på nytt. Sett til <code>0</code> for å deaktivere.",
"UI_REFRESH_name": "Oppdater UI automatisk", "UI_REFRESH_name": "Oppdater UI automatisk",
"VERSION_description": "",
"VERSION_name": "",
"devices_old": "Oppdaterer...", "devices_old": "Oppdaterer...",
"general_event_description": "Hendelsen du har utløst kan ta en stund til før bakgrunnsprosesser er ferdig. Utførelsen ble avsluttet når utførelseskøen nedenfor tømmes (sjekk <a href='/maintenance.php#tab_Logging'>Feillogg</a> Hvis du møter problemer). <br/> <br/> Utførelseskø:", "general_event_description": "Hendelsen du har utløst kan ta en stund til før bakgrunnsprosesser er ferdig. Utførelsen ble avsluttet når utførelseskøen nedenfor tømmes (sjekk <a href='/maintenance.php#tab_Logging'>Feillogg</a> Hvis du møter problemer). <br/> <br/> Utførelseskø:",
"general_event_title": "Utfører en ad-hoc hendelse", "general_event_title": "Utfører en ad-hoc hendelse",
@@ -690,4 +697,4 @@
"settings_update_item_warning": "Oppdater verdien nedenfor. Pass på å følge forrige format. <b>Validering etterpå utføres ikke.</b>", "settings_update_item_warning": "Oppdater verdien nedenfor. Pass på å følge forrige format. <b>Validering etterpå utføres ikke.</b>",
"test_event_icon": "fa-vial-circle-check", "test_event_icon": "fa-vial-circle-check",
"test_event_tooltip": "Lagre endringene først, før du tester innstillingene dine." "test_event_tooltip": "Lagre endringene først, før du tester innstillingene dine."
} }

View File

@@ -56,6 +56,8 @@
"BackDevices_Restore_okay": "Przywracanie wykonane z sukcesem.", "BackDevices_Restore_okay": "Przywracanie wykonane z sukcesem.",
"BackDevices_darkmode_disabled": "Tryb ciemny Wyłączony", "BackDevices_darkmode_disabled": "Tryb ciemny Wyłączony",
"BackDevices_darkmode_enabled": "Tryb ciemny Włączony", "BackDevices_darkmode_enabled": "Tryb ciemny Włączony",
"CLEAR_NEW_FLAG_description": "",
"CLEAR_NEW_FLAG_name": "",
"DAYS_TO_KEEP_EVENTS_description": "To jest ustawienie konserwacji. Określa ile dni mają być utrzymywane wpisy wydarzeń. Wszystkie starsze wpisy wydarzeń zostaną usunięte okresowo. Dotyczy także Historii Wydarzeń Pluginów.", "DAYS_TO_KEEP_EVENTS_description": "To jest ustawienie konserwacji. Określa ile dni mają być utrzymywane wpisy wydarzeń. Wszystkie starsze wpisy wydarzeń zostaną usunięte okresowo. Dotyczy także Historii Wydarzeń Pluginów.",
"DAYS_TO_KEEP_EVENTS_name": "Usuń wydarzenia starsze niż", "DAYS_TO_KEEP_EVENTS_name": "Usuń wydarzenia starsze niż",
"DevDetail_Copy_Device_Title": "<i class=\"fa fa-copy\"></i>Kopiuj opis z urządzenia", "DevDetail_Copy_Device_Title": "<i class=\"fa fa-copy\"></i>Kopiuj opis z urządzenia",
@@ -274,6 +276,7 @@
"Gen_AreYouSure": "Jesteś pewien?", "Gen_AreYouSure": "Jesteś pewien?",
"Gen_Backup": "Wykonaj Kopie Zapasową", "Gen_Backup": "Wykonaj Kopie Zapasową",
"Gen_Cancel": "Anuluj", "Gen_Cancel": "Anuluj",
"Gen_Change": "",
"Gen_Copy": "Wykonaj", "Gen_Copy": "Wykonaj",
"Gen_DataUpdatedUITakesTime": "OK - Aktualizacja UI może chwile potrwać jeżeli wykonywany jest skan.", "Gen_DataUpdatedUITakesTime": "OK - Aktualizacja UI może chwile potrwać jeżeli wykonywany jest skan.",
"Gen_Delete": "Usuń", "Gen_Delete": "Usuń",
@@ -292,6 +295,7 @@
"Gen_Save": "Zapisz", "Gen_Save": "Zapisz",
"Gen_Saved": "Zapisano", "Gen_Saved": "Zapisano",
"Gen_Search": "Szukaj", "Gen_Search": "Szukaj",
"Gen_SelectToPreview": "",
"Gen_Selected_Devices": "Wybierz Urządzenia:", "Gen_Selected_Devices": "Wybierz Urządzenia:",
"Gen_Switch": "Switch", "Gen_Switch": "Switch",
"Gen_Upd": "Zaktualizowane poprawnie", "Gen_Upd": "Zaktualizowane poprawnie",
@@ -556,6 +560,7 @@
"RandomMAC_hover": "Auto wykrywanie - oznacza czy urządzenie randomizuje swój adres MAC.", "RandomMAC_hover": "Auto wykrywanie - oznacza czy urządzenie randomizuje swój adres MAC.",
"Reports_Sent_Log": "Wyślij zgłoszenie logów", "Reports_Sent_Log": "Wyślij zgłoszenie logów",
"SCAN_SUBNETS_description": "Większość skanerów sieciowych (ARP-SCAN, NMAP, NSLOOKUP, DIG, PHOLUS) opiera się na konkretnych interfejsach sieciowych oraz podsieci. Sprawdź <a href=\"https://github.com/jokob-sk/NetAlertX/blob/main/docs/SUBNETS.md\" target=\"_blank\"> dokumentacji podsieci</a> jeżeli potrzebujesz pomocy w ustawieniach, a szczególnie z VLAN'ami, jakie VLAN'y są wspierane oraz jak rozgryźć maskę podsieci twojego interfejsu.<br/><br/> Alternatywą do skanerów sieciowych jest uruchomienie innego Skanera Urządzeń/Importera który nie polega by NetAlert<sup>X</sup> miał dostęp do sieci (UNIFI, dhcp.leases, PiHole, itp.).<br/><br/> Notatka: Czas skanu zależy od liczby adresów IP do sprawdzenia, więc ustaw go tak by skanował odpowiedni interfejs i maskę sieciową.", "SCAN_SUBNETS_description": "Większość skanerów sieciowych (ARP-SCAN, NMAP, NSLOOKUP, DIG, PHOLUS) opiera się na konkretnych interfejsach sieciowych oraz podsieci. Sprawdź <a href=\"https://github.com/jokob-sk/NetAlertX/blob/main/docs/SUBNETS.md\" target=\"_blank\"> dokumentacji podsieci</a> jeżeli potrzebujesz pomocy w ustawieniach, a szczególnie z VLAN'ami, jakie VLAN'y są wspierane oraz jak rozgryźć maskę podsieci twojego interfejsu.<br/><br/> Alternatywą do skanerów sieciowych jest uruchomienie innego Skanera Urządzeń/Importera który nie polega by NetAlert<sup>X</sup> miał dostęp do sieci (UNIFI, dhcp.leases, PiHole, itp.).<br/><br/> Notatka: Czas skanu zależy od liczby adresów IP do sprawdzenia, więc ustaw go tak by skanował odpowiedni interfejs i maskę sieciową.",
"SCAN_SUBNETS_name": "",
"SYSTEM_TITLE": "Informacje o Systemie", "SYSTEM_TITLE": "Informacje o Systemie",
"Setting_Override": "Nadpisz wartość", "Setting_Override": "Nadpisz wartość",
"Setting_Override_Description": "Włączanie tej opcji nadpisze podstawową wartość na wartość podaną powyżej.", "Setting_Override_Description": "Włączanie tej opcji nadpisze podstawową wartość na wartość podaną powyżej.",
@@ -654,6 +659,8 @@
"UI_PRESENCE_name": "Pokaż w tabeli obecności", "UI_PRESENCE_name": "Pokaż w tabeli obecności",
"UI_REFRESH_description": "Wprowadź liczbę sekund po której UI ma się przeładować. Ustaw na <code>0</code> by wyłączyć.", "UI_REFRESH_description": "Wprowadź liczbę sekund po której UI ma się przeładować. Ustaw na <code>0</code> by wyłączyć.",
"UI_REFRESH_name": "Automatycznie odświeżaj UI", "UI_REFRESH_name": "Automatycznie odświeżaj UI",
"VERSION_description": "",
"VERSION_name": "",
"devices_old": "Odświeżanie...", "devices_old": "Odświeżanie...",
"general_event_description": "Wydarzenie które wyzwoliłeś może chwilę zająć dopóki procesy w tle nie zakończą się. Wykonanie zakończy się kiedy kolejka się opróżni (Sprawdź <a href='/maintenance.php#tab_Logging'>logi błędów</a> jeżeli napotkasz błędy).<br/><br/> Kolejka wykonywania:", "general_event_description": "Wydarzenie które wyzwoliłeś może chwilę zająć dopóki procesy w tle nie zakończą się. Wykonanie zakończy się kiedy kolejka się opróżni (Sprawdź <a href='/maintenance.php#tab_Logging'>logi błędów</a> jeżeli napotkasz błędy).<br/><br/> Kolejka wykonywania:",
"general_event_title": "Wykonywanie wydarzeń ad-hoc", "general_event_title": "Wykonywanie wydarzeń ad-hoc",
@@ -690,4 +697,4 @@
"settings_update_item_warning": "Zaktualizuj poniższą wartość. Zachowaj ostrożność i postępuj zgodnie z poprzednim formatem. <b>Walidacja nie jest wykonywana.</b>", "settings_update_item_warning": "Zaktualizuj poniższą wartość. Zachowaj ostrożność i postępuj zgodnie z poprzednim formatem. <b>Walidacja nie jest wykonywana.</b>",
"test_event_icon": "fa-vial-circle-check", "test_event_icon": "fa-vial-circle-check",
"test_event_tooltip": "Zapisz zmiany zanim będziesz testować swoje ustawienia." "test_event_tooltip": "Zapisz zmiany zanim będziesz testować swoje ustawienia."
} }

View File

@@ -56,6 +56,8 @@
"BackDevices_Restore_okay": "Restauração executada com sucesso.", "BackDevices_Restore_okay": "Restauração executada com sucesso.",
"BackDevices_darkmode_disabled": "Modo Noturno Desabilitado", "BackDevices_darkmode_disabled": "Modo Noturno Desabilitado",
"BackDevices_darkmode_enabled": "Modo Noturno Habilitado", "BackDevices_darkmode_enabled": "Modo Noturno Habilitado",
"CLEAR_NEW_FLAG_description": "",
"CLEAR_NEW_FLAG_name": "",
"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_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", "DAYS_TO_KEEP_EVENTS_name": "Excluir eventos mais antigos que",
"DevDetail_Copy_Device_Title": "<i class=\"fa fa-copy\"></i> Copiar detalhes do dispositivo", "DevDetail_Copy_Device_Title": "<i class=\"fa fa-copy\"></i> Copiar detalhes do dispositivo",
@@ -274,6 +276,7 @@
"Gen_AreYouSure": "Tem certeza?", "Gen_AreYouSure": "Tem certeza?",
"Gen_Backup": "Executar backup", "Gen_Backup": "Executar backup",
"Gen_Cancel": "Cancelar", "Gen_Cancel": "Cancelar",
"Gen_Change": "",
"Gen_Copy": "Executar", "Gen_Copy": "Executar",
"Gen_DataUpdatedUITakesTime": "OK - Pode levar um tempo para a interface do usuário ser atualizada se uma verificação estiver em execução.", "Gen_DataUpdatedUITakesTime": "OK - Pode levar um tempo para a interface do usuário ser atualizada se uma verificação estiver em execução.",
"Gen_Delete": "Excluir", "Gen_Delete": "Excluir",
@@ -292,6 +295,7 @@
"Gen_Save": "Salvar", "Gen_Save": "Salvar",
"Gen_Saved": "Salvo", "Gen_Saved": "Salvo",
"Gen_Search": "Procurar", "Gen_Search": "Procurar",
"Gen_SelectToPreview": "",
"Gen_Selected_Devices": "Dispositivos selecionados:", "Gen_Selected_Devices": "Dispositivos selecionados:",
"Gen_Switch": "Trocar", "Gen_Switch": "Trocar",
"Gen_Upd": "Atualizado com sucesso", "Gen_Upd": "Atualizado com sucesso",
@@ -556,6 +560,7 @@
"RandomMAC_hover": "", "RandomMAC_hover": "",
"Reports_Sent_Log": "", "Reports_Sent_Log": "",
"SCAN_SUBNETS_description": "", "SCAN_SUBNETS_description": "",
"SCAN_SUBNETS_name": "",
"SYSTEM_TITLE": "", "SYSTEM_TITLE": "",
"Setting_Override": "", "Setting_Override": "",
"Setting_Override_Description": "", "Setting_Override_Description": "",
@@ -654,6 +659,8 @@
"UI_PRESENCE_name": "", "UI_PRESENCE_name": "",
"UI_REFRESH_description": "", "UI_REFRESH_description": "",
"UI_REFRESH_name": "", "UI_REFRESH_name": "",
"VERSION_description": "",
"VERSION_name": "",
"devices_old": "", "devices_old": "",
"general_event_description": "", "general_event_description": "",
"general_event_title": "", "general_event_title": "",
@@ -690,4 +697,4 @@
"settings_update_item_warning": "", "settings_update_item_warning": "",
"test_event_icon": "", "test_event_icon": "",
"test_event_tooltip": "" "test_event_tooltip": ""
} }

View File

@@ -56,6 +56,8 @@
"BackDevices_Restore_okay": "Восстановление выполнено успешно.", "BackDevices_Restore_okay": "Восстановление выполнено успешно.",
"BackDevices_darkmode_disabled": "Темный режим отключен", "BackDevices_darkmode_disabled": "Темный режим отключен",
"BackDevices_darkmode_enabled": "Темный режим включен", "BackDevices_darkmode_enabled": "Темный режим включен",
"CLEAR_NEW_FLAG_description": "",
"CLEAR_NEW_FLAG_name": "",
"DAYS_TO_KEEP_EVENTS_description": "Это настройка обслуживания. Здесь указывается количество дней, в течение которых будут храниться записи о событиях. Все старые события будут периодически удаляться. Также применимо к истории событий плагина.", "DAYS_TO_KEEP_EVENTS_description": "Это настройка обслуживания. Здесь указывается количество дней, в течение которых будут храниться записи о событиях. Все старые события будут периодически удаляться. Также применимо к истории событий плагина.",
"DAYS_TO_KEEP_EVENTS_name": "Удалить события старше", "DAYS_TO_KEEP_EVENTS_name": "Удалить события старше",
"DevDetail_Copy_Device_Title": "<i class=\"fa fa-copy\"></i> Скопировать данные с устройства", "DevDetail_Copy_Device_Title": "<i class=\"fa fa-copy\"></i> Скопировать данные с устройства",
@@ -274,6 +276,7 @@
"Gen_AreYouSure": "Вы уверены?", "Gen_AreYouSure": "Вы уверены?",
"Gen_Backup": "Запустить резервное копирование", "Gen_Backup": "Запустить резервное копирование",
"Gen_Cancel": "Отмена", "Gen_Cancel": "Отмена",
"Gen_Change": "Изменить",
"Gen_Copy": "Запустить", "Gen_Copy": "Запустить",
"Gen_DataUpdatedUITakesTime": "ОК - Обновление UI может занять некоторое время, если сканирование выполняется.", "Gen_DataUpdatedUITakesTime": "ОК - Обновление UI может занять некоторое время, если сканирование выполняется.",
"Gen_Delete": "Удалить", "Gen_Delete": "Удалить",
@@ -292,6 +295,7 @@
"Gen_Save": "Сохранить", "Gen_Save": "Сохранить",
"Gen_Saved": "Сохранено", "Gen_Saved": "Сохранено",
"Gen_Search": "Поиск", "Gen_Search": "Поиск",
"Gen_SelectToPreview": "",
"Gen_Selected_Devices": "Выбранные устройства:", "Gen_Selected_Devices": "Выбранные устройства:",
"Gen_Switch": "Переключить", "Gen_Switch": "Переключить",
"Gen_Upd": "Успешное обновление", "Gen_Upd": "Успешное обновление",
@@ -416,7 +420,7 @@
"Maintenance_Tool_del_unknowndev_text": "Прежде чем использовать эту функцию, сделайте резервную копию. Удаление невозможно отменить. Все названные устройства (неизвестные) будут удалены из базы данных.", "Maintenance_Tool_del_unknowndev_text": "Прежде чем использовать эту функцию, сделайте резервную копию. Удаление невозможно отменить. Все названные устройства (неизвестные) будут удалены из базы данных.",
"Maintenance_Tool_displayed_columns_text": "Измените видимость и порядок столбцов на странице <a href=\"devices.php\"><b> <i class=\"fa fa-laptop\"></i> Устройства</b></a>.", "Maintenance_Tool_displayed_columns_text": "Измените видимость и порядок столбцов на странице <a href=\"devices.php\"><b> <i class=\"fa fa-laptop\"></i> Устройства</b></a>.",
"Maintenance_Tool_drag_me": "Перетащите элемент, чтобы изменить порядок столбцов.", "Maintenance_Tool_drag_me": "Перетащите элемент, чтобы изменить порядок столбцов.",
"Maintenance_Tool_order_columns_text": "", "Maintenance_Tool_order_columns_text": "Maintenance_Tool_order_columns_text",
"Maintenance_Tool_purgebackup": "Очистить резервные копии", "Maintenance_Tool_purgebackup": "Очистить резервные копии",
"Maintenance_Tool_purgebackup_noti": "Очистить резервные копии", "Maintenance_Tool_purgebackup_noti": "Очистить резервные копии",
"Maintenance_Tool_purgebackup_noti_text": "Вы уверены, что хотите удалить все резервные копии, кроме трех последних?", "Maintenance_Tool_purgebackup_noti_text": "Вы уверены, что хотите удалить все резервные копии, кроме трех последних?",
@@ -556,6 +560,7 @@
"RandomMAC_hover": "Автоматически обнаружено — указывает, рандомизирует ли устройство свой MAC-адрес.", "RandomMAC_hover": "Автоматически обнаружено — указывает, рандомизирует ли устройство свой MAC-адрес.",
"Reports_Sent_Log": "Отправить журнал логов", "Reports_Sent_Log": "Отправить журнал логов",
"SCAN_SUBNETS_description": "Большинство сетевых сканеров (ARP-SCAN, NMAP, NSLOOKUP, DIG, PHOLUS) полагаются на сканирование определенных сетевых интерфейсов и подсетей. Дополнительную информацию по этому параметру можно найти в <a href=\"https://github.com/jokob-sk/NetAlertX/blob/main/docs/SUBNETS.md\" target=\"_blank\">документации по подсетям</a>, особенно VLAN, какие VLAN поддерживаются или как разобраться в маске сети и своем интерфейсе. <br/> <br/> Альтернативой сетевым сканерам является включение некоторых других сканеров/импортеров устройств, которые не полагаются на NetAlert<sup>X</sup>, имеющий доступ к сети (UNIFI, dhcp.leases , PiHole и др.). <br/> <br/> Примечание. Само время сканирования зависит от количества проверяемых IP-адресов, поэтому тщательно настройте его, указав соответствующую маску сети и интерфейс.", "SCAN_SUBNETS_description": "Большинство сетевых сканеров (ARP-SCAN, NMAP, NSLOOKUP, DIG, PHOLUS) полагаются на сканирование определенных сетевых интерфейсов и подсетей. Дополнительную информацию по этому параметру можно найти в <a href=\"https://github.com/jokob-sk/NetAlertX/blob/main/docs/SUBNETS.md\" target=\"_blank\">документации по подсетям</a>, особенно VLAN, какие VLAN поддерживаются или как разобраться в маске сети и своем интерфейсе. <br/> <br/> Альтернативой сетевым сканерам является включение некоторых других сканеров/импортеров устройств, которые не полагаются на NetAlert<sup>X</sup>, имеющий доступ к сети (UNIFI, dhcp.leases , PiHole и др.). <br/> <br/> Примечание. Само время сканирования зависит от количества проверяемых IP-адресов, поэтому тщательно настройте его, указав соответствующую маску сети и интерфейс.",
"SCAN_SUBNETS_name": "",
"SYSTEM_TITLE": "Системная информация", "SYSTEM_TITLE": "Системная информация",
"Setting_Override": "Переопределить значение", "Setting_Override": "Переопределить значение",
"Setting_Override_Description": "Включение этой опции приведет к переопределению значения по умолчанию, предоставленного приложением, на значение, указанное выше.", "Setting_Override_Description": "Включение этой опции приведет к переопределению значения по умолчанию, предоставленного приложением, на значение, указанное выше.",
@@ -654,6 +659,8 @@
"UI_PRESENCE_name": "Показать в диаграмме присутствия", "UI_PRESENCE_name": "Показать в диаграмме присутствия",
"UI_REFRESH_description": "Введите количество секунд, по истечении которых пользовательский интерфейс перезагружается. Установите значение <code>0</code>, чтобы отключить.", "UI_REFRESH_description": "Введите количество секунд, по истечении которых пользовательский интерфейс перезагружается. Установите значение <code>0</code>, чтобы отключить.",
"UI_REFRESH_name": "Автоматическое обновление интерфейса", "UI_REFRESH_name": "Автоматическое обновление интерфейса",
"VERSION_description": "Вспомогательное значение версии или метки времени, позволяющее проверить, было ли приложение обновлено.",
"VERSION_name": "Версия или временная метка",
"devices_old": "Актуализируется...", "devices_old": "Актуализируется...",
"general_event_description": "Событие, которое вы инициировали, может занять некоторое время, прежде чем фоновые процессы завершатся. Выполнение завершится, как только очередь выполнения, указанная ниже, опустеет (Проверьте <a href='/maintenance.php#tab_Logging'>журнал ошибок</a> при возникновении проблем). <br/> <br/>· · Очередь выполнения:", "general_event_description": "Событие, которое вы инициировали, может занять некоторое время, прежде чем фоновые процессы завершатся. Выполнение завершится, как только очередь выполнения, указанная ниже, опустеет (Проверьте <a href='/maintenance.php#tab_Logging'>журнал ошибок</a> при возникновении проблем). <br/> <br/>· · Очередь выполнения:",
"general_event_title": "Выполнение специального события", "general_event_title": "Выполнение специального события",
@@ -690,4 +697,4 @@
"settings_update_item_warning": "Обновить значение ниже. Будьте осторожны, следуя предыдущему формату. <b>Проверка не выполняется.</b>", "settings_update_item_warning": "Обновить значение ниже. Будьте осторожны, следуя предыдущему формату. <b>Проверка не выполняется.</b>",
"test_event_icon": "fa-vial-circle-check", "test_event_icon": "fa-vial-circle-check",
"test_event_tooltip": "Сначала сохраните изменения, прежде чем проверять настройки." "test_event_tooltip": "Сначала сохраните изменения, прежде чем проверять настройки."
} }

View File

@@ -56,6 +56,8 @@
"BackDevices_Restore_okay": "", "BackDevices_Restore_okay": "",
"BackDevices_darkmode_disabled": "", "BackDevices_darkmode_disabled": "",
"BackDevices_darkmode_enabled": "", "BackDevices_darkmode_enabled": "",
"CLEAR_NEW_FLAG_description": "",
"CLEAR_NEW_FLAG_name": "",
"DAYS_TO_KEEP_EVENTS_description": "", "DAYS_TO_KEEP_EVENTS_description": "",
"DAYS_TO_KEEP_EVENTS_name": "", "DAYS_TO_KEEP_EVENTS_name": "",
"DevDetail_Copy_Device_Title": "", "DevDetail_Copy_Device_Title": "",
@@ -274,6 +276,7 @@
"Gen_AreYouSure": "Emin misiniz?", "Gen_AreYouSure": "Emin misiniz?",
"Gen_Backup": "", "Gen_Backup": "",
"Gen_Cancel": "İptal", "Gen_Cancel": "İptal",
"Gen_Change": "",
"Gen_Copy": "Çalıştır", "Gen_Copy": "Çalıştır",
"Gen_DataUpdatedUITakesTime": "TAMAM - Eğer bir tarama çalışıyorsa arayüzün güncellenmesi biraz zaman alabilir", "Gen_DataUpdatedUITakesTime": "TAMAM - Eğer bir tarama çalışıyorsa arayüzün güncellenmesi biraz zaman alabilir",
"Gen_Delete": "Sil", "Gen_Delete": "Sil",
@@ -292,6 +295,7 @@
"Gen_Save": "Kaydet", "Gen_Save": "Kaydet",
"Gen_Saved": "Kaydedildi", "Gen_Saved": "Kaydedildi",
"Gen_Search": "", "Gen_Search": "",
"Gen_SelectToPreview": "",
"Gen_Selected_Devices": "Seçilmiş Cihazlar:", "Gen_Selected_Devices": "Seçilmiş Cihazlar:",
"Gen_Switch": "", "Gen_Switch": "",
"Gen_Upd": "Başarılı bir şekilde güncellendi", "Gen_Upd": "Başarılı bir şekilde güncellendi",
@@ -556,6 +560,7 @@
"RandomMAC_hover": "", "RandomMAC_hover": "",
"Reports_Sent_Log": "", "Reports_Sent_Log": "",
"SCAN_SUBNETS_description": "", "SCAN_SUBNETS_description": "",
"SCAN_SUBNETS_name": "",
"SYSTEM_TITLE": "", "SYSTEM_TITLE": "",
"Setting_Override": "", "Setting_Override": "",
"Setting_Override_Description": "", "Setting_Override_Description": "",
@@ -654,6 +659,8 @@
"UI_PRESENCE_name": "", "UI_PRESENCE_name": "",
"UI_REFRESH_description": "", "UI_REFRESH_description": "",
"UI_REFRESH_name": "", "UI_REFRESH_name": "",
"VERSION_description": "",
"VERSION_name": "",
"devices_old": "Yenileniyor...", "devices_old": "Yenileniyor...",
"general_event_description": "", "general_event_description": "",
"general_event_title": "", "general_event_title": "",

View File

@@ -56,6 +56,8 @@
"BackDevices_Restore_okay": "已成功恢复。", "BackDevices_Restore_okay": "已成功恢复。",
"BackDevices_darkmode_disabled": "暗黑模式已禁用", "BackDevices_darkmode_disabled": "暗黑模式已禁用",
"BackDevices_darkmode_enabled": "已启用暗黑模式", "BackDevices_darkmode_enabled": "已启用暗黑模式",
"CLEAR_NEW_FLAG_description": "",
"CLEAR_NEW_FLAG_name": "",
"DAYS_TO_KEEP_EVENTS_description": "这是维护设置。它指定将保留的事件条目的天数。所有较旧的事件将被定期删除。也适用于插件事件历史记录。", "DAYS_TO_KEEP_EVENTS_description": "这是维护设置。它指定将保留的事件条目的天数。所有较旧的事件将被定期删除。也适用于插件事件历史记录。",
"DAYS_TO_KEEP_EVENTS_name": "删除早于", "DAYS_TO_KEEP_EVENTS_name": "删除早于",
"DevDetail_Copy_Device_Title": "<i class=\"fa fa-copy\"></i> 从设备复制详细信息", "DevDetail_Copy_Device_Title": "<i class=\"fa fa-copy\"></i> 从设备复制详细信息",
@@ -274,6 +276,7 @@
"Gen_AreYouSure": "你确定吗?", "Gen_AreYouSure": "你确定吗?",
"Gen_Backup": "运行备份", "Gen_Backup": "运行备份",
"Gen_Cancel": "取消", "Gen_Cancel": "取消",
"Gen_Change": "",
"Gen_Copy": "运行", "Gen_Copy": "运行",
"Gen_DataUpdatedUITakesTime": "好的 - 如果扫描正在运行UI 可能需要一段时间才能更新。", "Gen_DataUpdatedUITakesTime": "好的 - 如果扫描正在运行UI 可能需要一段时间才能更新。",
"Gen_Delete": "删除", "Gen_Delete": "删除",
@@ -292,6 +295,7 @@
"Gen_Save": "保存", "Gen_Save": "保存",
"Gen_Saved": "已保存", "Gen_Saved": "已保存",
"Gen_Search": "搜索", "Gen_Search": "搜索",
"Gen_SelectToPreview": "",
"Gen_Selected_Devices": "选定的设备:", "Gen_Selected_Devices": "选定的设备:",
"Gen_Switch": "交换", "Gen_Switch": "交换",
"Gen_Upd": "已成功更新", "Gen_Upd": "已成功更新",
@@ -556,6 +560,7 @@
"RandomMAC_hover": "自动检测 - 表示设备是否随机化其 MAC 地址。", "RandomMAC_hover": "自动检测 - 表示设备是否随机化其 MAC 地址。",
"Reports_Sent_Log": "已发送报告日志", "Reports_Sent_Log": "已发送报告日志",
"SCAN_SUBNETS_description": "大多数网络扫描器ARP-SCAN、NMAP、NSLOOKUP、DIG、PHOLUS依赖于扫描特定的网络接口和子网。查看<a href=\"https://github.com/jokob-sk/NetAlertX/blob/main/docs/SUBNETS.md\" target=\"_blank\">子网文档</a>以获取有关此设置的帮助,尤其是 VLAN、支持哪些 VLAN或者如何确定网络掩码和接口。<br/> <br/> 网络扫描器的替代方法是启用一些其他不依赖于 NetAlert<sup>X</sup> 访问网络的设备扫描器/导入器UNIFI、dhcp.leases、PiHole 等)。<br/> <br/> 注意:扫描时间本身取决于要检查的 IP 地址数量,因此请使用适当的网络掩码和接口仔细设置。", "SCAN_SUBNETS_description": "大多数网络扫描器ARP-SCAN、NMAP、NSLOOKUP、DIG、PHOLUS依赖于扫描特定的网络接口和子网。查看<a href=\"https://github.com/jokob-sk/NetAlertX/blob/main/docs/SUBNETS.md\" target=\"_blank\">子网文档</a>以获取有关此设置的帮助,尤其是 VLAN、支持哪些 VLAN或者如何确定网络掩码和接口。<br/> <br/> 网络扫描器的替代方法是启用一些其他不依赖于 NetAlert<sup>X</sup> 访问网络的设备扫描器/导入器UNIFI、dhcp.leases、PiHole 等)。<br/> <br/> 注意:扫描时间本身取决于要检查的 IP 地址数量,因此请使用适当的网络掩码和接口仔细设置。",
"SCAN_SUBNETS_name": "",
"SYSTEM_TITLE": "系统信息", "SYSTEM_TITLE": "系统信息",
"Setting_Override": "覆盖值", "Setting_Override": "覆盖值",
"Setting_Override_Description": "启用此选项将用上面指定的值覆盖应用程序提供的默认值。", "Setting_Override_Description": "启用此选项将用上面指定的值覆盖应用程序提供的默认值。",
@@ -654,6 +659,8 @@
"UI_PRESENCE_name": "在存在图表中显示", "UI_PRESENCE_name": "在存在图表中显示",
"UI_REFRESH_description": "输入界面重新加载的秒数。设置为 <code>0</code> 可禁用。", "UI_REFRESH_description": "输入界面重新加载的秒数。设置为 <code>0</code> 可禁用。",
"UI_REFRESH_name": "自动刷新界面", "UI_REFRESH_name": "自动刷新界面",
"VERSION_description": "",
"VERSION_name": "",
"devices_old": "刷新中...", "devices_old": "刷新中...",
"general_event_description": "您触发的事件可能需要一段时间才能完成后台进程。一旦以下执行队列清空,执行就会结束(如果遇到问题,请检查<a href='/maintenance.php#tab_Logging'>错误日志</a>)。<br/> <br/> 执行队列:", "general_event_description": "您触发的事件可能需要一段时间才能完成后台进程。一旦以下执行队列清空,执行就会结束(如果遇到问题,请检查<a href='/maintenance.php#tab_Logging'>错误日志</a>)。<br/> <br/> 执行队列:",
"general_event_title": "执行自组织网络事件", "general_event_title": "执行自组织网络事件",

View File

@@ -4,9 +4,9 @@
// ## GUI settings processing start // ## GUI settings processing start
// ################################### // ###################################
if( isset($_COOKIE['Front_Dark_Mode_Enabled'])) if( isset($_COOKIE['UI_dark_mode']))
{ {
$ENABLED_DARKMODE = $_COOKIE['Front_Dark_Mode_Enabled'] == "true"; $ENABLED_DARKMODE = $_COOKIE['UI_dark_mode'] == "True";
}else }else
{ {
$ENABLED_DARKMODE = False; $ENABLED_DARKMODE = False;

View File

@@ -11,12 +11,12 @@ NetAlertX supports additional plugins to extend its functionality, each with its
> You can load additional Plugins via the General -> `LOADED_PLUGINS` setting. Use `Ctrl + Click` to select/deselect. > You can load additional Plugins via the General -> `LOADED_PLUGINS` setting. Use `Ctrl + Click` to select/deselect.
1. Pick your `🔍 dev scanner` plugin (e.g. `ARPSCAN` or `NMAPDEV`), or import devices into the application with an `📥 importer` plugin. (See **✅Enabling plugins** below) 1. Pick your `🔍 dev scanner` plugin (e.g. `ARPSCAN` or `NMAPDEV`), or import devices into the application with an `📥 importer` plugin. (See **✅Enabling plugins** below)
1. Pick a `▶️ publisher` plugin, if you want to send notifications. If you don't see a publisher you'd like to use, look at the [📚_publisher_apprise](/front/plugins/_publisher_apprise/) plugin which is a proxy for over 80 notification services. 2. Pick a `▶️ publisher` plugin, if you want to send notifications. If you don't see a publisher you'd like to use, look at the [📚_publisher_apprise](/front/plugins/_publisher_apprise/) plugin which is a proxy for over 80 notification services.
1. Setup your [Network topology diagram](/docs/NETWORK_TREE.md) 3. Setup your [Network topology diagram](/docs/NETWORK_TREE.md)
1. Fine-tune [Notifications](/docs/NOTIFICATIONS.md) 4. Fine-tune [Notifications](/docs/NOTIFICATIONS.md)
1. [Backup your setup](/docs/BACKUPS.md) 5. [Backup your setup](/docs/BACKUPS.md)
1. Contribute and [Create custom plugins](/docs/PLUGINS_DEV.md) 6. Contribute and [Create custom plugins](/docs/PLUGINS_DEV.md)
1. Consider [donating](https://github.com/jokob-sk/NetAlertX?tab=readme-ov-file#-sponsors) to keep me going 7. Consider [donating](https://github.com/jokob-sk/NetAlertX?tab=readme-ov-file#-sponsors) to keep me going
## 📑 Available Plugins ## 📑 Available Plugins
@@ -53,6 +53,7 @@ Device-detecting plugins insert values into the `CurrentScan` database table. T
| `SMTP` | ▶️ | Email notifications | | | Script | [_publisher_email](/front/plugins/_publisher_email/) | | `SMTP` | ▶️ | Email notifications | | | Script | [_publisher_email](/front/plugins/_publisher_email/) |
| `SNMPDSC` | 🔍/📥 | SNMP device import & sync | | | Script | [snmp_discovery](/front/plugins/snmp_discovery/) | | `SNMPDSC` | 🔍/📥 | SNMP device import & sync | | | Script | [snmp_discovery](/front/plugins/snmp_discovery/) |
| `SYNC` | 🔍/⚙/📥| Sync & import from NetAlertX instances | 🖧 🔄 | | Script | [sync](/front/plugins/sync/) | | `SYNC` | 🔍/⚙/📥| Sync & import from NetAlertX instances | 🖧 🔄 | | Script | [sync](/front/plugins/sync/) |
| `TELEGRAM` | ▶️ | Telegram notifications | | | Script | [_publisher_telegram](/front/plugins/_publisher_telegram/) |
| `UNDIS` | 🔍/📥 | Create dummy devices | | | Script | [undiscoverables](/front/plugins/undiscoverables/) | | `UNDIS` | 🔍/📥 | Create dummy devices | | | Script | [undiscoverables](/front/plugins/undiscoverables/) |
| `UNFIMP` | 🔍/📥 | UniFi device import & sync | 🖧 | | Script | [unifi_import](/front/plugins/unifi_import/) | | `UNFIMP` | 🔍/📥 | UniFi device import & sync | 🖧 | | Script | [unifi_import](/front/plugins/unifi_import/) |
| `VNDRPDT` | ⚙ | Vendor database update | | | Script | [vendor_update](/front/plugins/vendor_update/) | | `VNDRPDT` | ⚙ | Vendor database update | | | Script | [vendor_update](/front/plugins/vendor_update/) |

View File

@@ -767,8 +767,8 @@
{ "elementType": "select", "elementOptions": [], "transformers": [] } { "elementType": "select", "elementOptions": [], "transformers": [] }
] ]
}, },
"default_value": 1, "default_value": 5,
"options": [1, 2], "options": [3, 5],
"localized": ["name", "description"], "localized": ["name", "description"],
"name": [ "name": [
{ {
@@ -779,7 +779,7 @@
"description": [ "description": [
{ {
"language_code": "en_us", "language_code": "en_us",
"string": "Paho MQTT API version. Depends on the MQTT <a href=\"https://eclipse.dev/paho/files/paho.mqtt.python/html/index.html#callbacks\" target=\"_blank\">version supported by the MQTT broker</a>. Usually set to <code>1</code>." "string": "MQTT Protocol version. Depends on the MQTT broker</a>. Usually set to <code>5</code>, or <code>3</code> for backwards compatibility."
} }
] ]
}, },

View File

@@ -271,20 +271,23 @@ def create_sensor(mqtt_client, deviceId, deviceName, sensorType, sensorName, ico
return sensorConfig return sensorConfig
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
def mqtt_create_client(): def mqtt_create_client():
mytransport = 'tcp' # or 'websockets'
def on_disconnect(mqtt_client, userdata, reason_code): def on_disconnect(mqtt_client, userdata, reason_code):
global mqtt_connected_to_broker global mqtt_connected_to_broker
# REF: If we wanted a auto reconnect, a good source is here: https://www.emqx.com/en/blog/how-to-use-mqtt-in-python
mqtt_connected_to_broker = False mqtt_connected_to_broker = False
mylog('debug', [f"[{pluginName}] Connection terminated, reason_code: {reason_code}"])
# not sure is below line is correct / necessary
# client = mqtt_create_client()
def on_connect(mqtt_client, userdata, flags, reason_code): def on_connect(mqtt_client, userdata, flags, reason_code, properties):
global mqtt_connected_to_broker global mqtt_connected_to_broker
# REF: Good docu on reason codes: https://www.emqx.com/en/blog/mqtt5-new-features-reason-code-and-ack
if reason_code == 0: if reason_code == 0:
mylog('verbose', [f"[{pluginName}] Connected to broker"]) mylog('verbose', [f"[{pluginName}] Connected to broker"])
mqtt_connected_to_broker = True # Signal connection mqtt_connected_to_broker = True # Signal connection
@@ -292,21 +295,29 @@ def mqtt_create_client():
mylog('verbose', [f"[{pluginName}] Connection failed, reason_code: {reason_code}"]) mylog('verbose', [f"[{pluginName}] Connection failed, reason_code: {reason_code}"])
mqtt_connected_to_broker = False mqtt_connected_to_broker = False
global mqtt_client global mqtt_client
if get_setting_value('MQTT_VERSION') == 1: # Paho will be soon not supporting V1 anymore, so this really should not be a user choice to start with
mqtt_client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION1) # This code now uses V2 by default
# Ref: https://eclipse.dev/paho/files/paho.mqtt.python/html/migrations.html
if get_setting_value('MQTT_VERSION') == 3:
version = mqtt.MQTTv311
else: else:
mqtt_client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2) version = mqtt.MQTTv5
mqtt_client = mqtt.Client(
callback_api_version = mqtt.CallbackAPIVersion.VERSION2,
transport=mytransport,
protocol=mqtt.MQTTv5)
mqtt_client.on_connect = on_connect
mqtt_client.on_disconnect = on_disconnect
if get_setting_value('MQTT_TLS'): if get_setting_value('MQTT_TLS'):
mqtt_client.tls_set() mqtt_client.tls_set()
mqtt_client.username_pw_set(get_setting_value('MQTT_USER'), get_setting_value('MQTT_PASSWORD')) mqtt_client.username_pw_set(username = get_setting_value('MQTT_USER'), password = get_setting_value('MQTT_PASSWORD'))
mqtt_client.on_connect = on_connect mqtt_client.connect(host = get_setting_value('MQTT_BROKER'), port = get_setting_value('MQTT_PORT'))
mqtt_client.on_disconnect = on_disconnect
mqtt_client.connect(get_setting_value('MQTT_BROKER'), get_setting_value('MQTT_PORT'))
mqtt_client.loop_start() mqtt_client.loop_start()
return mqtt_client return mqtt_client

View File

@@ -0,0 +1,10 @@
## Overview
You can send notifications via Telegram
## Notes
You need Telegram bot to send notifications
### Usage
- Go to settings and fill in relevant details.

View File

@@ -0,0 +1,470 @@
{
"code_name": "_publisher_telegram",
"unique_prefix": "TELEGRAM",
"plugin_type": "publisher",
"enabled": true,
"data_source": "script",
"show_ui": true,
"localized": ["display_name", "description", "icon"],
"display_name": [
{
"language_code": "en_us",
"string": "Telegram publisher"
}
],
"icon": [
{
"language_code": "en_us",
"string": "<i class=\"fa-solid fa-bullhorn\"></i>"
}
],
"description": [
{
"language_code": "en_us",
"string": "A plugin to publish a notification via Telegram."
}
],
"params": [],
"database_column_definitions": [
{
"column": "Index",
"css_classes": "col-sm-2",
"show": false,
"type": "label",
"default_value": "",
"options": [],
"localized": ["name"],
"name": [
{
"language_code": "en_us",
"string": "N/A"
},
{
"language_code": "es_es",
"string": "N/A"
}
]
},
{
"column": "Plugin",
"css_classes": "col-sm-2",
"show": false,
"type": "label",
"default_value": "",
"options": [],
"localized": ["name"],
"name": [
{
"language_code": "en_us",
"string": "N/A"
},
{
"language_code": "es_es",
"string": "N/A"
}
]
},
{
"column": "Object_PrimaryID",
"css_classes": "col-sm-2",
"show": false,
"type": "url",
"default_value": "",
"options": [],
"localized": ["name"],
"name": [
{
"language_code": "en_us",
"string": "N/A"
}
]
},
{
"column": "Object_SecondaryID",
"css_classes": "col-sm-2",
"show": false,
"type": "label",
"default_value": "",
"options": [],
"localized": ["name"],
"name": [
{
"language_code": "en_us",
"string": "N/A"
},
{
"language_code": "es_es",
"string": "N/A"
}
]
},
{
"column": "DateTimeCreated",
"css_classes": "col-sm-2",
"show": true,
"type": "label",
"default_value": "",
"options": [],
"localized": ["name"],
"name": [
{
"language_code": "en_us",
"string": "Sent when"
}
]
},
{
"column": "DateTimeChanged",
"css_classes": "col-sm-2",
"show": false,
"type": "label",
"default_value": "",
"options": [],
"localized": ["name"],
"name": [
{
"language_code": "en_us",
"string": "Changed"
},
{
"language_code": "es_es",
"string": "Cambiado"
}
]
},
{
"column": "Watched_Value1",
"css_classes": "col-sm-2",
"show": true,
"type": "eval",
"default_value": "",
"options": [
{
"type": "eval",
"param": "`<a href='/report.php?guid=${value}'>${value}</a>`"
}
],
"localized": ["name"],
"name": [
{
"language_code": "en_us",
"string": "Notification GUID"
}
]
},
{
"column": "Watched_Value2",
"css_classes": "col-sm-8",
"show": true,
"type": "textarea_readonly",
"default_value": "",
"options": [],
"localized": ["name"],
"name": [
{
"language_code": "en_us",
"string": "Result"
}
]
},
{
"column": "Watched_Value3",
"css_classes": "col-sm-2",
"show": false,
"type": "label",
"default_value": "",
"options": [],
"localized": ["name"],
"name": [
{
"language_code": "en_us",
"string": "N/A"
},
{
"language_code": "es_es",
"string": "N/A"
}
]
},
{
"column": "Watched_Value4",
"css_classes": "col-sm-2",
"show": false,
"type": "label",
"default_value": "",
"options": [],
"localized": ["name"],
"name": [
{
"language_code": "en_us",
"string": "N/A"
},
{
"language_code": "es_es",
"string": "N/A"
}
]
},
{
"column": "UserData",
"css_classes": "col-sm-2",
"show": false,
"type": "textbox_save",
"default_value": "",
"options": [],
"localized": ["name"],
"name": [
{
"language_code": "en_us",
"string": "Comments"
},
{
"language_code": "es_es",
"string": "Comentarios"
}
]
},
{
"column": "Status",
"css_classes": "col-sm-1",
"show": false,
"type": "replace",
"default_value": "",
"options": [
{
"equals": "watched-not-changed",
"replacement": "<div style='text-align:center'><i class='fa-solid fa-square-check'></i><div></div>"
},
{
"equals": "watched-changed",
"replacement": "<div style='text-align:center'><i class='fa-solid fa-triangle-exclamation'></i></div>"
},
{
"equals": "new",
"replacement": "<div style='text-align:center'><i class='fa-solid fa-circle-plus'></i></div>"
},
{
"equals": "missing-in-last-scan",
"replacement": "<div style='text-align:center'><i class='fa-solid fa-question'></i></div>"
}
],
"localized": ["name"],
"name": [
{
"language_code": "en_us",
"string": "Status"
},
{
"language_code": "es_es",
"string": "Estado"
}
]
},
{
"column": "Extra",
"css_classes": "col-sm-3",
"show": false,
"type": "label",
"default_value": "",
"options": [],
"localized": ["name"],
"name": [
{
"language_code": "en_us",
"string": "Extra"
},
{
"language_code": "es_es",
"string": "Extra"
}
]
}
],
"settings": [
{
"function": "RUN",
"events": ["test"],
"type": {
"dataType": "string",
"elements": [
{ "elementType": "select", "elementOptions": [], "transformers": [] }
]
},
"default_value": "disabled",
"options": ["disabled", "on_notification"],
"localized": ["name", "description"],
"name": [
{
"language_code": "en_us",
"string": "When to run"
},
{
"language_code": "es_es",
"string": "Cuando ejecuta"
}
],
"description": [
{
"language_code": "en_us",
"string": "Enable sending notifications via a Telegram messanger"
}
]
},
{
"function": "CMD",
"type": {
"dataType": "string",
"elements": [
{
"elementType": "input",
"elementOptions": [{ "readonly": "true" }],
"transformers": []
}
]
},
"default_value": "python3 /app/front/plugins/_publisher_telegram/tg.py",
"options": [],
"localized": ["name", "description"],
"name": [
{
"language_code": "en_us",
"string": "Command"
},
{
"language_code": "es_es",
"string": "Comando"
}
],
"description": [
{
"language_code": "en_us",
"string": "Command to run"
},
{
"language_code": "es_es",
"string": "Comando a ejecutar"
}
]
},
{
"function": "RUN_TIMEOUT",
"type": {
"dataType": "integer",
"elements": [
{
"elementType": "input",
"elementOptions": [{ "type": "number" }],
"transformers": []
}
]
},
"default_value": 10,
"options": [],
"localized": ["name", "description"],
"name": [
{
"language_code": "en_us",
"string": "Run timeout"
},
{
"language_code": "es_es",
"string": "Tiempo de espera de ejecución"
},
{
"language_code": "de_de",
"string": "Wartezeit"
}
],
"description": [
{
"language_code": "en_us",
"string": "Maximum time in seconds to wait for the script to finish. If this time is exceeded the script is aborted."
},
{
"language_code": "es_es",
"string": "Tiempo máximo en segundos para esperar a que finalice el script. Si se supera este tiempo, el script se cancela."
}
]
},
{
"function": "HOST",
"type": {
"dataType": "string",
"elements": [
{ "elementType": "input", "elementOptions": [], "transformers": [] }
]
},
"default_value": "",
"options": [],
"localized": ["name", "description"],
"name": [
{
"language_code": "en_us",
"string": "Telegram chat id"
}
],
"description": [
{
"language_code": "en_us",
"string": "Telegram chat id. If you want to send messages to user, paste user id (Example: <code>1234123412</code>)"
}
]
},
{
"function": "URL",
"type": {
"dataType": "string",
"elements": [
{ "elementType": "input", "elementOptions": [], "transformers": [] }
]
},
"default_value": "",
"options": [],
"localized": ["name", "description"],
"name": [
{
"language_code": "en_us",
"string": "Telegram bot token"
}
],
"description": [
{
"language_code": "en_us",
"string": "Telegram bot token. You cat get at from <a target=\"_blank\" href=\"https://t.me/BotFather\">BotFather</a>"
}
]
},
{
"function": "SIZE",
"type": {
"dataType": "integer",
"elements": [
{
"elementType": "input",
"elementOptions": [{ "type": "number" }],
"transformers": []
}
]
},
"default_value": 1024,
"options": [],
"localized": ["name", "description"],
"name": [
{
"language_code": "en_us",
"string": "Max payload size"
},
{
"language_code": "es_es",
"string": "Tamaño máximo de carga útil"
}
],
"description": [
{
"language_code": "en_us",
"string": "The maximum size of the payload as number of characters in the passed string. If above limit, it will be truncated and a <code>(text was truncated)</code> message is appended."
}
]
}
]
}

View File

@@ -0,0 +1,124 @@
#!/usr/bin/env python
import json
import subprocess
import argparse
import os
import pathlib
import sys
from datetime import datetime
# Register NetAlertX directories
INSTALL_PATH = "/app"
sys.path.extend([f"{INSTALL_PATH}/front/plugins", f"{INSTALL_PATH}/server"])
import conf
from const import confFileName
from plugin_helper import Plugin_Objects
from logger import mylog, append_line_to_file
from helper import timeNowTZ, get_setting_value
from notification import Notification_obj
from database import DB
from pytz import timezone
# Make sure the TIMEZONE for logging is correct
conf.tz = timezone(get_setting_value('TIMEZONE'))
CUR_PATH = str(pathlib.Path(__file__).parent.resolve())
RESULT_FILE = os.path.join(CUR_PATH, 'last_result.log')
pluginName = 'TELEGRAM'
def main():
mylog('verbose', [f'[{pluginName}](publisher) In script'])
# Check if basic config settings supplied
if check_config() == False:
mylog('none', [
f'[{pluginName}] ⚠ ERROR: Publisher notification gateway not set up correctly. Check your {confFileName} {pluginName}_* variables.'])
return
# Create a database connection
db = DB() # instance of class DB
db.open()
# Initialize the Plugin obj output file
plugin_objects = Plugin_Objects(RESULT_FILE)
# Create a Notification_obj instance
notifications = Notification_obj(db)
# Retrieve new notifications
new_notifications = notifications.getNew()
# Process the new notifications (see the Notifications DB table for structure or check the /api/table_notifications.json endpoint)
for notification in new_notifications:
# Send notification
result = send(notification["Text"])
# Log result
plugin_objects.add_object(
primaryId=pluginName,
secondaryId=timeNowTZ(),
watched1=notification["GUID"],
watched2=result,
watched3='null',
watched4='null',
extra='null',
foreignKey=notification["GUID"]
)
plugin_objects.write_result_file()
# -------------------------------------------------------------------------------
def check_config():
return True
# -------------------------------------------------------------------------------
def send(text):
# limit = 1024 * 1024 # 1MB limit (1024 bytes * 1024 bytes = 1MB)
limit = get_setting_value('TELEGRAM_SIZE')
if len(text) > limit:
payloadData = text[:limit] + " (text was truncated)"
else:
payloadData = text
try:
# try runnning a subprocess
req = """curl --location 'https://api.telegram.org/bot%s/sendMessage' \\
--header 'Content-Type: application/json' \\
--data '{
"chat_id": "%s",
"text": "%s",
"disable_notification": false
}'""" % (get_setting_value('TELEGRAM_URL'), get_setting_value('TELEGRAM_HOST'), payloadData)
mylog('debug', [req])
p = subprocess.Popen(req, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True)
stdout, stderr = p.communicate()
# write stdout and stderr into .log files for debugging if needed
# Log the stdout and stderr
mylog('debug', [stdout, stderr])
# log result
result = stdout
except subprocess.CalledProcessError as e:
# An error occurred, handle it
mylog('none', [e.output])
# log result
result = e.output
return result
if __name__ == '__main__':
sys.exit(main())

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

View File

@@ -6,3 +6,7 @@ A plugin to publish a notification via the Webhook gateway. Webhooks help you to
- Go to settings and fill in relevant details. - Go to settings and fill in relevant details.
#### Sample Discord Setup
![image](Discord_Config.png)

View File

@@ -44,12 +44,13 @@ def main():
HRS_TO_KEEP_NEWDEV = int(values.hourstokeepnewdevice.split('=')[1]) HRS_TO_KEEP_NEWDEV = int(values.hourstokeepnewdevice.split('=')[1])
DAYS_TO_KEEP_EVENTS = int(values.daystokeepevents.split('=')[1]) DAYS_TO_KEEP_EVENTS = int(values.daystokeepevents.split('=')[1])
PHOLUS_DAYS_DATA = get_setting_value("PHOLUS_DAYS_DATA") PHOLUS_DAYS_DATA = get_setting_value("PHOLUS_DAYS_DATA")
CLEAR_NEW_FLAG = get_setting_value("CLEAR_NEW_FLAG")
mylog('verbose', [f'[{pluginName}] In script']) mylog('verbose', [f'[{pluginName}] In script'])
# Execute cleanup/upkeep # Execute cleanup/upkeep
cleanup_database(fullDbPath, DAYS_TO_KEEP_EVENTS, PHOLUS_DAYS_DATA, HRS_TO_KEEP_NEWDEV, PLUGINS_KEEP_HIST) cleanup_database(fullDbPath, DAYS_TO_KEEP_EVENTS, PHOLUS_DAYS_DATA, HRS_TO_KEEP_NEWDEV, PLUGINS_KEEP_HIST, CLEAR_NEW_FLAG)
mylog('verbose', [f'[{pluginName}] Cleanup complete']) mylog('verbose', [f'[{pluginName}] Cleanup complete'])
@@ -58,7 +59,7 @@ def main():
#=============================================================================== #===============================================================================
# Cleanup / upkeep database # Cleanup / upkeep database
#=============================================================================== #===============================================================================
def cleanup_database (dbPath, DAYS_TO_KEEP_EVENTS, PHOLUS_DAYS_DATA, HRS_TO_KEEP_NEWDEV, PLUGINS_KEEP_HIST): def cleanup_database (dbPath, DAYS_TO_KEEP_EVENTS, PHOLUS_DAYS_DATA, HRS_TO_KEEP_NEWDEV, PLUGINS_KEEP_HIST, CLEAR_NEW_FLAG):
""" """
Cleaning out old records from the tables that don't need to keep all data. Cleaning out old records from the tables that don't need to keep all data.
""" """
@@ -147,8 +148,20 @@ def cleanup_database (dbPath, DAYS_TO_KEEP_EVENTS, PHOLUS_DAYS_DATA, HRS_TO_KEEP
# Cleanup New Devices # Cleanup New Devices
if HRS_TO_KEEP_NEWDEV != 0: if HRS_TO_KEEP_NEWDEV != 0:
mylog('verbose', [f'[{pluginName}] Devices: Delete all New Devices older than {str(HRS_TO_KEEP_NEWDEV)} hours (HRS_TO_KEEP_NEWDEV setting)']) mylog('verbose', [f'[{pluginName}] Devices: Delete all New Devices older than {str(HRS_TO_KEEP_NEWDEV)} hours (HRS_TO_KEEP_NEWDEV setting)'])
cursor.execute (f"""DELETE FROM Devices query = f"""DELETE FROM Devices WHERE dev_NewDevice = 1 AND dev_FirstConnection < date('now', '-{str(HRS_TO_KEEP_NEWDEV)} hour')"""
WHERE dev_NewDevice = 1 AND dev_FirstConnection < date('now', '+{str(HRS_TO_KEEP_NEWDEV)} hour')""") mylog('verbose', [f'[{pluginName}] Query: {query} '])
cursor.execute (query)
# -----------------------------------------------------
# Clear New Flag
if CLEAR_NEW_FLAG != 0:
mylog('verbose', [f'[{pluginName}] Devices: Clear "New Device" flag for all devices older than {str(CLEAR_NEW_FLAG)} hours (CLEAR_NEW_FLAG setting)'])
query = f"""UPDATE Devices SET dev_NewDevice = 0 WHERE dev_NewDevice = 1 AND date(dev_FirstConnection, '+{str(CLEAR_NEW_FLAG)} hour') < date('now')"""
# select * from Devices where dev_NewDevice = 1 AND date(dev_FirstConnection, '+3 hour' ) < date('now')
mylog('verbose', [f'[{pluginName}] Query: {query} '])
cursor.execute(query)
# ----------------------------------------------------- # -----------------------------------------------------
# Cleanup Pholus_Scan # Cleanup Pholus_Scan

View File

@@ -1,7 +1,7 @@
{ {
"code_name": "mikrotik_scan", "code_name": "mikrotik_scan",
"unique_prefix": "MTSCAN", "unique_prefix": "MTSCAN",
"plugin_type": "other", "plugin_type": "device_scanner",
"execution_order" : "Layer_4", "execution_order" : "Layer_4",
"enabled": true, "enabled": true,
"data_source": "script", "data_source": "script",
@@ -11,7 +11,7 @@
"display_name": [ "display_name": [
{ {
"language_code": "en_us", "language_code": "en_us",
"string": "Mikrotik (Name discovery)" "string": "Mikrotik (Device discovery)"
} }
], ],
"icon": [ "icon": [
@@ -23,7 +23,7 @@
"description": [ "description": [
{ {
"language_code": "en_us", "language_code": "en_us",
"string": "A plugin to discover device names." "string": "A plugin to discover devices via Mikrotik."
} }
], ],
"params": [ "params": [

View File

@@ -1,6 +1,4 @@
#!/usr/bin/env python #!/usr/bin/env python
# test script by running:
# tbc
import os import os
import pathlib import pathlib
@@ -40,42 +38,35 @@ pluginName = 'MTSCAN'
def main(): def main():
mylog('verbose', [f'[{pluginName}] In script']) mylog('verbose', [f'[{pluginName}] In script'])
mt_host = get_setting_value('MTSCAN_MT_HOST') # init global variables
mt_port = get_setting_value('MTSCAN_MT_PORT') global MT_HOST, MT_PORT, MT_USER, MT_PASS
mt_user = get_setting_value('MTSCAN_MT_USER')
mt_password = get_setting_value('MTSCAN_MT_PASS')
#mylog('verbose', [f'[{pluginName}] Router: {mt_host}:{mt_port} user: {mt_user}, pass: {mt_password}'])
# Create a database connection
db = DB() # instance of class DB
db.open()
# Initialize the Plugin obj output file # Initialize the Plugin obj output file
plugin_objects = Plugin_Objects(RESULT_FILE) plugin_objects = Plugin_Objects(RESULT_FILE)
# Create a Device_obj instance # Mikrotik settings
device_handler = Device_obj(db) MT_HOST = get_setting_value('MTSCAN_MT_HOST')
MT_PORT = get_setting_value('MTSCAN_MT_PORT')
MT_USER = get_setting_value('MTSCAN_MT_USER')
MT_PASS = get_setting_value('MTSCAN_MT_PASS')
# Retrieve devices plugin_objects = get_entries(plugin_objects)
#unknown_devices = device_handler.getUnknown()
#mylog('verbose', [f'[{pluginName}] Unknown devices count: {len(unknown_devices)}'])
all_devices = device_handler.getAll() plugin_objects.write_result_file()
mylog('verbose', [f'[{pluginName}] Scan finished, found {len(plugin_objects)} devices'])
mylog('verbose', [f'[{pluginName}] all devices count: {len(all_devices)}'])
device_map = {d['dev_MAC']:d['dev_LastIP'] for d in all_devices} def get_entries(plugin_objects: Plugin_Objects) -> Plugin_Objects:
try: try:
# connect router # connect router
api = connect(username=mt_user, password=mt_password, host=mt_host, port=mt_port) api = connect(username=MT_USER, password=MT_PASS, host=MT_HOST, port=MT_PORT)
# get dhcp leases # get dhcp leases
leases = api('/ip/dhcp-server/lease/print') leases = api('/ip/dhcp-server/lease/print')
for lease in leases: for lease in leases:
lease_id = lease.get('.id') lease_id = lease.get('.id')
@@ -84,56 +75,31 @@ def main():
host_name = lease.get('host-name') host_name = lease.get('host-name')
comment = lease.get('comment') comment = lease.get('comment')
last_seen = lease.get('last-seen') last_seen = lease.get('last-seen')
status = lease.get('status')
mylog('verbose', [f"ID: {lease_id}, Address: {address}, MAC Address: {mac_address}, Host Name: {host_name}, Comment: {comment}, Last Seen: {last_seen}"]) mylog('verbose', [f"ID: {lease_id}, Address: {address}, MAC Address: {mac_address}, Host Name: {host_name}, Comment: {comment}, Last Seen: {last_seen}, Status: {status}"])
if mac_address in device_map.keys():
device_name = host_name if (status == "bound"):
if comment != '':
device_name = comment
plugin_objects.add_object( plugin_objects.add_object(
# "Name-MAC", "LastIP", "IP", "Name","Host","LastSeen","Comment"
primaryId = mac_address, primaryId = mac_address,
secondaryId = device_map[mac_address], secondaryId = '',
watched1 = address, watched1 = address,
watched2 = device_name, watched2 = host_name,
watched3 = host_name, watched3 = last_seen,
watched4 = last_seen, watched4 = '',
extra = '', extra = '',
helpVal1 = comment, helpVal1 = comment,
foreignKey = mac_address) foreignKey = mac_address)
plugin_objects.write_result_file()
except TrapError as e: except TrapError as e:
mylog('error', [f"An error occurred: {e}"]) mylog('error', [f"An error occurred: {e}"])
except Exception as e: except Exception as e:
mylog('error', [f"Failed to connect to MikroTik API: {e}"]) mylog('error', [f"Failed to connect to MikroTik API: {e}"])
#for device in unknown_devices:
# domain_name, dns_server = execute_nslookup(device['dev_LastIP'], timeout)
# if domain_name != '':
# plugin_objects.add_object(
# # "MAC", "IP", "Server", "Name"
# primaryId = device['dev_MAC'],
# secondaryId = device['dev_LastIP'],
# watched1 = dns_server,
# watched2 = domain_name,
# watched3 = '',
# watched4 = '',
# extra = '',
# foreignKey = device['dev_MAC'])
#plugin_objects.write_result_file()
mylog('verbose', [f'[{pluginName}] Script finished']) mylog('verbose', [f'[{pluginName}] Script finished'])
return 0 return plugin_objects
#=============================================================================== #===============================================================================
# BEGIN # BEGIN

View File

@@ -198,7 +198,7 @@
"elementOptions": [ "elementOptions": [
{ "sourceSuffixes": ["_in"] }, { "sourceSuffixes": ["_in"] },
{ "separator": "" }, { "separator": "" },
{ "cssClasses": "col-sm-2" }, { "cssClasses": "col-xs-12" },
{ "onClick": "addList(this, false)" }, { "onClick": "addList(this, false)" },
{ "getStringKey": "Gen_Add" } { "getStringKey": "Gen_Add" }
], ],
@@ -219,7 +219,7 @@
"elementOptions": [ "elementOptions": [
{ "sourceSuffixes": [] }, { "sourceSuffixes": [] },
{ "separator": "" }, { "separator": "" },
{ "cssClasses": "col-sm-3" }, { "cssClasses": "col-xs-6" },
{ "onClick": "removeFromList(this)" }, { "onClick": "removeFromList(this)" },
{ "getStringKey": "Gen_Remove_Last" } { "getStringKey": "Gen_Remove_Last" }
], ],
@@ -230,7 +230,7 @@
"elementOptions": [ "elementOptions": [
{ "sourceSuffixes": [] }, { "sourceSuffixes": [] },
{ "separator": "" }, { "separator": "" },
{ "cssClasses": "col-sm-3" }, { "cssClasses": "col-xs-6" },
{ "onClick": "removeAllOptions(this)" }, { "onClick": "removeAllOptions(this)" },
{ "getStringKey": "Gen_Remove_All" } { "getStringKey": "Gen_Remove_All" }
], ],
@@ -261,7 +261,7 @@
"description": [ "description": [
{ {
"language_code": "en_us", "language_code": "en_us",
"string": "All the newly discovered device names are clened up by applying the following REGEX expression in this order. All the below are replaced by a blank string." "string": "All the newly discovered device names are cleaned up by applying the following REGEX expression in this order. All the below are replaced by a blank string."
} }
] ]
}, },
@@ -977,7 +977,27 @@
"type": { "type": {
"dataType": "string", "dataType": "string",
"elements": [ "elements": [
{ "elementType": "select", "elementOptions": [], "transformers": [] } {
"elementType": "span",
"elementOptions": [
{ "cssClasses": "input-group-addon iconPreview" },
{ "getStringKey": "Gen_SelectToPreview" },
{ "customId": "NEWDEV_dev_Icon_preview" }
],
"transformers": []
},
{
"elementType": "select",
"elementHasInputValue": 1,
"elementOptions": [
{ "cssClasses": "col-xs-12" },
{
"onChange": "updateIconPreview(this)"
},
{ "customParams": "NEWDEV_dev_Icon,NEWDEV_dev_Icon_preview" }
],
"transformers": []
}
] ]
}, },
"default_value": "", "default_value": "",

View File

@@ -3,7 +3,7 @@
NMAP-scan is a command-line tool to discover and fingerprint IP hosts on the local network. The NMAP-scan (and other Network-scan plugin times using the `SCAN_SUBNETS` setting) time depends on the number of IP addresses to check so set this up carefully with the appropriate network mask and interface. Check the [subnets documentation](https://github.com/jokob-sk/NetAlertX/blob/main/docs/SUBNETS.md) for help with setting up VLANs, what VLANs are supported, or how to figure out the network mask and your interface. NMAP-scan is a command-line tool to discover and fingerprint IP hosts on the local network. The NMAP-scan (and other Network-scan plugin times using the `SCAN_SUBNETS` setting) time depends on the number of IP addresses to check so set this up carefully with the appropriate network mask and interface. Check the [subnets documentation](https://github.com/jokob-sk/NetAlertX/blob/main/docs/SUBNETS.md) for help with setting up VLANs, what VLANs are supported, or how to figure out the network mask and your interface.
> [!NOTE] > [!NOTE]
> The `NMAPDEV` plugin is great for detecting the availability of devices, however ARP scan might be better covering multiple VLANS. You can always combine different scan methods. You can find all available network scanning options (marked as `🔍 dev scanner`) in the [Plugins overview](https://github.com/jokob-sk/NetAlertX/blob/main/front/plugins/README.md) readme. > The `NMAPDEV` plugin is great for detecting the availability of devices, however ARP scan might be better covering multiple VLANS and subnets as NMAP can't pickup the MAC address from other subnets (this is an NMAP limitation) which are necessary to identify a device. You can always combine different scan methods. You can find all available network scanning options (marked as `🔍 dev scanner`) in the [Plugins overview](https://github.com/jokob-sk/NetAlertX/blob/main/front/plugins/README.md) readme.
### Usage ### Usage

View File

@@ -1057,7 +1057,7 @@ def main():
elif values.rdns_scanning: elif values.rdns_scanning:
file_print_pr("[DEBUG] Timestamp 45: ", timeNow()) file_print_pr("[DEBUG] Timestamp 45: ", timeNow())
dns_query=None dns_query=None
ipn = ipaddress.ip_network(values.rdns_scanning) ipn = ipaddress.ip_network(values.rdns_scanning, strict=False)
for ip in ipn.hosts(): for ip in ipn.hosts():
the_query = ip.reverse_pointer the_query = ip.reverse_pointer
if not dns_query: if not dns_query:

View File

@@ -1,41 +1,63 @@
## Overview ## Overview
Synchronization plugin to synchronize multiple app instances. The Plugin can sychronize 2 types of data: The synchronization plugin is designed to synchronize data across multiple instances of the app. It supports the following data synchronization modes:
1. 💻 Devices: The plugin sends an encrypted `table_devices.json` file to synchronize the whole Devices DB table. 1. **💻 Devices**: Sends an encrypted `table_devices.json` file to synchronize the entire Devices database table.
1. 🔌 Plugin data: The plugin sends encrypted `last_result.log` files for individual plugins. 2. **🔌 Plugin Data**: Sends encrypted `last_result.log` files for individual plugins.
> [!TIP] > **Note:** `[n]` indicates a setting specified for the node instance, and `[n,h]` indicates a setting used on both the node and the hub instances.
> `[n]` indicates a setting that is usually specified for the node instance. `[n,h]` indicates a setting used both, on the node and on the hub instance.
### Synchronizing 💻 Devices data or 🔌 Plugins data ### Synchronization Modes
Most of the setups will probably only use 💻 Devices synchronization. 🔌 Plugins data will be probably used in only special use cases. The plugin operates in three different modes based on the configuration settings:
#### [n] Node (Source) Settings 1. **Mode 1: PUSH (NODE)** - Sends data from the node to the hub.
- This mode is activated if `SYNC_hub_url` is set and either `SYNC_devices` or `SYNC_plugins` is enabled.
- **Actions**:
- Sends `table_devices.json` to the hub if `SYNC_devices` is enabled.
- Sends individual plugin `last_result.log` files to the hub if `SYNC_plugins` is enabled.
- When to run [n,h] `SYNC_RUN` 2. **Mode 2: PULL (HUB)** - Retrieves data from nodes to the hub.
- Schedule [n,h] `SYNC_RUN_SCHD` - This mode is activated if `SYNC_nodes` is set.
- API token [n,h] `SYNC_api_token` - **Actions**:
- Encryption Key [n,h] `SYNC_encryption_key` - Retrieves data from configured nodes using the API and saves it locally for further processing.
- Node name [n] `SYNC_node_name`
- Hub URL [n] `SYNC_hub_url`
- Sync Devices [n] `SYNC_devices` or Sync Plugins [n] `SYNC_plugins` (or both)
#### [h] Hub (Target) Settings 3. **Mode 3: RECEIVE (HUB)** - Processes received data on the hub.
- Activated when data is received in Mode 2 and is ready to be processed.
- **Actions**:
- Decodes received data files, processes them, and updates the Devices table accordingly.
- When to run [n,h] `SYNC_RUN` ### Settings
- Schedule [n,h] `SYNC_RUN_SCHD`
- API token [n,h] `SYNC_api_token`
- Encryption Key [n,h] `SYNC_encryption_key`
#### Node (Source) Settings `[n]`
- **When to Run** `[n,h]`: `SYNC_RUN`
- **Schedule** `[n,h]`: `SYNC_RUN_SCHD`
- **API Token** `[n,h]`: `SYNC_api_token`
- **Encryption Key** `[n,h]`: `SYNC_encryption_key`
- **Node Name** `[n]`: `SYNC_node_name`
- **Hub URL** `[n]`: `SYNC_hub_url`
- **Sync Devices** `[n]`: `SYNC_devices`
- **Sync Plugins** `[n]`: `SYNC_plugins`
#### Hub (Target) Settings `[h]`
- **When to Run** `[n,h]`: `SYNC_RUN`
- **Schedule** `[n,h]`: `SYNC_RUN_SCHD`
- **API Token** `[n,h]`: `SYNC_api_token`
- **Encryption Key** `[n,h]`: `SYNC_encryption_key`
- **Nodes to Pull From** `[h]`: `SYNC_nodes`
### Usage ### Usage
- Head to **Settings** > **Sync Hub** to adjust the default values. 1. **Adjust Settings**:
- Navigate to **Settings** > **Sync Hub** to modify default settings.
2. **Data Flow**:
- Nodes send or receive data based on the specified modes, either pushing data to the hub or pulling from nodes.
### Notes ### Notes
- If a MAC address already exists on the hub, the device will be skipped in the data coming from this SYNC plugin. - Existing devices on the hub will not be updated by the data received from this SYNC plugin if their MAC addresses are already present.
- It is recommended to use Device synchronization primarily. Plugin data synchronization is more suitable for specific use cases.
![Syn Hub Setup Diagram](/front/plugins/sync/sync_hub.png) ![Sync Hub Setup Diagram](/front/plugins/sync/sync_hub.png)

View File

@@ -159,6 +159,81 @@
"string": "Encryption key used to encrypt the data before sending and for decryption on the hub. The key needs to be the same on the hub and on the nodes." "string": "Encryption key used to encrypt the data before sending and for decryption on the hub. The key needs to be the same on the hub and on the nodes."
} }
] ]
},{
"function": "nodes",
"type": {
"dataType": "array",
"elements": [
{
"elementType": "input",
"elementOptions": [
{ "placeholder": "Enter full url" },
{ "suffix": "_in" },
{ "cssClasses": "col-sm-10" },
{ "prefillValue": "null" }
],
"transformers": []
},
{
"elementType": "button",
"elementOptions": [
{ "sourceSuffixes": ["_in"] },
{ "separator": "" },
{ "cssClasses": "col-xs-12" },
{ "onClick": "addList(this, false)" },
{ "getStringKey": "Gen_Add" }
],
"transformers": []
},
{
"elementType": "select",
"elementHasInputValue": 1,
"elementOptions": [
{ "multiple": "true" },
{ "readonly": "true" },
{ "editable": "true" }
],
"transformers": []
},
{
"elementType": "button",
"elementOptions": [
{ "sourceSuffixes": [] },
{ "separator": "" },
{ "cssClasses": "col-xs-6" },
{ "onClick": "removeAllOptions(this)" },
{ "getStringKey": "Gen_Remove_All" }
],
"transformers": []
},
{
"elementType": "button",
"elementOptions": [
{ "sourceSuffixes": [] },
{ "separator": "" },
{ "cssClasses": "col-xs-6" },
{ "onClick": "removeFromList(this)" },
{ "getStringKey": "Gen_Remove_Last" }
],
"transformers": []
}
]
},
"default_value": [],
"options": [],
"localized": ["name", "description"],
"name": [
{
"language_code": "en_us",
"string": "Nodes [h]"
}
],
"description": [
{
"language_code": "en_us",
"string": "If specified, the hub will pull Devices data from the listed nodes."
}
]
}, },
{ {
"function": "hub_url", "function": "hub_url",

View File

@@ -3,8 +3,11 @@
// External files // External files
require '/app/front/php/server/init.php'; require '/app/front/php/server/init.php';
$method = $_SERVER['REQUEST_METHOD'];
if ($_SERVER['REQUEST_METHOD'] === 'POST') { // ----------------------------------------------
// Method to check authorization
function checkAuthorization($method) {
// Retrieve the authorization header // Retrieve the authorization header
$headers = apache_request_headers(); $headers = apache_request_headers();
$auth_header = $headers['Authorization'] ?? ''; $auth_header = $headers['Authorization'] ?? '';
@@ -14,16 +17,56 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if ($auth_header !== $expected_token) { if ($auth_header !== $expected_token) {
http_response_code(403); http_response_code(403);
echo 'Forbidden'; echo 'Forbidden';
write_notification("[Plugin: SYNC] Incoming data: Incorrect API Token", "alert"); write_notification("[Plugin: SYNC] Incoming data: Incorrect API Token (".$method.")", "alert");
exit; exit;
} }
}
// ----------------------------------------------
// Function to return JSON response
function jsonResponse($status, $data = '', $message = '') {
http_response_code($status);
header('Content-Type: application/json');
echo json_encode([
'node_name' => getSettingValue('SYNC_node_name'),
'status' => $status,
'message' => $message,
'data_base64' => $data,
'timestamp' => date('Y-m-d H:i:s')
]);
}
// ----------------------------------------------
// MAIN
// ----------------------------------------------
// requesting data (this is a NODE)
if ($method === 'GET') {
checkAuthorization($method);
$file_path = "/app/front/api/table_devices.json";
$data = file_get_contents($file_path);
// Prepare the data to return as a JSON response
$response_data = base64_encode($data);
// Return JSON response
jsonResponse(200, $response_data, 'OK');
write_notification("[Plugin: SYNC] Data sent", "info");
}
// receiving data (this is a HUB)
else if ($method === 'POST') {
checkAuthorization($method);
// Retrieve and decode the data from the POST request // Retrieve and decode the data from the POST request
$data = $_POST['data'] ?? ''; $data = $_POST['data'] ?? '';
$plugin_folder = $_POST['plugin_folder'] ?? ''; $plugin_folder = $_POST['plugin_folder'] ?? '';
$node_name = $_POST['node_name'] ?? ''; $node_name = $_POST['node_name'] ?? '';
$storage_path = "/app/front/plugins/{$plugin_folder}"; $storage_path = "/app/front/plugins/{$plugin_folder}";
// Create the storage directory if it doesn't exist // Create the storage directory if it doesn't exist
@@ -43,12 +86,12 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$file_path = "{$storage_path}/last_result.encoded.{$node_name}.{$file_count}.log"; $file_path = "{$storage_path}/last_result.encoded.{$node_name}.{$file_count}.log";
// Save the decoded data to the file // Save the decoded data to the file
file_put_contents($file_path, $data); file_put_contents($file_path, $data);
http_response_code(200); http_response_code(200);
echo 'Data received and stored successfully'; echo 'Data received and stored successfully';
write_notification("[Plugin: SYNC] Data received ({$plugin_folder})", "info"); write_notification("[Plugin: SYNC] Data received ({$plugin_folder})", "info");
} else { } else {
http_response_code(405); http_response_code(405);
echo 'Method Not Allowed'; echo 'Method Not Allowed';

View File

@@ -7,6 +7,7 @@ import hashlib
import requests import requests
import json import json
import sqlite3 import sqlite3
import base64
# Define the installation path and extend the system path for plugin imports # Define the installation path and extend the system path for plugin imports
@@ -46,24 +47,66 @@ def main():
hub_url = get_setting_value('SYNC_hub_url') hub_url = get_setting_value('SYNC_hub_url')
node_name = get_setting_value('SYNC_node_name') node_name = get_setting_value('SYNC_node_name')
send_devices = get_setting_value('SYNC_devices') send_devices = get_setting_value('SYNC_devices')
pull_nodes = get_setting_value('SYNC_nodes')
# variables to determine operation mode
is_hub = False
is_node = False
# Check if api_token set
if not api_token:
mylog('verbose', [f'[{pluginName}] ⚠ ERROR api_token not defined - quitting.'])
return -1
# Get all plugin configurations # check if this is a hub or a node
all_plugins = get_plugins_configs() if len(hub_url) > 0 and (send_devices or plugins_to_sync):
is_node = True
mylog('verbose', [f'[{pluginName}] Mode 1: PUSH (NODE) - This is a NODE as SYNC_hub_url, SYNC_devices or SYNC_plugins are set'])
if len(pull_nodes) > 0:
is_hub = True
mylog('verbose', [f'[{pluginName}] Mode 2: PULL (HUB) - This is a HUB as SYNC_nodes is set'])
mylog('verbose', [f'[{pluginName}] plugins_to_sync {plugins_to_sync}']) # Mode 1: PUSH/SEND (NODE)
if is_node:
# PUSHING/SENDING Plugins
# Get all plugin configurations
all_plugins = get_plugins_configs()
# Plugins processing mylog('verbose', [f'[{pluginName}] plugins_to_sync {plugins_to_sync}'])
index = 0
for plugin in all_plugins: for plugin in all_plugins:
pref = plugin["unique_prefix"] pref = plugin["unique_prefix"]
if pref in plugins_to_sync: index = 0
index += 1 if pref in plugins_to_sync:
mylog('verbose', [f'[{pluginName}] synching "{pref}" ({index}/{len(plugins_to_sync)})']) index += 1
mylog('verbose', [f'[{pluginName}] synching "{pref}" ({index}/{len(plugins_to_sync)})'])
# Construct the file path for the plugin's last_result.log file # Construct the file path for the plugin's last_result.log file
plugin_folder = plugin["code_name"] plugin_folder = plugin["code_name"]
file_path = f"{INSTALL_PATH}/front/plugins/{plugin_folder}/last_result.log" file_path = f"{INSTALL_PATH}/front/plugins/{plugin_folder}/last_result.log"
if os.path.exists(file_path):
# Read the content of the log file
with open(file_path, 'r') as f:
file_content = f.read()
mylog('verbose', [f'[{pluginName}] Sending file_content: "{file_content}"'])
# encrypt and send data to the hub
send_data(api_token, file_content, encryption_key, plugin_folder, node_name, pref, hub_url)
else:
mylog('verbose', [f'[{pluginName}] {plugin_folder}/last_result.log not found'])
# PUSHING/SENDING devices
if send_devices:
file_path = f"{INSTALL_PATH}/front/api/table_devices.json"
plugin_folder = 'sync'
pref = 'SYNC'
if os.path.exists(file_path): if os.path.exists(file_path):
# Read the content of the log file # Read the content of the log file
@@ -71,131 +114,147 @@ def main():
file_content = f.read() file_content = f.read()
mylog('verbose', [f'[{pluginName}] Sending file_content: "{file_content}"']) mylog('verbose', [f'[{pluginName}] Sending file_content: "{file_content}"'])
# encrypt and send data to the hub
send_data(api_token, file_content, encryption_key, plugin_folder, node_name, pref, hub_url) send_data(api_token, file_content, encryption_key, plugin_folder, node_name, pref, hub_url)
else:
mylog('verbose', [f'[{pluginName}] SYNC_hub_url not defined, skipping posting "Devices" data'])
else:
mylog('verbose', [f'[{pluginName}] SYNC_hub_url not defined, skipping posting "Plugins" and "Devices" data'])
else: # Mode 2: PULL/GET (HUB)
mylog('verbose', [f'[{pluginName}] {plugin_folder}/last_result.log not found'])
# PULLING DEVICES
# Devices procesing
if send_devices:
file_path = f"{INSTALL_PATH}/front/api/table_devices.json"
plugin_folder = 'sync'
pref = 'SYNC'
if os.path.exists(file_path):
# Read the content of the log file
with open(file_path, 'r') as f:
file_content = f.read()
mylog('verbose', [f'[{pluginName}] Sending file_content: "{file_content}"'])
send_data(api_token, file_content, encryption_key, plugin_folder, node_name, pref, hub_url)
# process any received data for the Device DB table
# Create the file path
file_dir = os.path.join(pluginsPath, 'sync') file_dir = os.path.join(pluginsPath, 'sync')
file_prefix = 'last_result' file_prefix = 'last_result'
# pull data from nodes if specified
if is_hub:
for node_url in pull_nodes:
response_json = get_data(api_token, node_url)
# Extract node_name and base64 data
node_name = response_json.get('node_name', 'unknown_node')
data_base64 = response_json.get('data_base64', '')
# Decode base64 data
decoded_data = base64.b64decode(data_base64)
# Create log file name using node name
log_file_name = f'{file_prefix}.{node_name}.log'
# Write decoded data to log file
with open(os.path.join(file_dir, log_file_name), 'wb') as log_file:
log_file.write(decoded_data)
message = f'[{pluginName}] Device data from node "{node_name}" written to {log_file_name}'
mylog('verbose', [message])
write_notification(message, 'info', timeNowTZ())
# Process any received data for the Device DB table
# Create the file path
# Decode files, rename them, and get the list of files # Decode files, rename them, and get the list of files
files_to_process = decode_and_rename_files(file_dir, file_prefix) files_to_process = decode_and_rename_files(file_dir, file_prefix)
# Connect to the App database
conn = sqlite3.connect(fullDbPath)
cursor = conn.cursor()
# Collect all unique dev_MAC values from the JSON files
unique_mac_addresses = set()
device_data = []
mylog('verbose', [f'[{pluginName}] Devices files to process: "{files_to_process}"'])
for file_name in files_to_process:
# only process received .log files, skipping the one logging the progress of this plugin
if file_name != 'last_result.log':
mylog('verbose', [f'[{pluginName}] Processing: "{file_name}"'])
# Store e.g. Node_1 from last_result.encoded.Node_1.1.log
tmp_SyncHubNodeName = ''
if len(file_name.split('.')) > 3:
tmp_SyncHubNodeName = file_name.split('.')[2]
file_path = f"{INSTALL_PATH}/front/plugins/sync/{file_name}"
with open(file_path, 'r') as f:
data = json.load(f)
for device in data['data']:
if device['dev_MAC'] not in unique_mac_addresses:
device['dev_SyncHubNodeName'] = tmp_SyncHubNodeName
unique_mac_addresses.add(device['dev_MAC'])
device_data.append(device)
if len(files_to_process) > 0:
mylog('verbose', [f'[{pluginName}] Mode 3: RECEIVE (HUB) - This is a HUB as received data found'])
if len(device_data) > 0: # Connect to the App database
# Retrieve existing dev_MAC values from the Devices table conn = sqlite3.connect(fullDbPath)
placeholders = ', '.join('?' for _ in unique_mac_addresses) cursor = conn.cursor()
cursor.execute(f'SELECT dev_MAC FROM Devices WHERE dev_MAC IN ({placeholders})', tuple(unique_mac_addresses))
existing_mac_addresses = set(row[0] for row in cursor.fetchall())
# insert devices into the lats_result.log to manage state # Collect all unique dev_MAC values from the JSON files
for device in device_data: unique_mac_addresses = set()
if device['dev_PresentLastScan'] == 1: device_data = []
plugin_objects.add_object(
primaryId = device['dev_MAC'],
secondaryId = device['dev_LastIP'],
watched1 = device['dev_Name'],
watched2 = device['dev_Vendor'],
watched3 = device['dev_SyncHubNodeName'],
watched4 = device['dev_GUID'],
extra = '',
foreignKey = device['dev_GUID'])
# Filter out existing devices mylog('verbose', [f'[{pluginName}] Devices files to process: "{files_to_process}"'])
new_devices = [device for device in device_data if device['dev_MAC'] not in existing_mac_addresses]
# Remove 'rowid' key if it exists for file_name in files_to_process:
for device in new_devices:
device.pop('rowid', None)
mylog('verbose', [f'[{pluginName}] All devices: "{len(device_data)}"']) # only process received .log files, skipping the one logging the progress of this plugin
mylog('verbose', [f'[{pluginName}] New devices: "{len(new_devices)}"']) if file_name != 'last_result.log':
mylog('verbose', [f'[{pluginName}] Processing: "{file_name}"'])
# Prepare the insert statement # Store e.g. Node_1 from last_result.encoded.Node_1.1.log
if new_devices: tmp_SyncHubNodeName = ''
if len(file_name.split('.')) > 3:
tmp_SyncHubNodeName = file_name.split('.')[2]
columns = ', '.join(k for k in new_devices[0].keys() if k != 'rowid')
placeholders = ', '.join('?' for k in new_devices[0] if k != 'rowid')
sql = f'INSERT INTO Devices ({columns}) VALUES ({placeholders})'
# Extract values for the new devices file_path = f"{INSTALL_PATH}/front/plugins/sync/{file_name}"
values = [tuple(device.values()) for device in new_devices]
with open(file_path, 'r') as f:
data = json.load(f)
for device in data['data']:
if device['dev_MAC'] not in unique_mac_addresses:
device['dev_SyncHubNodeName'] = tmp_SyncHubNodeName
unique_mac_addresses.add(device['dev_MAC'])
device_data.append(device)
mylog('verbose', [f'[{pluginName}] Inserting Devices SQL : "{sql}"']) if len(device_data) > 0:
mylog('verbose', [f'[{pluginName}] Inserting Devices VALUES: "{values}"']) # Retrieve existing dev_MAC values from the Devices table
placeholders = ', '.join('?' for _ in unique_mac_addresses)
cursor.execute(f'SELECT dev_MAC FROM Devices WHERE dev_MAC IN ({placeholders})', tuple(unique_mac_addresses))
existing_mac_addresses = set(row[0] for row in cursor.fetchall())
# Use executemany for batch insertion # insert devices into the lats_result.log to manage state
cursor.executemany(sql, values) for device in device_data:
if device['dev_PresentLastScan'] == 1:
plugin_objects.add_object(
primaryId = device['dev_MAC'],
secondaryId = device['dev_LastIP'],
watched1 = device['dev_Name'],
watched2 = device['dev_Vendor'],
watched3 = device['dev_SyncHubNodeName'],
watched4 = device['dev_GUID'],
extra = '',
foreignKey = device['dev_GUID'])
message = f'[{pluginName}] Inserted "{len(new_devices)}" new devices' # Filter out existing devices
new_devices = [device for device in device_data if device['dev_MAC'] not in existing_mac_addresses]
mylog('verbose', [message]) # Remove 'rowid' key if it exists
write_notification(message, 'info', timeNowTZ()) for device in new_devices:
device.pop('rowid', None)
# Commit and close the connection mylog('verbose', [f'[{pluginName}] All devices: "{len(device_data)}"'])
conn.commit() mylog('verbose', [f'[{pluginName}] New devices: "{len(new_devices)}"'])
conn.close()
# log result # Prepare the insert statement
plugin_objects.write_result_file() if new_devices:
columns = ', '.join(k for k in new_devices[0].keys() if k != 'rowid')
placeholders = ', '.join('?' for k in new_devices[0] if k != 'rowid')
sql = f'INSERT INTO Devices ({columns}) VALUES ({placeholders})'
# Extract values for the new devices
values = [tuple(device.values()) for device in new_devices]
mylog('verbose', [f'[{pluginName}] Inserting Devices SQL : "{sql}"'])
mylog('verbose', [f'[{pluginName}] Inserting Devices VALUES: "{values}"'])
# Use executemany for batch insertion
cursor.executemany(sql, values)
message = f'[{pluginName}] Inserted "{len(new_devices)}" new devices'
mylog('verbose', [message])
write_notification(message, 'info', timeNowTZ())
# Commit and close the connection
conn.commit()
conn.close()
# log result
plugin_objects.write_result_file()
return 0 return 0
# send data to the HUB
def send_data(api_token, file_content, encryption_key, plugin_folder, node_name, pref, hub_url): def send_data(api_token, file_content, encryption_key, plugin_folder, node_name, pref, hub_url):
# Encrypt the log data using the encryption_key # Encrypt the log data using the encryption_key
encrypted_data = encrypt_data(file_content, encryption_key) encrypted_data = encrypt_data(file_content, encryption_key)
@@ -223,6 +282,36 @@ def send_data(api_token, file_content, encryption_key, plugin_folder, node_name,
message = f'[{pluginName}] Failed to send data for "{plugin_folder}" (Status code: {response.status_code})' message = f'[{pluginName}] Failed to send data for "{plugin_folder}" (Status code: {response.status_code})'
mylog('verbose', [message]) mylog('verbose', [message])
write_notification(message, 'alert', timeNowTZ()) write_notification(message, 'alert', timeNowTZ())
# get data from the nodes to the HUB
def get_data(api_token, node_url):
mylog('verbose', [f'[{pluginName}] Getting data from node: "{node_url}"'])
# Set the authorization header with the API token
headers = {'Authorization': f'Bearer {api_token}'}
api_endpoint = f"{node_url}/plugins/sync/hub.php"
response = requests.get(api_endpoint, headers=headers)
# mylog('verbose', [f'[{pluginName}] response: "{response}"'])
if response.status_code == 200:
try:
# Parse JSON response
response_json = response.json()
return response_json
except json.JSONDecodeError:
message = f'[{pluginName}] Failed to parse JSON response from "{node_url}"'
mylog('verbose', [message])
write_notification(message, 'alert', timeNowTZ())
return ""
else:
message = f'[{pluginName}] Failed to send data for "{node_url}" (Status code: {response.status_code})'
mylog('verbose', [message])
write_notification(message, 'alert', timeNowTZ())
return ""

View File

@@ -26,6 +26,367 @@
], ],
"params": [], "params": [],
"settings": [ "settings": [
{
"function": "NOT_RANDOM_MAC",
"type": {
"dataType": "array",
"elements": [
{
"elementType": "input",
"elementOptions": [
{ "placeholder": "Enter value" },
{ "suffix": "_in" },
{ "cssClasses": "col-sm-10" },
{ "prefillValue": "null" }
],
"transformers": []
},
{
"elementType": "button",
"elementOptions": [
{ "sourceSuffixes": ["_in"] },
{ "separator": "" },
{ "cssClasses": "col-xs-12" },
{ "onClick": "addList(this,false)" },
{ "getStringKey": "Gen_Add" }
],
"transformers": []
},
{
"elementType": "select",
"elementHasInputValue": 1,
"elementOptions": [
{ "multiple": "true" },
{ "readonly": "true" },
{ "editable": "true" }
],
"transformers": []
},
{
"elementType": "button",
"elementOptions": [
{ "sourceSuffixes": [] },
{ "separator": "" },
{ "cssClasses": "col-xs-6" },
{ "onClick": "removeAllOptions(this)" },
{ "getStringKey": "Gen_Remove_All" }
],
"transformers": []
},
{
"elementType": "button",
"elementOptions": [
{ "sourceSuffixes": [] },
{ "separator": "" },
{ "cssClasses": "col-xs-6" },
{ "onClick": "removeFromList(this)" },
{ "getStringKey": "Gen_Remove_Last" }
],
"transformers": []
}
]
},
"maxLength": 50,
"default_value": [],
"options": [],
"localized": [],
"name": [
{
"string": "_GLOBAL_LANG_FILES_"
}
],
"description": [
{
"string": "_GLOBAL_LANG_FILES_"
}
]
},
{
"function": "ICONS",
"type": {
"dataType": "array",
"elements": [
{
"elementType": "input",
"elementOptions": [
{ "placeholder": "Enter value" },
{ "suffix": "_in" },
{ "cssClasses": "col-sm-10" },
{ "prefillValue": "null" }
],
"transformers": []
},
{
"elementType": "button",
"elementOptions": [
{ "sourceSuffixes": ["_in"] },
{ "separator": "" },
{ "cssClasses": "col-xs-12" },
{ "onClick": "addList(this,false)" },
{ "getStringKey": "Gen_Add" }
],
"transformers": []
},
{
"elementType": "select",
"elementHasInputValue": 1,
"elementOptions": [
{ "multiple": "true" },
{ "readonly": "true" },
{ "editable": "true" }
],
"transformers": []
},
{
"elementType": "button",
"elementOptions": [
{ "sourceSuffixes": [] },
{ "separator": "" },
{ "cssClasses": "col-xs-6" },
{ "onClick": "removeAllOptions(this)" },
{ "getStringKey": "Gen_Remove_All" }
],
"transformers": []
},
{
"elementType": "button",
"elementOptions": [
{ "sourceSuffixes": [] },
{ "separator": "" },
{ "cssClasses": "col-xs-6" },
{ "onClick": "removeFromList(this)" },
{ "getStringKey": "Gen_Remove_Last" }
],
"transformers": []
}
]
},
"maxLength": 50,
"default_value": [
"PGkgY2xhc3M9ImZhIGZhLWNvbXB1dGVyIj48L2k+",
"PGkgY2xhc3M9ImZhIGZhLWV0aGVybmV0Ij48L2k+",
"PGkgY2xhc3M9ImZhIGZhLWdhbWVwYWQiPjwvaT4=",
"PGkgY2xhc3M9ImZhIGZhLWdsb2JlIj48L2k+",
"PGkgY2xhc3M9ImZhIGZhLWxhcHRvcCI+PC9pPg==",
"PGkgY2xhc3M9ImZhIGZhLWxpZ2h0YnVsYiI+PC9pPg==",
"PGkgY2xhc3M9ImZhIGZhLXNoaWVsZCI+PC9pPg==",
"PGkgY2xhc3M9ImZhIGZhLXdpZmkiPjwvaT4=",
"PGkgY2xhc3M9ImZhIGZhLWdhbWVwYWQiPjwvaT4="
],
"options": [],
"localized": [],
"name": [
{
"string": "_GLOBAL_LANG_FILES_"
}
],
"description": [
{
"string": "_GLOBAL_LANG_FILES_"
}
]
},
{
"function": "REFRESH",
"type": {
"dataType": "integer",
"elements": [
{
"elementType": "input",
"elementOptions": [{ "type": "number" }],
"transformers": []
}
]
},
"maxLength": 50,
"default_value": 0,
"options": [],
"localized": [],
"name": [
{
"string": "_GLOBAL_LANG_FILES_"
}
],
"description": [
{
"string": "_GLOBAL_LANG_FILES_"
}
]
},
{
"function": "DEV_SECTIONS",
"type": {
"dataType": "array",
"elements": [
{
"elementType": "select",
"elementOptions": [{ "multiple": "true" }],
"transformers": []
}
]
},
"maxLength": 50,
"default_value": [],
"options": ["Tile Cards", "Device Presence"],
"localized": [],
"name": [
{
"string": "_GLOBAL_LANG_FILES_"
}
],
"description": [
{
"string": "_GLOBAL_LANG_FILES_"
}
]
},
{
"function": "PRESENCE",
"type": {
"dataType": "array",
"elements": [
{
"elementType": "select",
"elementOptions": [{ "multiple": "true" }],
"transformers": []
}
]
},
"maxLength": 50,
"default_value": ["online", "offline", "archived"],
"options": ["online", "offline", "archived"],
"localized": [],
"name": [
{
"string": "_GLOBAL_LANG_FILES_"
}
],
"description": [
{
"string": "_GLOBAL_LANG_FILES_"
}
]
},
{
"function": "MY_DEVICES",
"type": {
"dataType": "array",
"elements": [
{
"elementType": "select",
"elementOptions": [{ "multiple": "true" }],
"transformers": []
}
]
},
"maxLength": 50,
"default_value": ["online", "offline", "archived", "new", "down"],
"options": ["online", "offline", "archived", "new", "down"],
"localized": [],
"name": [
{
"string": "_GLOBAL_LANG_FILES_"
}
],
"description": [
{
"string": "_GLOBAL_LANG_FILES_"
}
]
},
{
"function": "device_columns",
"type": {
"dataType": "array",
"elements": [
{
"elementType": "select",
"elementOptions": [{ "multiple": "true", "ordeable": "true" }],
"transformers": ["getString"]
},
{
"elementType": "button",
"elementOptions": [
{ "sourceSuffixes": [] },
{ "separator": "" },
{ "cssClasses": "col-xs-4" },
{ "onClick": "selectAll(this)" },
{ "getStringKey": "Gen_Add_All" }
],
"transformers": []
},
{
"elementType": "button",
"elementOptions": [
{ "sourceSuffixes": [] },
{ "separator": "" },
{ "cssClasses": "col-xs-4" },
{ "onClick": "unselectAll(this)" },
{ "getStringKey": "Gen_Remove_All" }
],
"transformers": []
},
{
"elementType": "button",
"elementOptions": [
{ "sourceSuffixes": [] },
{ "separator": "" },
{ "cssClasses": "col-xs-4" },
{ "onClick": "selectChange(this)" },
{ "getStringKey": "Gen_Change" }
],
"transformers": []
}
]
},
"maxLength": 50,
"default_value": [
"Device_TableHead_Icon",
"Device_TableHead_Name",
"Device_TableHead_Type",
"Device_TableHead_LastIP",
"Device_TableHead_Status",
"Device_TableHead_MAC_full"
],
"options": [
"Device_TableHead_Name",
"Device_TableHead_Owner",
"Device_TableHead_Type",
"Device_TableHead_Icon",
"Device_TableHead_Favorite",
"Device_TableHead_Group",
"Device_TableHead_FirstSession",
"Device_TableHead_LastSession",
"Device_TableHead_LastIP",
"Device_TableHead_MAC",
"Device_TableHead_Status",
"Device_TableHead_MAC_full",
"Device_TableHead_LastIPOrder",
"Device_TableHead_Rowid",
"Device_TableHead_Parent_MAC",
"Device_TableHead_Connected_Devices",
"Device_TableHead_Location",
"Device_TableHead_Vendor",
"Device_TableHead_Port",
"Device_TableHead_GUID",
"Device_TableHead_SyncHubNodeName",
"Device_TableHead_NetworkSite",
"Device_TableHead_SSID"
],
"localized": ["name", "description"],
"name": [
{
"language_code": "en_us",
"string": "Device Columns"
}
],
"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."
}
]
},
{ {
"function": "shown_cards", "function": "shown_cards",
"type": { "type": {
@@ -67,7 +428,7 @@
"description": [ "description": [
{ {
"language_code": "en_us", "language_code": "en_us",
"string": "Which tiles to show on teh top of the Devices page." "string": "Which tiles to show on the top of the Devices page."
} }
] ]
}, },
@@ -98,6 +459,34 @@
"string": "Hide Device tiles with zero results." "string": "Hide Device tiles with zero results."
} }
] ]
},
{
"function": "dark_mode",
"type": {
"dataType": "boolean",
"elements": [
{
"elementType": "input",
"elementOptions": [{ "type": "checkbox" }],
"transformers": []
}
]
},
"default_value": false,
"options": [],
"localized": ["name", "description"],
"name": [
{
"language_code": "en_us",
"string": "Dark mode"
}
],
"description": [
{
"language_code": "en_us",
"string": "Enable dark mode."
}
]
} }
] ]
} }

View File

@@ -25,28 +25,12 @@
{ {
"language_code": "en_us", "language_code": "en_us",
"string": "<i class=\"fa-solid fa-binoculars\"></i>" "string": "<i class=\"fa-solid fa-binoculars\"></i>"
},
{
"language_code": "es_es",
"string": "<i class=\"fa-solid fa-binoculars\"></i>"
},
{
"language_code": "de_de",
"string": "<i class=\"fa-solid fa-binoculars\"></i>"
} }
], ],
"description": [ "description": [
{ {
"language_code": "en_us", "language_code": "en_us",
"string": "This plugin is to import undiscoverable devices from a file." "string": "This plugin is to import undiscoverable devices from a file. Only ASCII characters are supported."
},
{
"language_code": "es_es",
"string": "Este complemento es para importar dispositivos no detectables desde un archivo."
},
{
"language_code": "de_de",
"string": "Ein Plugin zum Importieren von nicht erkennbaren Geräten aus einer Datei."
} }
], ],
"params": [ "params": [

View File

@@ -42,7 +42,7 @@ def main():
fake_mac = string_to_mac_hash(fake_dev) fake_mac = string_to_mac_hash(fake_dev)
plugin_objects.add_object( plugin_objects.add_object(
primaryId=fake_dev, # MAC (Device Name) primaryId=fake_mac, # MAC (Device Name)
secondaryId="0.0.0.0", # IP Address (always 0.0.0.0) secondaryId="0.0.0.0", # IP Address (always 0.0.0.0)
watched1=fake_dev, # Device Name watched1=fake_dev, # Device Name
watched2="", watched2="",

View File

@@ -99,7 +99,7 @@
// Function to update the displayed data and timestamp based on the selected format and index // Function to update the displayed data and timestamp based on the selected format and index
function updateData(format, index) { function updateData(format, index) {
// Fetch data from the API endpoint // Fetch data from the API endpoint
fetch('/api/table_notifications.json?nocache=' + Date.now()) fetch('api/table_notifications.json?nocache=' + Date.now())
.then(response => response.json()) .then(response => response.json())
.then(data => { .then(data => {
if (index < 0) { if (index < 0) {
@@ -163,7 +163,7 @@
const urlParams = new URLSearchParams(window.location.search); const urlParams = new URLSearchParams(window.location.search);
if (urlParams.has('guid')) { if (urlParams.has('guid')) {
const guid = urlParams.get('guid'); const guid = urlParams.get('guid');
fetch('/api/table_notifications.json') fetch('api/table_notifications.json')
.then(response => response.json()) .then(response => response.json())
.then(data => { .then(data => {
const index = findIndexByGUID(data.data, guid); const index = findIndexByGUID(data.data, guid);

View File

@@ -378,6 +378,7 @@ $settingsJSON_DB = json_encode($settings, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX
const valIn = set['Value']; const valIn = set['Value'];
const codeName = set['Code_Name']; const codeName = set['Code_Name'];
const overriddenByEnv = set['OverriddenByEnv'] == 1;
const setType = set['Type']; const setType = set['Type'];
const isMetadata = codeName.includes('__metadata'); const isMetadata = codeName.includes('__metadata');
// is this isn't a metadata entry, get corresponding metadata object from the dummy setting // is this isn't a metadata entry, get corresponding metadata object from the dummy setting
@@ -416,11 +417,11 @@ $settingsJSON_DB = json_encode($settings, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX
<div class="table_cell setting_description"> <div class="table_cell setting_description">
${getString(codeName + '_description', set['Description'])} ${getString(codeName + '_description', set['Description'])}
</div> </div>
<div class="table_cell setting_input input-group col-sm-12"> <div class="table_cell input-group setting_input ${overriddenByEnv ? "setting_overriden_by_env" : ""} input-group col-sm-12">
`; `;
// OVERRIDE // OVERRIDE
// surface settings override functionality if the setting is a template that can be overriden with user defined values // surface settings override functionality if the setting is a template that can be overridden with user defined values
// if the setting is a json of the correct structure, handle like a template setting // if the setting is a json of the correct structure, handle like a template setting
let overrideHtml = ""; let overrideHtml = "";
@@ -428,7 +429,7 @@ $settingsJSON_DB = json_encode($settings, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX
//pre-check if this is a json object that needs value extraction //pre-check if this is a json object that needs value extraction
let overridable = false; // indicates if the setting is overridable let overridable = false; // indicates if the setting is overridable
let override = false; // If the setting is set to be overriden by the user or by default let override = false; // If the setting is set to be overridden by the user or by default
let readonly = ""; // helper variable to make text input readonly let readonly = ""; // helper variable to make text input readonly
let disabled = ""; // helper variable to make checkbox input readonly let disabled = ""; // helper variable to make checkbox input readonly
@@ -460,7 +461,7 @@ $settingsJSON_DB = json_encode($settings, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX
// INPUT // INPUT
console.log(codeName); // console.log(codeName);
// Parse the setType JSON string into an object // Parse the setType JSON string into an object
let inputHtml = ''; let inputHtml = '';
@@ -476,6 +477,7 @@ $settingsJSON_DB = json_encode($settings, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX
inputType, inputType,
readOnly, readOnly,
isMultiSelect, isMultiSelect,
isOrdeable,
cssClasses, cssClasses,
placeholder, placeholder,
suffix, suffix,
@@ -484,7 +486,10 @@ $settingsJSON_DB = json_encode($settings, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX
editable, editable,
valRes, valRes,
getStringKey, getStringKey,
onClick onClick,
onChange,
customParams,
customId
} = handleElementOptions(codeName, elementOptions, transformers, valIn); } = handleElementOptions(codeName, elementOptions, transformers, valIn);
// override // override
@@ -494,8 +499,18 @@ $settingsJSON_DB = json_encode($settings, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX
switch (elementType) { switch (elementType) {
case 'select': case 'select':
let multi = isMultiSelect ? "multiple" : ""; let multi = isMultiSelect ? "multiple" : "";
let addCss = isOrdeable ? "select2 select2-hidden-accessible" : "";
inputHtml += `<select onChange="settingsChanged()" my-data-type="${dataType}" my-editable="${editable}" class="form-control" name="${codeName}" id="${codeName}" ${multi}>
inputHtml += `<select onChange="settingsChanged();${onChange}"
my-data-type="${dataType}"
my-editable="${editable}"
class="form-control ${addCss}"
name="${codeName}"
id="${codeName}"
my-customparams="${customParams}"
my-customid="${customId}"
${multi}>
<option value="" id="${codeName + "_temp_"}"></option> <option value="" id="${codeName + "_temp_"}"></option>
</select>`; </select>`;
@@ -510,8 +525,10 @@ $settingsJSON_DB = json_encode($settings, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX
inputHtml += ` inputHtml += `
<input <input
class="${inputClass} ${cssClasses}" class="${inputClass} ${cssClasses}"
onChange="settingsChanged()" onChange="settingsChanged();${onChange}"
my-data-type="${dataType}" my-data-type="${dataType}"
my-customparams="${customParams}"
my-customid="${customId}"
id="${codeName}${suffix}" id="${codeName}${suffix}"
type="${inputType}" type="${inputType}"
value="${val}" value="${val}"
@@ -526,6 +543,8 @@ $settingsJSON_DB = json_encode($settings, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX
inputHtml += ` inputHtml += `
<button <button
class="btn btn-primary ${cssClasses}" class="btn btn-primary ${cssClasses}"
my-customparams="${customParams}"
my-customid="${customId}"
my-input-from="${sourceIds}" my-input-from="${sourceIds}"
my-input-to="${codeName}" my-input-to="${codeName}"
onclick="${onClick}"> onclick="${onClick}">
@@ -536,12 +555,25 @@ $settingsJSON_DB = json_encode($settings, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX
inputHtml += ` inputHtml += `
<textarea <textarea
class="form-control input" class="form-control input"
my-customparams="${customParams}"
my-customid="${customId}"
my-data-type="${dataType}" my-data-type="${dataType}"
id="${codeName}" id="${codeName}"
${readOnly}> ${readOnly}>
${val} ${val}
</textarea>`; </textarea>`;
break; break;
case 'span':
inputHtml += `
<span
class="${cssClasses}"
my-data-type="${dataType}"
my-customparams="${customParams}"
my-customid="${customId}"
>
${getString(getStringKey)}
</span>`;
break;
default: default:
console.warn(`🟥Unknown element type: ${elementType}`); console.warn(`🟥Unknown element type: ${elementType}`);
@@ -549,7 +581,7 @@ $settingsJSON_DB = json_encode($settings, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX
}); });
// EVENTS // EVENTS
// process events (e.g. run ascan, or test a notification) if associated with the setting // process events (e.g. run a scan, or test a notification) if associated with the setting
let eventsHtml = ""; let eventsHtml = "";
const eventsList = createArray(set['Events']); const eventsList = createArray(set['Events']);
@@ -588,6 +620,8 @@ $settingsJSON_DB = json_encode($settings, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX
}, 50); }, 50);
setupSmoothScrolling() setupSmoothScrolling()
// try to initialize select2
initSelect2()
hideSpinner() hideSpinner()
} }
@@ -635,16 +669,26 @@ $settingsJSON_DB = json_encode($settings, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX
// console.log(setTypeObject); // console.log(setTypeObject);
const dataType = setTypeObject.dataType; const dataType = setTypeObject.dataType;
// const lastElementObj = setTypeObject.elements[setTypeObject.elements.length - 1]; //🔽
// get the element with the input value(s) // get the element with the input value(s)
const elementsWithInputValue = setTypeObject.elements.filter(element => element.elementHasInputValue === 1); let elements = setTypeObject.elements.filter(element => element.elementHasInputValue === 1);
const { elementType, elementOptions = [], transformers = [] } = elementsWithInputValue; // if none found, take last
if(elements.length == 0)
{
elementWithInputValue = setTypeObject.elements[setTypeObject.elements.length - 1]
} else
{
elementWithInputValue = elements[0]
}
const { elementType, elementOptions = [], transformers = [] } = elementWithInputValue;
const { const {
inputType, inputType,
readOnly, readOnly,
isMultiSelect, isMultiSelect,
isOrdeable,
cssClasses, cssClasses,
placeholder, placeholder,
suffix, suffix,
@@ -653,38 +697,51 @@ $settingsJSON_DB = json_encode($settings, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX
editable, editable,
valRes, valRes,
getStringKey, getStringKey,
onClick onClick,
onChange,
customParams,
customId
} = handleElementOptions('none', elementOptions, transformers, val = ""); } = handleElementOptions('none', elementOptions, transformers, val = "");
let value; let value;
if (dataType === "string" || if (dataType === "string" ||
(dataType === "integer" && (inputType === "number" || inputType === "text"))) { (dataType === "integer" && (inputType === "number" || inputType === "text"))) {
value = $('#' + setCodeName).val(); value = $('#' + setCodeName).val();
value = applyTransformers(value, transformers); value = applyTransformers(value, transformers);
settingsArray.push([prefix, setCodeName, dataType, value]); settingsArray.push([prefix, setCodeName, dataType, value]);
} else if (inputType === 'checkbox') { } else if (dataType === 'boolean') {
value = $(`#${setCodeName}`).is(':checked') ? 1 : 0; value = $(`#${setCodeName}`).is(':checked') ? 1 : 0;
value = applyTransformers(value, transformers); value = applyTransformers(value, transformers);
settingsArray.push([prefix, setCodeName, dataType, value]); settingsArray.push([prefix, setCodeName, dataType, value]);
} else if (dataType === "array" ) { } else if (dataType === "array" ) {
// make sure to collect all if set as "editable" or selected only otherwise
$(`#${setCodeName}`).attr("my-editable") == "true" ? additionalSelector = "" : additionalSelector = ":selected"
const temps = []; let temps = [];
$(`#${setCodeName} option${additionalSelector}`).each(function() {
const vl = $(this).val(); if(isOrdeable)
if (vl !== '') { {
temps.push(applyTransformers(vl, transformers)); temps = $(`#${setCodeName}`).val()
} } else
}); {
// make sure to collect all if set as "editable" or selected only otherwise
$(`#${setCodeName}`).attr("my-editable") == "true" ? additionalSelector = "" : additionalSelector = ":selected";
$(`#${setCodeName} option${additionalSelector}`).each(function() {
const vl = $(this).val();
if (vl !== '') {
temps.push(applyTransformers(vl, transformers));
}
});
}
value = JSON.stringify(temps); value = JSON.stringify(temps);
settingsArray.push([prefix, setCodeName, dataType, value]); settingsArray.push([prefix, setCodeName, dataType, value]);
} else if (dataType === "json") { } else if (dataType === "json") {
@@ -780,34 +837,35 @@ $settingsJSON_DB = json_encode($settings, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX
setTimeout("handleLoadingDialog()", 1000); setTimeout("handleLoadingDialog()", 1000);
} else } else
{ {
// check if the app is initialized and hide the spinner checkInitialization();
if(isAppInitialized())
{
// init page
getData()
// reload page if outdated information might be displayed
if(secondsSincePageLoad() > 5)
{
clearCache()
}
}
else
{
// reload the page if not initialized to give time the background tasks to finish
setTimeout(() => {
window.location.reload()
}, 3000);
}
} }
document.getElementById('lastImportedTime').innerHTML = humanReadable; document.getElementById('lastImportedTime').innerHTML = humanReadable;
}) })
} }
function checkInitialization() {
if (isAppInitialized()) {
// App is initialized, hide spinner and proceed with initialization
console.log("App initialized, proceeding...");
getData();
// Reload page if outdated information might be displayed
if (secondsSincePageLoad() > 10) {
console.log("App outdated, reloading...");
clearCache();
}
} else {
console.log("App not initialized, checking again in 1s...");
// Check again after a delay
setTimeout(checkInitialization, 1000);
}
}
showSpinner() showSpinner()

View File

@@ -60,7 +60,7 @@ require 'php/templates/header.php';
<script> <script>
function fetchData(callback) { function fetchData(callback) {
$.ajax({ $.ajax({
url: '/api/user_notifications.json?nocache=' + Date.now(), url: 'api/user_notifications.json?nocache=' + Date.now(),
method: 'GET', method: 'GET',
dataType: 'json', dataType: 'json',
success: function(response) { success: function(response) {

View File

@@ -15,6 +15,7 @@ pluginsPath = applicationPath + '/front/plugins'
logPath = applicationPath + '/front/log' logPath = applicationPath + '/front/log'
apiPath = applicationPath + '/front/api/' apiPath = applicationPath + '/front/api/'
reportTemplatesPath = applicationPath + '/front/report_templates/' reportTemplatesPath = applicationPath + '/front/report_templates/'
fullConfFolder = applicationPath + '/config'
fullConfPath = applicationPath + confPath fullConfPath = applicationPath + confPath
fullDbPath = applicationPath + dbPath fullDbPath = applicationPath + dbPath
vendorsPath = '/usr/share/arp-scan/ieee-oui.txt' vendorsPath = '/usr/share/arp-scan/ieee-oui.txt'

View File

@@ -213,15 +213,16 @@ class DB():
self.sql.execute(""" DROP TABLE IF EXISTS Settings;""") self.sql.execute(""" DROP TABLE IF EXISTS Settings;""")
self.sql.execute(""" self.sql.execute("""
CREATE TABLE "Settings" ( CREATE TABLE "Settings" (
"Code_Name" TEXT, "Code_Name" TEXT,
"Display_Name" TEXT, "Display_Name" TEXT,
"Description" TEXT, "Description" TEXT,
"Type" TEXT, "Type" TEXT,
"Options" TEXT, "Options" TEXT,
"RegEx" TEXT, "RegEx" TEXT,
"Value" TEXT, "Group" TEXT,
"Group" TEXT, "Value" TEXT,
"Events" TEXT "Events" TEXT,
"OverriddenByEnv" INTEGER
); );
""") """)

View File

@@ -4,7 +4,7 @@ import subprocess
import conf import conf
import os import os
import re import re
from helper import timeNowTZ, get_setting, get_setting_value, list_to_where, resolve_device_name_dig, resolve_device_name_pholus, get_device_name_nbtlookup, get_device_name_nslookup, check_IP_format from helper import timeNowTZ, get_setting, get_setting_value, list_to_where, resolve_device_name_dig, resolve_device_name_pholus, get_device_name_nbtlookup, get_device_name_nslookup, check_IP_format, sanitize_SQL_input
from logger import mylog, print_log from logger import mylog, print_log
from const import vendorsPath, vendorsPathNewest, sql_generateGuid from const import vendorsPath, vendorsPathNewest, sql_generateGuid
@@ -192,12 +192,12 @@ def create_new_devices (db):
{get_setting_value('NEWDEV_dev_NewDevice')}, {get_setting_value('NEWDEV_dev_NewDevice')},
{get_setting_value('NEWDEV_dev_SkipRepeated')}, {get_setting_value('NEWDEV_dev_SkipRepeated')},
{get_setting_value('NEWDEV_dev_ScanCycle')}, {get_setting_value('NEWDEV_dev_ScanCycle')},
'{get_setting_value('NEWDEV_dev_Owner')}', '{sanitize_SQL_input(get_setting_value('NEWDEV_dev_Owner'))}',
{get_setting_value('NEWDEV_dev_Favorite')}, {get_setting_value('NEWDEV_dev_Favorite')},
'{get_setting_value('NEWDEV_dev_Group')}', '{sanitize_SQL_input(get_setting_value('NEWDEV_dev_Group'))}',
'{get_setting_value('NEWDEV_dev_Comments')}', '{sanitize_SQL_input(get_setting_value('NEWDEV_dev_Comments'))}',
{get_setting_value('NEWDEV_dev_LogEvents')}, {get_setting_value('NEWDEV_dev_LogEvents')},
'{get_setting_value('NEWDEV_dev_Location')}'""" '{sanitize_SQL_input(get_setting_value('NEWDEV_dev_Location'))}'"""
# Fetch data from CurrentScan # Fetch data from CurrentScan
current_scan_data = sql.execute("SELECT cur_MAC, cur_Name, cur_Vendor, cur_IP, cur_SyncHubNodeName, cur_NetworkNodeMAC, cur_PORT, cur_NetworkSite, cur_SSID, cur_Type FROM CurrentScan").fetchall() current_scan_data = sql.execute("SELECT cur_MAC, cur_Name, cur_Vendor, cur_IP, cur_SyncHubNodeName, cur_NetworkNodeMAC, cur_PORT, cur_NetworkSite, cur_SSID, cur_Type FROM CurrentScan").fetchall()
@@ -210,6 +210,7 @@ def create_new_devices (db):
cur_Type = cur_Type.strip() if cur_Type else get_setting_value("NEWDEV_dev_DeviceType") cur_Type = cur_Type.strip() if cur_Type else get_setting_value("NEWDEV_dev_DeviceType")
cur_NetworkNodeMAC = cur_NetworkNodeMAC.strip() if cur_NetworkNodeMAC else '' cur_NetworkNodeMAC = cur_NetworkNodeMAC.strip() if cur_NetworkNodeMAC else ''
cur_NetworkNodeMAC = cur_NetworkNodeMAC if cur_NetworkNodeMAC and cur_MAC != "Internet" else (get_setting_value("NEWDEV_dev_Network_Node_MAC_ADDR") if cur_MAC != "Internet" else "null") cur_NetworkNodeMAC = cur_NetworkNodeMAC if cur_NetworkNodeMAC and cur_MAC != "Internet" else (get_setting_value("NEWDEV_dev_Network_Node_MAC_ADDR") if cur_MAC != "Internet" else "null")
cur_SyncHubNodeName = cur_SyncHubNodeName if cur_SyncHubNodeName and cur_SyncHubNodeName != "null" else (get_setting_value("SYNC_node_name"))
# Preparing the individual insert statement # Preparing the individual insert statement
sqlQuery = f"""INSERT OR IGNORE INTO Devices sqlQuery = f"""INSERT OR IGNORE INTO Devices
@@ -231,19 +232,19 @@ def create_new_devices (db):
) )
VALUES VALUES
( (
'{cur_MAC}', '{sanitize_SQL_input(cur_MAC)}',
'{cur_Name}', '{sanitize_SQL_input(cur_Name)}',
'{cur_Vendor}', '{sanitize_SQL_input(cur_Vendor)}',
'{cur_IP}', '{sanitize_SQL_input(cur_IP)}',
?, ?,
?, ?,
'{cur_SyncHubNodeName}', '{sanitize_SQL_input(cur_SyncHubNodeName)}',
{sql_generateGuid}, {sql_generateGuid},
'{cur_NetworkNodeMAC}', '{sanitize_SQL_input(cur_NetworkNodeMAC)}',
'{cur_PORT}', '{sanitize_SQL_input(cur_PORT)}',
'{cur_NetworkSite}', '{sanitize_SQL_input(cur_NetworkSite)}',
'{cur_SSID}', '{sanitize_SQL_input(cur_SSID)}',
'{cur_Type}', '{sanitize_SQL_input(cur_Type)}',
{newDevDefaults} {newDevDefaults}
)""" )"""
@@ -637,8 +638,8 @@ icons = {
def guess_icon(vendor, mac, ip, name, default): def guess_icon(vendor, mac, ip, name, default):
result = default result = default
mac = mac.upper() mac = mac.upper()
vendor = vendor.lower() vendor = vendor.lower() if vendor else "unknown"
name = name.lower() name = name.lower() if name else "(unknown)"
# Guess icon based on vendor # Guess icon based on vendor
if any(brand in vendor for brand in {"samsung", "motorola"}): if any(brand in vendor for brand in {"samsung", "motorola"}):
@@ -693,8 +694,8 @@ def guess_icon(vendor, mac, ip, name, default):
def guess_type(vendor, mac, ip, name, default): def guess_type(vendor, mac, ip, name, default):
result = default result = default
mac = mac.upper() mac = mac.upper()
vendor = vendor.lower() vendor = vendor.lower() if vendor else "unknown"
name = name.lower() name = name.lower() if name else "(unknown)"
# Guess icon based on vendor # Guess icon based on vendor
if any(brand in vendor for brand in {"samsung", "motorola"}): if any(brand in vendor for brand in {"samsung", "motorola"}):

View File

@@ -319,7 +319,7 @@ def get_setting_value(key):
set_type = 'Error: Not handled' set_type = 'Error: Not handled'
set_value = 'Error: Not handled' set_value = 'Error: Not handled'
set_value = setting["Value"] # Setting value (Value (upper case) = user overriden default_value) set_value = setting["Value"] # Setting value (Value (upper case) = user overridden default_value)
set_type = setting["Type"] # Setting type # lower case "type" - default json value vs uppper-case "Type" (= from user defined settings) set_type = setting["Type"] # Setting type # lower case "type" - default json value vs uppper-case "Type" (= from user defined settings)
value = setting_value_to_python_type(set_type, set_value) value = setting_value_to_python_type(set_type, set_value)
@@ -806,6 +806,13 @@ def sanitize_string(input):
return input return input
#-------------------------------------------------------------------------------
def sanitize_SQL_input(val):
if val is None:
return ''
return val.replace("'", "_")
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
def generate_mac_links (html, deviceUrl): def generate_mac_links (html, deviceUrl):

View File

@@ -11,13 +11,14 @@ import re
import conf import conf
from const import fullConfPath from const import fullConfPath, applicationPath, fullConfFolder
from helper import collect_lang_strings, updateSubnets, initOrSetParam, isJsonObject, updateState, setting_value_to_python_type from helper import collect_lang_strings, updateSubnets, initOrSetParam, isJsonObject, updateState, setting_value_to_python_type, timeNowTZ, get_setting_value
from logger import mylog from logger import mylog
from api import update_api from api import update_api
from scheduler import schedule_class from scheduler import schedule_class
from plugin import print_plugin_info, run_plugin_scripts from plugin import print_plugin_info, run_plugin_scripts
from plugin_utils import get_plugins_configs, get_plugin_setting_obj from plugin_utils import get_plugins_configs, get_plugin_setting_obj
from notification import write_notification
#=============================================================================== #===============================================================================
# Initialise user defined values # Initialise user defined values
@@ -28,7 +29,8 @@ from plugin_utils import get_plugins_configs, get_plugin_setting_obj
# Check config dictionary # Check config dictionary
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
def ccd(key, default, config_dir, name, inputtype, options, group, events=None, desc="", regex="", setJsonMetadata=None, overrideTemplate=None): # managing application settings, ensuring SQL safety for user input, and updating internal configuration lists
def ccd(key, default, config_dir, name, inputtype, options, group, events=None, desc="", regex="", setJsonMetadata=None, overrideTemplate=None, forceDefault=False, overriddenByEnv=0):
if events is None: if events is None:
events = [] events = []
if setJsonMetadata is None: if setJsonMetadata is None:
@@ -40,7 +42,7 @@ def ccd(key, default, config_dir, name, inputtype, options, group, events=None,
result = default result = default
# Use existing value if already supplied, otherwise default value is used # Use existing value if already supplied, otherwise default value is used
if key in config_dir: if forceDefault == False and key in config_dir:
result = config_dir[key] result = config_dir[key]
# Single quotes might break SQL queries, replacing them # Single quotes might break SQL queries, replacing them
@@ -48,8 +50,8 @@ def ccd(key, default, config_dir, name, inputtype, options, group, events=None,
result = result.replace('\'', "{s-quote}") result = result.replace('\'', "{s-quote}")
# Create the tuples # Create the tuples
sql_safe_tuple = (key, name, desc, str(inputtype), options, regex, str(result), group, str(events)) sql_safe_tuple = (key, name, desc, str(inputtype), options, regex, str(result), group, str(events), overriddenByEnv)
settings_tuple = (key, name, desc, inputtype, options, regex, result, group, str(events)) settings_tuple = (key, name, desc, inputtype, options, regex, result, group, str(events), overriddenByEnv)
# Update or append the tuples in the lists # Update or append the tuples in the lists
conf.mySettingsSQLsafe = update_or_append(conf.mySettingsSQLsafe, sql_safe_tuple, key) conf.mySettingsSQLsafe = update_or_append(conf.mySettingsSQLsafe, sql_safe_tuple, key)
@@ -57,7 +59,7 @@ def ccd(key, default, config_dir, name, inputtype, options, group, events=None,
# Save metadata in dummy setting if not a metadata key # Save metadata in dummy setting if not a metadata key
if '__metadata' not in key: if '__metadata' not in key:
metadata_tuple = (f'{key}__metadata', "metadata name", "metadata desc", '{"dataType":"json", "elements": [{"elementType" : "textarea", "elementOptions" : [{"readonly": "true"}] ,"transformers": []}]}', '[]', "", json.dumps(setJsonMetadata), group, '[]') metadata_tuple = (f'{key}__metadata', "metadata name", "metadata desc", '{"dataType":"json", "elements": [{"elementType" : "textarea", "elementOptions" : [{"readonly": "true"}] ,"transformers": []}]}', '[]', "", json.dumps(setJsonMetadata), group, '[]', overriddenByEnv)
conf.mySettingsSQLsafe = update_or_append(conf.mySettingsSQLsafe, metadata_tuple, f'{key}__metadata') conf.mySettingsSQLsafe = update_or_append(conf.mySettingsSQLsafe, metadata_tuple, f'{key}__metadata')
conf.mySettings = update_or_append(conf.mySettings, metadata_tuple, f'{key}__metadata') conf.mySettings = update_or_append(conf.mySettings, metadata_tuple, f'{key}__metadata')
@@ -69,16 +71,20 @@ def update_or_append(settings_list, item_tuple, key):
if settings_list is None: if settings_list is None:
settings_list = [] settings_list = []
# mylog('debug', ['[Import Config] update_or_append debug '])
# mylog('debug', ['[Import Config] update_or_append ', settings_list])
# mylog('debug', ['[Import Config] update_or_append item_tuple ' , item_tuple])
for index, item in enumerate(settings_list): for index, item in enumerate(settings_list):
if item[0] == key: if item[0] == key:
settings_list[index] = item_tuple mylog('trace', ['[Import Config] OLD TUPLE : ', item])
mylog('debug', ['[Import Config] FOUND key : ', key]) # Keep values marked as "_KEEP_"
return settings_list updated_tuple = tuple(
new_val if new_val != "_KEEP_" else old_val
for old_val, new_val in zip(item, item_tuple)
)
mylog('trace', ['[Import Config] NEW TUPLE : ', updated_tuple])
settings_list[index] = updated_tuple
mylog('trace', ['[Import Config] FOUND key : ', key])
return settings_list
settings_list.append(item_tuple) settings_list.append(item_tuple)
return settings_list return settings_list
@@ -139,17 +145,13 @@ def importConfigs (db, all_plugins):
conf.REPORT_DASHBOARD_URL = ccd('REPORT_DASHBOARD_URL', 'http://netalertx/' , c_d, 'NetAlertX URL', '{"dataType":"string", "elements": [{"elementType" : "input", "elementOptions" : [] ,"transformers": []}]}', '[]', 'General') conf.REPORT_DASHBOARD_URL = ccd('REPORT_DASHBOARD_URL', 'http://netalertx/' , c_d, 'NetAlertX URL', '{"dataType":"string", "elements": [{"elementType" : "input", "elementOptions" : [] ,"transformers": []}]}', '[]', 'General')
conf.DAYS_TO_KEEP_EVENTS = ccd('DAYS_TO_KEEP_EVENTS', 90 , c_d, 'Delete events days', '{"dataType":"integer", "elements": [{"elementType" : "input", "elementOptions" : [{"type": "number"}] ,"transformers": []}]}', '[]', 'General') conf.DAYS_TO_KEEP_EVENTS = ccd('DAYS_TO_KEEP_EVENTS', 90 , c_d, 'Delete events days', '{"dataType":"integer", "elements": [{"elementType" : "input", "elementOptions" : [{"type": "number"}] ,"transformers": []}]}', '[]', 'General')
conf.HRS_TO_KEEP_NEWDEV = ccd('HRS_TO_KEEP_NEWDEV', 0 , c_d, 'Keep new devices for', '{"dataType":"integer", "elements": [{"elementType" : "input", "elementOptions" : [{"type": "number"}] ,"transformers": []}]}', "[]", 'General') conf.HRS_TO_KEEP_NEWDEV = ccd('HRS_TO_KEEP_NEWDEV', 0 , c_d, 'Keep new devices for', '{"dataType":"integer", "elements": [{"elementType" : "input", "elementOptions" : [{"type": "number"}] ,"transformers": []}]}', "[]", 'General')
conf.CLEAR_NEW_FLAG = ccd('CLEAR_NEW_FLAG', 0 , c_d, 'Clear new flag', '{"dataType":"integer", "elements": [{"elementType" : "input", "elementOptions" : [{"type": "number"}] ,"transformers": []}]}', "[]", 'General')
conf.API_CUSTOM_SQL = ccd('API_CUSTOM_SQL', 'SELECT * FROM Devices WHERE dev_PresentLastScan = 0' , c_d, 'Custom endpoint', '{"dataType":"string", "elements": [{"elementType" : "input", "elementOptions" : [] ,"transformers": []}]}', '[]', 'General') conf.API_CUSTOM_SQL = ccd('API_CUSTOM_SQL', 'SELECT * FROM Devices WHERE dev_PresentLastScan = 0' , c_d, 'Custom endpoint', '{"dataType":"string", "elements": [{"elementType" : "input", "elementOptions" : [] ,"transformers": []}]}', '[]', 'General')
conf.NETWORK_DEVICE_TYPES = ccd('NETWORK_DEVICE_TYPES', ['AP', 'Gateway', 'Firewall', 'Hypervisor', 'Powerline', 'Switch', 'WLAN', 'PLC', 'Router','USB LAN Adapter', 'USB WIFI Adapter', 'Internet'] , c_d, 'Network device types', '{"dataType":"array","elements":[{"elementType":"input","elementOptions":[{"placeholder":"Entervalue"},{"suffix":"_in"},{"cssClasses":"col-sm-10"},{"prefillValue":"null"}],"transformers":[]},{"elementType":"button","elementOptions":[{"sourceSuffixes":["_in"]},{"separator":""},{"cssClasses":"col-xs-12"},{"onClick":"addList(this,false)"},{"getStringKey":"Gen_Add"}],"transformers":[]},{"elementType":"select", "elementHasInputValue":1,"elementOptions":[{"multiple":"true"},{"readonly":"true"},{"editable":"true"}],"transformers":[]},{"elementType":"button","elementOptions":[{"sourceSuffixes":[]},{"separator":""},{"cssClasses":"col-xs-6"},{"onClick":"removeAllOptions(this)"},{"getStringKey":"Gen_Remove_All"}],"transformers":[]},{"elementType":"button","elementOptions":[{"sourceSuffixes":[]},{"separator":""},{"cssClasses":"col-xs-6"},{"onClick":"removeFromList(this)"},{"getStringKey":"Gen_Remove_Last"}],"transformers":[]}]}', '[]', 'General') conf.VERSION = ccd('VERSION', '' , c_d, 'Version', '{"dataType":"string", "elements": [{"elementType" : "input", "elementOptions" : [{ "readonly": "true" }] ,"transformers": []}]}', '', 'General')
conf.NETWORK_DEVICE_TYPES = ccd('NETWORK_DEVICE_TYPES', ['AP', 'Gateway', 'Firewall', 'Hypervisor', 'Powerline', 'Switch', 'WLAN', 'PLC', 'Router','USB LAN Adapter', 'USB WIFI Adapter', 'Internet'] , c_d, 'Network device types', '{"dataType":"array","elements":[{"elementType":"input","elementOptions":[{"placeholder":"Enter value"},{"suffix":"_in"},{"cssClasses":"col-sm-10"},{"prefillValue":"null"}],"transformers":[]},{"elementType":"button","elementOptions":[{"sourceSuffixes":["_in"]},{"separator":""},{"cssClasses":"col-xs-12"},{"onClick":"addList(this,false)"},{"getStringKey":"Gen_Add"}],"transformers":[]},{"elementType":"select", "elementHasInputValue":1,"elementOptions":[{"multiple":"true"},{"readonly":"true"},{"editable":"true"}],"transformers":[]},{"elementType":"button","elementOptions":[{"sourceSuffixes":[]},{"separator":""},{"cssClasses":"col-xs-6"},{"onClick":"removeAllOptions(this)"},{"getStringKey":"Gen_Remove_All"}],"transformers":[]},{"elementType":"button","elementOptions":[{"sourceSuffixes":[]},{"separator":""},{"cssClasses":"col-xs-6"},{"onClick":"removeFromList(this)"},{"getStringKey":"Gen_Remove_Last"}],"transformers":[]}]}', '[]', 'General')
# UI # UI
conf.UI_LANG = ccd('UI_LANG', 'English' , c_d, 'Language Interface', '{"dataType":"string", "elements": [{"elementType" : "select", "elementOptions" : [] ,"transformers": []}]}', "['English', 'French', 'German', 'Norwegian', 'Russian', 'Spanish', 'Italian (it_it)', 'Portuguese (pt_br)', 'Polish (pl_pl)', 'Turkish (tr_tr)', 'Chinese (zh_cn)', 'Czech (cs_cz)' ]", 'UI') conf.UI_LANG = ccd('UI_LANG', 'English' , c_d, 'Language Interface', '{"dataType":"string", "elements": [{"elementType" : "select", "elementOptions" : [] ,"transformers": []}]}', "['English', 'French', 'German', 'Norwegian', 'Russian', 'Spanish', 'Italian (it_it)', 'Portuguese (pt_br)', 'Polish (pl_pl)', 'Turkish (tr_tr)', 'Chinese (zh_cn)', 'Czech (cs_cz)' ]", 'UI')
conf.UI_NOT_RANDOM_MAC = ccd('UI_NOT_RANDOM_MAC', [] , c_d, 'Exlude from Random Prefix', '{"dataType": "array","elements": [ {"elementType": "input","elementOptions": [{ "placeholder": "Enter value" },{ "suffix": "_in" },{ "cssClasses": "col-sm-10" },{ "prefillValue": "null" }],"transformers": [] }, {"elementType": "button","elementOptions": [{ "sourceSuffixes": ["_in"] },{ "separator": "" },{ "cssClasses": "col-xs-12" },{ "onClick": "addList(this, false)" },{ "getStringKey": "Gen_Add" }],"transformers": [] }, {"elementType": "button","elementOptions": [{ "sourceSuffixes": [] },{ "separator": "" },{ "cssClasses": "col-xs-6" },{ "onClick": "removeAllOptions(this)" },{ "getStringKey": "Gen_Remove_All" }],"transformers": []},{"elementType": "button","elementOptions": [{ "sourceSuffixes": [] },{ "separator": "" },{ "cssClasses": "col-xs-6" },{ "onClick": "removeFromList(this)" },{ "getStringKey": "Gen_Remove_Last" }],"transformers": []}, {"elementType": "select","elementOptions": [{ "multiple": "true" },{ "readonly": "true" },{ "editable": "true" }],"transformers": [] }]}', "[]", 'UI')
conf.UI_ICONS = ccd('UI_ICONS', ['PGkgY2xhc3M9J2ZhIGZhLXdpZmknPjwvaT4=', 'PGkgY2xhc3M9ImZhIGZhLWNvbXB1dGVyIj48L2k+', 'PGkgY2xhc3M9ImZhIGZhLWV0aGVybmV0Ij48L2k+', 'PGkgY2xhc3M9ImZhIGZhLWdhbWVwYWQiPjwvaT4', 'PGkgY2xhc3M9ImZhIGZhLWdsb2JlIj48L2k+', 'PGkgY2xhc3M9ImZhIGZhLWxhcHRvcCI+PC9pPg==', 'PGkgY2xhc3M9ImZhIGZhLWxpZ2h0YnVsYiI+PC9pPg==', 'PGkgY2xhc3M9ImZhIGZhLXNoaWVsZCI+PC9pPg==', 'PGkgY2xhc3M9ImZhIGZhLXdpZmkiPjwvaT4', 'PGkgY2xhc3M9J2ZhIGZhLWdhbWVwYWQnPjwvaT4'] , c_d, 'Icons', '{"dataType": "array","elements": [ {"elementType": "input","elementOptions": [{ "placeholder": "Enter value" },{ "suffix": "_in" },{ "cssClasses": "col-sm-10" },{ "prefillValue": "null" }],"transformers": [] }, {"elementType": "button","elementOptions": [{ "sourceSuffixes": ["_in"] },{ "separator": "" },{ "cssClasses": "col-xs-12" },{ "onClick": "addList(this, false)" },{ "getStringKey": "Gen_Add" }],"transformers": [] }, {"elementType": "button","elementOptions": [{ "sourceSuffixes": [] },{ "separator": "" },{ "cssClasses": "col-xs-6" },{ "onClick": "removeAllOptions(this)" },{ "getStringKey": "Gen_Remove_All" }],"transformers": []},{"elementType": "button","elementOptions": [{ "sourceSuffixes": [] },{ "separator": "" },{ "cssClasses": "col-xs-6" },{ "onClick": "removeFromList(this)" },{ "getStringKey": "Gen_Remove_Last" }],"transformers": []}, {"elementType": "select","elementOptions": [{ "multiple": "true" },{ "readonly": "true" },{ "editable": "true" }],"transformers": [] }]}', "[]", 'UI')
conf.UI_REFRESH = ccd('UI_REFRESH', 0 , c_d, 'Refresh interval', '{"dataType":"integer", "elements": [{"elementType" : "input", "elementOptions" : [{"type": "number"}] ,"transformers": []}]}', "[]", 'UI')
conf.UI_DEV_SECTIONS = ccd('UI_DEV_SECTIONS', [] , c_d, 'Show sections', '{"dataType":"array", "elements": [{"elementType" : "select", "elementOptions" : [{"multiple":"true"}] ,"transformers": []}]}', "['Tile Cards', 'Device Presence']", 'UI')
conf.UI_PRESENCE = ccd('UI_PRESENCE', ['online', 'offline', 'archived'] , c_d, 'Include in presence', '{"dataType":"array", "elements": [{"elementType" : "select", "elementOptions" : [{"multiple":"true"}] ,"transformers": []}]}', "['online', 'offline', 'archived']", 'UI')
conf.UI_MY_DEVICES = ccd('UI_MY_DEVICES', ['online', 'offline', 'archived', 'new', 'down'] , c_d, 'Include in My Devices', '{"dataType":"array", "elements": [{"elementType" : "select", "elementOptions" : [{"multiple":"true"}] ,"transformers": []}]}', "['online', 'offline', 'archived', 'new', 'down']", 'UI')
# Init timezone in case it changed # Init timezone in case it changed
conf.tz = timezone(conf.TIMEZONE) conf.tz = timezone(conf.TIMEZONE)
@@ -285,8 +287,7 @@ def importConfigs (db, all_plugins):
for plugin in all_plugins: for plugin in all_plugins:
pref = plugin["unique_prefix"] pref = plugin["unique_prefix"]
loaded_plugins_prefixes.append(pref) loaded_plugins_prefixes.append(pref)
# save the newly discovered plugins as options and default values # save the newly discovered plugins as options and default values
conf.LOADED_PLUGINS = ccd('LOADED_PLUGINS', loaded_plugins_prefixes , c_d, 'Loaded plugins', '{"dataType":"array", "elements": [{"elementType" : "select", "elementOptions" : [{"multiple":"true"}] ,"transformers": []}]}', str(sorted(all_plugins_prefixes)), 'General') conf.LOADED_PLUGINS = ccd('LOADED_PLUGINS', loaded_plugins_prefixes , c_d, 'Loaded plugins', '{"dataType":"array", "elements": [{"elementType" : "select", "elementOptions" : [{"multiple":"true"}] ,"transformers": []}]}', str(sorted(all_plugins_prefixes)), 'General')
@@ -296,12 +297,60 @@ def importConfigs (db, all_plugins):
conf.plugins_once_run = False conf.plugins_once_run = False
# ----------------- # -----------------
# Plugins END # Plugins END
# HANDLE APP_CONF_OVERRIDE via app_conf_override.json
# Assuming fullConfFolder is defined elsewhere
app_conf_override_path = fullConfFolder + '/app_conf_override.json'
if os.path.exists(app_conf_override_path):
with open(app_conf_override_path, 'r') as f:
try:
# Load settings_override from the JSON file
settings_override = json.load(f)
# Loop through settings_override dictionary
for setting_name, value in settings_override.items():
# Ensure the value is treated as a string and passed directly
if isinstance(value, str):
# Log the value being passed
# ccd(key, default, config_dir, name, inputtype, options, group, events=None, desc="", regex="", setJsonMetadata=None, overrideTemplate=None, forceDefault=False)
mylog('debug', [f"[Config] Setting override {setting_name} with value: {value}"])
ccd(setting_name, value, c_d, '_KEEP_', '_KEEP_', '_KEEP_', '_KEEP_', None, "_KEEP_", "", None, None, True, 1)
else:
# Convert to string and log
# ccd(key, default, config_dir, name, inputtype, options, group, events=None, desc="", regex="", setJsonMetadata=None, overrideTemplate=None, forceDefault=False)
mylog('debug', [f"[Config] Setting override {setting_name} with value: {str(value)}"])
ccd(setting_name, str(value), c_d, '_KEEP_', '_KEEP_', '_KEEP_', '_KEEP_', None, "_KEEP_", "", None, None, True, 1)
except json.JSONDecodeError:
mylog('none', [f"[Config] [ERROR] Setting override decoding JSON from {app_conf_override_path}"])
else:
mylog('debug', [f"[Config] File {app_conf_override_path} does not exist."])
# Check if app was upgraded
with open(applicationPath + '/front/buildtimestamp.txt', 'r') as f:
buildTimestamp = int(f.read().strip())
cur_version = conf.VERSION
mylog('debug', [f"[Config] buildTimestamp: '{buildTimestamp}'"])
mylog('debug', [f"[Config] conf.VERSION : '{cur_version}'"])
if str(cur_version) != str(buildTimestamp):
mylog('none', ['[Config] App upgraded 🚀'])
# ccd(key, default, config_dir, name, inputtype, options, group, events=None, desc="", regex="", setJsonMetadata=None, overrideTemplate=None, forceDefault=False)
ccd('VERSION', buildTimestamp , c_d, '_KEEP_', '_KEEP_', '_KEEP_', '_KEEP_', None, "_KEEP_", "", None, None, True)
write_notification(f'[Upgrade] : App upgraded 🚀 Please clear the cache: <ol> <li>Click OK below</li> <li>Clear the browser cache (shift + browser refresh button)</li> <li> Clear app cache with the 🔄 (reload) button in the header</li><li>Go to Settings and click Save</li> </ol> Check out new features and what has changed in the <a href="https://github.com/jokob-sk/NetAlertX/releases" target="_blank">📓 release notes</a>.', 'interrupt', timeNowTZ())
# Insert settings into the DB # Insert settings into the DB
sql.execute ("DELETE FROM Settings") sql.execute ("DELETE FROM Settings")
# mylog('debug', [f"[Config] conf.mySettingsSQLsafe : '{conf.mySettingsSQLsafe}'"])
sql.executemany ("""INSERT INTO Settings ("Code_Name", "Display_Name", "Description", "Type", "Options", sql.executemany ("""INSERT INTO Settings ("Code_Name", "Display_Name", "Description", "Type", "Options",
"RegEx", "Value", "Group", "Events" ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)""", conf.mySettingsSQLsafe) "RegEx", "Value", "Group", "Events", "OverriddenByEnv" ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""", conf.mySettingsSQLsafe)
db.commitDB() db.commitDB()

View File

@@ -248,7 +248,11 @@ def execute_plugin(db, all_plugins, plugin, pluginsState = plugins_state() ):
for line in newLines: for line in newLines:
columns = line.split("|") columns = line.split("|")
# There have to be 9 or 13 columns # There have to be 9 or 13 columns
if len(columns) not in [9, 13]:
mylog('none', [f'[Plugins] Wrong number of input values, must be 9 or 13, got {len(columns)} from: {line}'])
continue # Skip lines with incorrect number of columns
# Common part of the SQL parameters # Common part of the SQL parameters
base_params = [ base_params = [
0, # "Index" placeholder 0, # "Index" placeholder
@@ -284,8 +288,6 @@ def execute_plugin(db, all_plugins, plugin, pluginsState = plugins_state() ):
'null', # "HelpVal3" 'null', # "HelpVal3"
'null' # "HelpVal4" 'null' # "HelpVal4"
]) ])
else:
mylog('none', [f'[Plugins] Wrong number of input values, must be 9 or 13, got {len(columns)} from: {line} '])
# Create a tuple containing values to be inserted into the database. # Create a tuple containing values to be inserted into the database.
# Each value corresponds to a column in the table in the order of the columns. # Each value corresponds to a column in the table in the order of the columns.