Merge branch 'main' of https://github.com/netalertx/NetAlertX into agentic-workflows
# Please enter a commit message to explain why this merge is necessary, # especially if it merges an updated upstream into a topic branch. # # Lines starting with '#' will be ignored, and an empty message aborts # the commit.
@@ -157,6 +157,8 @@ Check the [GitHub Issues](https://github.com/netalertx/NetAlertX/issues) for the
|
||||
## Everything else
|
||||
<!--- --------------------------------------------------------------------- --->
|
||||
|
||||
<a href="https://trendshift.io/repositories/12670" target="_blank"><img src="https://trendshift.io/api/badge/repositories/12670" alt="jokob-sk%2FNetAlertX | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
|
||||
|
||||
### 📧 Get notified what's new
|
||||
|
||||
Get notified about a new release, what new functionality you can use and about breaking changes.
|
||||
@@ -219,7 +221,7 @@ Proudly using [Weblate](https://hosted.weblate.org/projects/pialert/). Help out
|
||||
[sync_hub]: ./docs/img/sync_hub.png "Screen 8"
|
||||
[notification_center]: ./docs/img/notification_center.png "Screen 8"
|
||||
[sent_reports_text]: ./docs/img/sent_reports_text.png "Screen 8"
|
||||
[device_nmap]: ./docs/img/device_nmap.png "Screen 9"
|
||||
[device_nmap]: ./docs/img/device_tools.png "Screen 9"
|
||||
[report1]: ./docs/img/report_sample.png "Report sample 1"
|
||||
[main_dark]: /docs/img/1_devices_dark.jpg "Main screen dark"
|
||||
[maintain_dark]: /docs/img/5_maintain.jpg "Maintain screen dark"
|
||||
|
||||
@@ -59,6 +59,10 @@ http://<server>:<GRAPHQL_PORT>/
|
||||
|
||||
## Endpoints
|
||||
|
||||
> [!NOTE]
|
||||
> You can explore the API endpoints by using the interactive API docs at `http://<server>:<GRAPHQL_PORT>/docs`.
|
||||
> 
|
||||
|
||||
> [!TIP]
|
||||
> When retrieving devices or settings try using the GraphQL API endpoint first as it is read-optimized.
|
||||
|
||||
|
||||
@@ -31,11 +31,6 @@ graph TB
|
||||
D -->|Response Data| C
|
||||
C -->|JSON Response| B
|
||||
B -->|Stream Events| A
|
||||
|
||||
style A fill:#e1f5fe
|
||||
style B fill:#f3e5f5
|
||||
style C fill:#fff3e0
|
||||
style D fill:#e8f5e8
|
||||
```
|
||||
|
||||
### MCP Tool Integration
|
||||
@@ -98,15 +93,6 @@ graph LR
|
||||
F --> I
|
||||
G --> J
|
||||
H --> I
|
||||
|
||||
style A fill:#e1f5fe
|
||||
style B fill:#e1f5fe
|
||||
style C fill:#f3e5f5
|
||||
style D fill:#f3e5f5
|
||||
style E fill:#f3e5f5
|
||||
style F fill:#fff3e0
|
||||
style G fill:#fff3e0
|
||||
style H fill:#fff3e0
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -6,7 +6,7 @@ NetAlertX is a lightweight, flexible platform for monitoring networks, tracking
|
||||
|
||||
## Network Discovery & Device Tracking
|
||||
|
||||
[Network Discovery & Device Tracking](./img/FEATURES/Network_Discovery_Device_Tracking.png)
|
||||

|
||||
|
||||
- **Automatic Device Detection**: Continuously scans your local network to detect all connected devices via ARP, DHCP, SNMP, and compatible controllers.
|
||||
- **Presence Monitoring**: Track when devices appear, disappear, or reconnect on the network.
|
||||
|
||||
BIN
docs/img/API/API_docs.png
Normal file
|
After Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 262 KiB After Width: | Height: | Size: 107 KiB |
|
Before Width: | Height: | Size: 173 KiB |
BIN
docs/img/device_tools.png
Normal file
|
After Width: | Height: | Size: 190 KiB |
|
Before Width: | Height: | Size: 210 KiB After Width: | Height: | Size: 446 KiB |
|
Before Width: | Height: | Size: 146 KiB After Width: | Height: | Size: 203 KiB |
|
Before Width: | Height: | Size: 216 KiB After Width: | Height: | Size: 328 KiB |
|
Before Width: | Height: | Size: 202 KiB After Width: | Height: | Size: 97 KiB |
|
Before Width: | Height: | Size: 84 KiB After Width: | Height: | Size: 156 KiB |
@@ -4,10 +4,21 @@ hide:
|
||||
- toc
|
||||
---
|
||||
|
||||
# NetAlertX Documentation
|
||||
|
||||
Guides and resources to help you set up, configure, and troubleshoot NetAlertX.
|
||||
|
||||
<div class="hero-wrapper">
|
||||
<div class="hero-content">
|
||||
<h1>NetAlertX</h1>
|
||||
<p class="hero-subheading">
|
||||
Centralized network visibility and continuous asset discovery.
|
||||
</p>
|
||||
<p class="hero-description">
|
||||
NetAlertx delivers a scalable and secure solution for comprehensive network monitoring, supporting security awareness and operational efficiency.
|
||||
</p>
|
||||
</div>
|
||||
<div class="hero-image">
|
||||
<img src="./img/devices_split.png" alt="Hero image for NetAlertx" class="hero-logo-crisp">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="promo-card-wrapper">
|
||||
<div class="promo-card">
|
||||
@@ -43,48 +54,6 @@ Guides and resources to help you set up, configure, and troubleshoot NetAlertX.
|
||||
</div>
|
||||
</div>
|
||||
|
||||

|
||||
|
||||
## In-App Help
|
||||
|
||||
NetAlertX provides contextual help within the application:
|
||||
|
||||
- **Hover over settings, fields, or labels** to see additional tooltips and guidance.
|
||||
- **Click ? (question-mark) icons** next to various elements to view detailed information.
|
||||
|
||||
---
|
||||
|
||||
## Installation Guides
|
||||
|
||||
The app can be installed different ways, with the best support of the docker-based deployments. This includes the Home Assistant and Unraid installation approaches. See details below.
|
||||
|
||||
### Docker (Fully Supported)
|
||||
|
||||
NetAlertX is fully supported in Docker environments, allowing for easy setup and configuration. Follow the official guide to get started:
|
||||
|
||||
- [Docker Installation Guide](./DOCKER_INSTALLATION.md)
|
||||
|
||||
This guide will take you through the process of setting up NetAlertX using Docker Compose or standalone Docker commands.
|
||||
|
||||
### Home Assistant (Fully Supported)
|
||||
|
||||
You can install NetAlertX also as a Home Assistant addon [](https://my.home-assistant.io/redirect/supervisor_add_addon_repository/?repository_url=https%3A%2F%2Fgithub.com%2Falexbelgium%2Fhassio-addons) via the [alexbelgium/hassio-addons](https://github.com/alexbelgium/hassio-addons/) repository. This is only possible if you run a supervised instance of Home Assistant. If not, you can still run NetAlertX in a separate Docker container and follow this guide to configure MQTT.
|
||||
|
||||
- [[Installation] Home Assistant](https://github.com/alexbelgium/hassio-addons/tree/master/netalertx)
|
||||
|
||||
### Unraid (Partial Support)
|
||||
|
||||
The Unraid template was created by the community, so it's only partially supported. Alternatively, here is [another version of the Unraid template](https://github.com/jokob-sk/NetAlertX-unraid).
|
||||
|
||||
- [[Installation] Unraid App](https://unraid.net/community/apps)
|
||||
|
||||
### Bare-Metal Installation (Experimental)
|
||||
|
||||
If you prefer to run NetAlertX on your own hardware, you can try the experimental bare-metal installation. Please note that this method is still under development, and are looking for maintainers to help improve it.
|
||||
|
||||
- [Bare-Metal Installation Guide](./HW_INSTALL.md)
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Help and Support
|
||||
@@ -93,14 +62,16 @@ If you need help or run into issues, here are some resources to guide you:
|
||||
|
||||
**Before opening an issue, please:**
|
||||
|
||||
- **Hover over settings, fields, or labels** to see additional tooltips and guidance.
|
||||
- **Click ? (question-mark) icons** next to various elements to view detailed information.
|
||||
- [Check common issues](./DEBUG_TIPS.md#common-issues) to see if your problem has already been reported.
|
||||
- [Look at closed issues](https://github.com/jokob-sk/NetAlertX/issues?q=is%3Aissue+is%3Aclosed) for possible solutions to past problems.
|
||||
- [Look at closed issues](https://github.com/netalertx/NetAlertX/issues?q=is%3Aissue+is%3Aclosed) for possible solutions to past problems.
|
||||
- **Enable debugging** to gather more information: [Debug Guide](./DEBUG_TIPS.md).
|
||||
|
||||
**Need more help?** Join the community discussions or submit a support request:
|
||||
|
||||
- Visit the [GitHub Discussions](https://github.com/jokob-sk/NetAlertX/discussions) for community support.
|
||||
- If you are experiencing issues that require immediate attention, consider opening an issue on our [GitHub Issues page](https://github.com/jokob-sk/NetAlertX/issues).
|
||||
- Visit the [GitHub Discussions](https://github.com/netalertx/NetAlertX/discussions) for community support.
|
||||
- If you are experiencing issues that require immediate attention, consider opening an issue on our [GitHub Issues page](https://github.com/netalertx/NetAlertX/issues).
|
||||
|
||||
---
|
||||
|
||||
@@ -119,15 +90,15 @@ For more information on contributing, check out our [Dev Guide](./DEV_ENV_SETUP.
|
||||
|
||||
To keep up with the latest changes and updates to NetAlertX, please refer to the following resources:
|
||||
|
||||
- [Releases](https://github.com/jokob-sk/NetAlertX/releases)
|
||||
- [Releases](https://github.com/netalertx/NetAlertX/releases)
|
||||
|
||||
Make sure to follow the project on GitHub to get notifications for new releases and important updates.
|
||||
|
||||
---
|
||||
## Additional info
|
||||
|
||||
- **Documentation Index**: Check out the full [documentation index](https://github.com/jokob-sk/NetAlertX/tree/main/docs) for all the guides available.
|
||||
- **Documentation Index**: Check out the full [documentation index](https://github.com/netalertx/NetAlertX/tree/main/docs) for all the guides available.
|
||||
|
||||
If you have any suggestions or improvements, please don’t hesitate to contribute!
|
||||
|
||||
NetAlertX is actively maintained. You can find the source code, report bugs, or request new features on our [GitHub page](https://github.com/jokob-sk/NetAlertX).
|
||||
NetAlertX is actively maintained. You can find the source code, report bugs, or request new features on our [GitHub page](https://github.com/netalertx/NetAlertX).
|
||||
|
||||
@@ -14,6 +14,53 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
/* --- HERO SECTION --- */
|
||||
.hero-wrapper {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.hero-content {
|
||||
flex: 1;
|
||||
max-width: 26.8rem;
|
||||
}
|
||||
|
||||
.hero-content h1 {
|
||||
font-size: 3rem;
|
||||
line-height: 1.12;
|
||||
font-weight: 450;
|
||||
margin-bottom: 0.5rem;
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
|
||||
p.hero-subheading {
|
||||
font-size: 1.5rem;
|
||||
line-height: 1.28;
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
p.hero-description {
|
||||
line-height: 1.4;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.hero-image {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 15px;
|
||||
max-width: 45%;
|
||||
}
|
||||
|
||||
.hero-logo-crisp {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
/* --- PROMO CARDS --- */
|
||||
.promo-card-wrapper {
|
||||
display: flex;
|
||||
|
||||
@@ -508,6 +508,41 @@ body
|
||||
color: #a0a0a0;
|
||||
}
|
||||
|
||||
.small-box {
|
||||
margin-bottom: 15px !important;
|
||||
float: left;
|
||||
width: 100%;
|
||||
}
|
||||
#TopSmallBoxes .small-box {
|
||||
height: 3em;
|
||||
}
|
||||
|
||||
.small-box .icon
|
||||
{
|
||||
font-size: 2.2em !important;
|
||||
float: right;
|
||||
top: 0;
|
||||
}
|
||||
.small-box .small-box-text
|
||||
{
|
||||
float:left;
|
||||
font-size: x-large;
|
||||
margin-top: -0.3em;
|
||||
}
|
||||
|
||||
.small-box .infobox_label
|
||||
{
|
||||
font-size: larger;
|
||||
float: right;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
hr
|
||||
{
|
||||
margin-top: 5px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
Customized Box Borders
|
||||
----------------------------------------------------------------------------- */
|
||||
@@ -901,10 +936,6 @@ height: 50px;
|
||||
background-color: #b2b6be !important;
|
||||
}
|
||||
|
||||
.infobox_label {
|
||||
font-size: 16px !important;
|
||||
}
|
||||
|
||||
.deviceSelector
|
||||
{
|
||||
display: block;
|
||||
@@ -1667,6 +1698,10 @@ textarea[readonly],
|
||||
min-height: 42px;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 5px !important;
|
||||
}
|
||||
|
||||
/* Remove the default Select2 chevron (the down arrow) */
|
||||
.select2-container .select2-selection__arrow b {
|
||||
display: none !important;
|
||||
|
||||
@@ -172,6 +172,15 @@ function getDeviceData() {
|
||||
labelClasses: "col-sm-4 col-xs-12 control-label",
|
||||
inputClasses: "col-sm-8 col-xs-12 input-group"
|
||||
},
|
||||
// Group for Custom properties.
|
||||
DevDetail_CustomProperties_Title: {
|
||||
data: ["devCustomProps"],
|
||||
docs: "https://docs.netalertx.com/CUSTOM_PROPERTIES",
|
||||
iconClass: "fa fa-list",
|
||||
inputGroupClasses: "field-group cutprop-group col-lg-6 col-sm-12 col-xs-12",
|
||||
labelClasses: "col-sm-12 col-xs-12 control-label",
|
||||
inputClasses: "col-sm-12 col-xs-12 input-group"
|
||||
},
|
||||
// Group for Children.
|
||||
DevDetail_Children_Title: {
|
||||
data: ["devChildrenDynamic"],
|
||||
@@ -181,15 +190,6 @@ function getDeviceData() {
|
||||
labelClasses: "col-sm-12 col-xs-12 control-label",
|
||||
inputClasses: "col-sm-12 col-xs-12 input-group"
|
||||
},
|
||||
// Group for Custom properties.
|
||||
DevDetail_CustomProperties_Title: {
|
||||
data: ["devCustomProps"],
|
||||
docs: "https://docs.netalertx.com/CUSTOM_PROPERTIES",
|
||||
iconClass: "fa fa-list",
|
||||
inputGroupClasses: "field-group cutprop-group col-lg-6 col-sm-12 col-xs-12",
|
||||
labelClasses: "col-sm-12 col-xs-12 control-label",
|
||||
inputClasses: "col-sm-12 col-xs-12 input-group"
|
||||
}
|
||||
};
|
||||
|
||||
// Filter settings data to get relevant settings
|
||||
|
||||
@@ -450,10 +450,18 @@ function localizeTimestamp(input) {
|
||||
const date = new Date(str);
|
||||
if (!isFinite(date)) {
|
||||
console.error(`ERROR: Couldn't parse date: '${str}' with TIMEZONE ${tz}`);
|
||||
return 'Failed conversion - Check browser console';
|
||||
return 'Failed conversion';
|
||||
}
|
||||
|
||||
// CHECK: Does the input string have an offset (e.g., +11:00 or Z)?
|
||||
// If it does, and we apply a 'tz' again, we double-shift.
|
||||
const hasOffset = /[Z|[+-]\d{2}:?\d{2}]$/.test(str.trim());
|
||||
|
||||
return new Intl.DateTimeFormat(LOCALE, {
|
||||
timeZone: tz,
|
||||
// If it has an offset, we display it as-is (UTC mode in Intl
|
||||
// effectively means "don't add more hours").
|
||||
// If no offset, apply your variable 'tz'.
|
||||
timeZone: hasOffset ? 'UTC' : tz,
|
||||
year: 'numeric', month: '2-digit', day: '2-digit',
|
||||
hour: '2-digit', minute: '2-digit', second: '2-digit',
|
||||
hour12: false
|
||||
|
||||
@@ -23,10 +23,19 @@ class NetAlertXStateManager {
|
||||
*/
|
||||
init() {
|
||||
if (this.initialized) return;
|
||||
// waiting until cache ready
|
||||
const waitForInit = () => {
|
||||
if (!isAppInitialized()) {
|
||||
setTimeout(waitForInit, 300);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("[NetAlertX State] Initializing state manager...");
|
||||
this.trySSE();
|
||||
this.initialized = true;
|
||||
console.log("[NetAlertX State] App initialized, starting state manager");
|
||||
this.trySSE();
|
||||
this.initialized = true;
|
||||
};
|
||||
|
||||
waitForInit();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -478,9 +478,14 @@ function deleteEvents30()
|
||||
function askUnlockFields () {
|
||||
// Ask
|
||||
showModalWarning('<?= lang('Maintenance_Tool_UnlockFields_noti');?>', '<?= lang('Maintenance_Tool_UnlockFields_noti_text');?>',
|
||||
'<?= lang('Gen_Cancel');?>', '<?= lang('Gen_Delete');?>', 'unlockFields');
|
||||
'<?= lang('Gen_Cancel');?>', '<?= lang('Gen_Delete');?>', () => unlockFields(true));
|
||||
}
|
||||
function unlockFields() {
|
||||
function unlockFields(clearAllFields) {
|
||||
|
||||
|
||||
console.log("clearAllFields");
|
||||
console.log(clearAllFields);
|
||||
|
||||
const apiBase = getApiBase();
|
||||
const apiToken = getSetting("API_TOKEN");
|
||||
const url = `${apiBase}/devices/fields/unlock`;
|
||||
@@ -489,7 +494,7 @@ function unlockFields() {
|
||||
const payload = {
|
||||
mac: null, // null = all devices
|
||||
fields: null, // null = all tracked fields
|
||||
clearAll: true // clear all source values
|
||||
clearAll: clearAllFields // clear all source values
|
||||
};
|
||||
|
||||
$.ajax({
|
||||
|
||||
@@ -70,6 +70,12 @@
|
||||
</div>
|
||||
<div class="col-md-10"><?= lang('Maintenance_Tool_del_unlockFields_selecteddev_text');?></div>
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<div class="col-md-2" style="">
|
||||
<button type="button" class="btn btn-default pa-btn pa-btn-delete bg-red" id="btnClearSourceFields" onclick="askClearSourceFields()"><?= lang('Maintenance_Tool_clearSourceFields_selected');?></button>
|
||||
</div>
|
||||
<div class="col-md-10"><?= lang('Maintenance_Tool_clearSourceFields_selected_text');?></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -436,6 +442,18 @@ function askUnlockFieldsSelected () {
|
||||
'unlockFieldsSelected');
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Ask to unlock fields of selected devices
|
||||
function askClearSourceFields () {
|
||||
// Ask
|
||||
showModalWarning(
|
||||
getString('Maintenance_Tool_clearSourceFields_selected_noti'),
|
||||
getString('Gen_AreYouSure'),
|
||||
getString('Gen_Cancel'),
|
||||
getString('Gen_Okay'),
|
||||
()=>unlockFieldsSelected(null, true));
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Unlock fields for selected devices
|
||||
function unlockFieldsSelected(fields = null, clearAll = false) {
|
||||
@@ -443,6 +461,7 @@ function unlockFieldsSelected(fields = null, clearAll = false) {
|
||||
const macs_tmp = selectorMacs(); // returns array of MACs
|
||||
|
||||
console.log(macs_tmp);
|
||||
console.log(clearAll);
|
||||
|
||||
|
||||
if (!macs_tmp || macs_tmp == "" || macs_tmp.length === 0) {
|
||||
@@ -461,7 +480,7 @@ function unlockFieldsSelected(fields = null, clearAll = false) {
|
||||
const payload = {
|
||||
mac: macsArray, // array of MACs for backend
|
||||
fields: fields, // null for all tracked fields
|
||||
clear_all: clearAll // true to clear all sources, false to clear only LOCKED/USER
|
||||
clearAll: clearAll // true to clear all sources, false to clear only LOCKED/USER
|
||||
};
|
||||
|
||||
$.ajax({
|
||||
|
||||
@@ -21,8 +21,10 @@ function renderSmallBox($params) {
|
||||
<a href="#" onclick="javascript: ' . htmlspecialchars($onclickEvent) . '">
|
||||
<div class="small-box ' . htmlspecialchars($color) . '">
|
||||
<div class="inner">
|
||||
<h3 id="' . htmlspecialchars($headerId) . '" style="' . htmlspecialchars($headerStyle) . '"> ' . htmlspecialchars($dataValue) . ' </h3>
|
||||
<p class="infobox_label">' . lang(htmlspecialchars($labelLang)) . '</p>
|
||||
<div class="col-lg-6 col-sm-6 col-xs-6">
|
||||
<div class="small-box-text col-lg-12 col-sm-12 col-xs-12" id="' . htmlspecialchars($headerId) . '" style="' . htmlspecialchars($headerStyle) . '"> <b>' . htmlspecialchars($dataValue) . '</b> </div>
|
||||
</div>
|
||||
<div class="infobox_label col-lg-6 col-sm-6 col-xs-6">' . lang(htmlspecialchars($labelLang)) . '</div>
|
||||
</div>
|
||||
<div class="icon">
|
||||
<i id="' . htmlspecialchars($iconId) . '" class="' . htmlspecialchars($iconClass) . '"></i>
|
||||
|
||||
@@ -427,6 +427,9 @@
|
||||
"Maintenance_Tool_backup_noti_text": "جاري إنشاء نسخة احتياطية...",
|
||||
"Maintenance_Tool_backup_text": "إنشاء نسخة احتياطية من قاعدة البيانات",
|
||||
"Maintenance_Tool_check_visible": "فحص المرئي",
|
||||
"Maintenance_Tool_clearSourceFields_selected": "",
|
||||
"Maintenance_Tool_clearSourceFields_selected_noti": "",
|
||||
"Maintenance_Tool_clearSourceFields_selected_text": "",
|
||||
"Maintenance_Tool_darkmode": "الوضع الداكن",
|
||||
"Maintenance_Tool_darkmode_noti": "الوضع الداكن",
|
||||
"Maintenance_Tool_darkmode_noti_text": "تم تغيير الوضع الداكن",
|
||||
@@ -786,4 +789,4 @@
|
||||
"settings_system_label": "نظام",
|
||||
"settings_update_item_warning": "قم بتحديث القيمة أدناه. احرص على اتباع التنسيق السابق. <b>لم يتم إجراء التحقق.</b>",
|
||||
"test_event_tooltip": "احفظ التغييرات أولاً قبل اختبار الإعدادات."
|
||||
}
|
||||
}
|
||||
@@ -427,6 +427,9 @@
|
||||
"Maintenance_Tool_backup_noti_text": "Estàs segur que vols executar el Backup DB? Assegura't que no hi ha exploració en funcionament.",
|
||||
"Maintenance_Tool_backup_text": "Les còpies de seguretat de la base de dades es troben al directori de bases de dades com a arxiu zip, anomenat amb la data de creació. No hi ha un nombre màxim de còpies de seguretat.",
|
||||
"Maintenance_Tool_check_visible": "Desmarqueu-ho per amagar la columna.",
|
||||
"Maintenance_Tool_clearSourceFields_selected": "",
|
||||
"Maintenance_Tool_clearSourceFields_selected_noti": "",
|
||||
"Maintenance_Tool_clearSourceFields_selected_text": "",
|
||||
"Maintenance_Tool_darkmode": "Canvia Modes (Fosc/Clar)",
|
||||
"Maintenance_Tool_darkmode_noti": "Canvia Modes",
|
||||
"Maintenance_Tool_darkmode_noti_text": "Després del canvi de tema, la pàgina intenta recarregar-se per activar el canvi. Si és necessari, s'ha de netejar la memòria cau.",
|
||||
|
||||
@@ -427,6 +427,9 @@
|
||||
"Maintenance_Tool_backup_noti_text": "",
|
||||
"Maintenance_Tool_backup_text": "",
|
||||
"Maintenance_Tool_check_visible": "",
|
||||
"Maintenance_Tool_clearSourceFields_selected": "",
|
||||
"Maintenance_Tool_clearSourceFields_selected_noti": "",
|
||||
"Maintenance_Tool_clearSourceFields_selected_text": "",
|
||||
"Maintenance_Tool_darkmode": "",
|
||||
"Maintenance_Tool_darkmode_noti": "",
|
||||
"Maintenance_Tool_darkmode_noti_text": "",
|
||||
|
||||
@@ -84,12 +84,12 @@
|
||||
"DevDetail_EveandAl_NewDevice": "Neues Gerät",
|
||||
"DevDetail_EveandAl_NewDevice_Tooltip": "Zeigt den Status „Neu“ für das Gerät an und nimmt es in Listen auf, wenn der Filter „Neue Geräte“ aktiv ist. Hat keine Auswirkungen auf Benachrichtigungen.",
|
||||
"DevDetail_EveandAl_RandomMAC": "Zufällige MAC",
|
||||
"DevDetail_EveandAl_ScanCycle": "Scan Abstand",
|
||||
"DevDetail_EveandAl_ScanCycle": "Gerät scannen",
|
||||
"DevDetail_EveandAl_ScanCycle_a": "Gerät scannen",
|
||||
"DevDetail_EveandAl_ScanCycle_z": "Gerät nicht scannen",
|
||||
"DevDetail_EveandAl_Skip": "pausiere wiederhol. Meldungen für",
|
||||
"DevDetail_EveandAl_Skip": "Keine wiederholten Benachrichtigungen für",
|
||||
"DevDetail_EveandAl_Title": "Konfiguration der Benachrichtigungen",
|
||||
"DevDetail_Events_CheckBox": "Blende Verbindungs-Ereignisse aus",
|
||||
"DevDetail_Events_CheckBox": "Verbindungsereignisse ausblenden",
|
||||
"DevDetail_GoToNetworkNode": "Zur Netzwerkseite des angegebenen Knotens navigieren.",
|
||||
"DevDetail_Icon": "Icon",
|
||||
"DevDetail_Icon_Descr": "Geben Sie einen Font Awesome Icon-Namen ohne das Präfix „fa-“ ein oder die vollständige Klasse, z. B.: fa fa-brands fa-apple.",
|
||||
@@ -102,10 +102,10 @@
|
||||
"DevDetail_MainInfo_Network": "<i class=\"fa fa-server\"></i> Knoten (MAC)",
|
||||
"DevDetail_MainInfo_Network_Port": "<i class=\"fa fa-ethernet\"></i> Port",
|
||||
"DevDetail_MainInfo_Network_Site": "Seite",
|
||||
"DevDetail_MainInfo_Network_Title": "Network",
|
||||
"DevDetail_MainInfo_Network_Title": "Netzwerkdetails",
|
||||
"DevDetail_MainInfo_Owner": "Eigen­tümer",
|
||||
"DevDetail_MainInfo_SSID": "SSID",
|
||||
"DevDetail_MainInfo_Title": "Hauptinformation",
|
||||
"DevDetail_MainInfo_Title": "Geräteinformationen",
|
||||
"DevDetail_MainInfo_Type": "Typ",
|
||||
"DevDetail_MainInfo_Vendor": "Hersteller",
|
||||
"DevDetail_MainInfo_mac": "MAC",
|
||||
@@ -209,7 +209,7 @@
|
||||
"Device_MultiEdit_Tooltip": "Achtung! Beim Drücken werden alle Werte auf die oben ausgewählten Geräte übertragen.",
|
||||
"Device_Save_Failed": "",
|
||||
"Device_Save_Unauthorized": "",
|
||||
"Device_Saved_Success": "",
|
||||
"Device_Saved_Success": "Gerät erfolgreich gespeichert",
|
||||
"Device_Saved_Unexpected": "",
|
||||
"Device_Searchbox": "Suche",
|
||||
"Device_Shortcut_AllDevices": "Meine Geräte",
|
||||
@@ -255,7 +255,7 @@
|
||||
"Device_TableHead_SyncHubNodeName": "Synchronisationsknoten",
|
||||
"Device_TableHead_Type": "Typ",
|
||||
"Device_TableHead_Vendor": "Hersteller",
|
||||
"Device_TableHead_Vlan": "",
|
||||
"Device_TableHead_Vlan": "VLAN",
|
||||
"Device_Table_Not_Network_Device": "Nicht konfiguriert als Netzwerkgerät",
|
||||
"Device_Table_info": "Zeige _START_ bis _END_ von _TOTAL_ Einträgen",
|
||||
"Device_Table_nav_next": "Nächste",
|
||||
@@ -445,6 +445,9 @@
|
||||
"Maintenance_Tool_backup_noti_text": "Sind Sie sicher, dass Sie die Datenbank jetzt sichern möchten. Prüfen Sie, dass gerade keine Scans stattfinden.",
|
||||
"Maintenance_Tool_backup_text": "Die Datenbank-Sicher­ungen befinden sich im Datenbank-Ver­zeich­nis, gepackt als zip-Archive, benannt mit dem Erstellungs­datum. Es gibt keine maximale Anzahl von Backups.",
|
||||
"Maintenance_Tool_check_visible": "Abwählen um die Spalte auszublenden.",
|
||||
"Maintenance_Tool_clearSourceFields_selected": "",
|
||||
"Maintenance_Tool_clearSourceFields_selected_noti": "",
|
||||
"Maintenance_Tool_clearSourceFields_selected_text": "",
|
||||
"Maintenance_Tool_darkmode": "Darstellungswechsel (Dunkel/Hell)",
|
||||
"Maintenance_Tool_darkmode_noti": "Darstellungswechsel",
|
||||
"Maintenance_Tool_darkmode_noti_text": "Wechselt zwischen der hellen und der dunklen Darstellung. Wenn die Umschaltung nicht ordentlich funktionieren sollte, versuchen Sie den Browsercache zu löschen.",
|
||||
|
||||
@@ -414,8 +414,8 @@
|
||||
"Maintenance_Tool_ImportPastedConfig": "Settings Import (paste)",
|
||||
"Maintenance_Tool_ImportPastedConfig_noti_text": "Are you sure you want to import the pasted config settings? This will completely <b>overwrite</b> the <code>app.conf</code> file.",
|
||||
"Maintenance_Tool_ImportPastedConfig_text": "Imports the <code>app.conf</code> file containing all the application Settings. You might want to download the current <code>app.conf</code> file first with the <b>Settings Export</b>.",
|
||||
"Maintenance_Tool_UnlockFields": "Clear All Device Sources",
|
||||
"Maintenance_Tool_UnlockFields_noti": "Clear All Device Sources",
|
||||
"Maintenance_Tool_UnlockFields": "Unlock Device Fields",
|
||||
"Maintenance_Tool_UnlockFields_noti": "Unlock Device Fields",
|
||||
"Maintenance_Tool_UnlockFields_noti_text": "Are you sure you want to clear all source values (LOCKED/USER) for all device fields on all devices? This action cannot be undone.",
|
||||
"Maintenance_Tool_UnlockFields_text": "This tool will remove all source values from every tracked field for all devices, effectively unlocking all fields for plugins and users. Use this with caution, as it will affect your entire device inventory.",
|
||||
"Maintenance_Tool_arpscansw": "Toggle arp-Scan (on/off)",
|
||||
@@ -427,6 +427,9 @@
|
||||
"Maintenance_Tool_backup_noti_text": "Are you sure you want to execute the DB Backup? Be sure that no scan is currently running.",
|
||||
"Maintenance_Tool_backup_text": "The database backups are located in the database directory as a zip-archive, named with the creation date. There is no maximum number of backups.",
|
||||
"Maintenance_Tool_check_visible": "Uncheck to hide column.",
|
||||
"Maintenance_Tool_clearSourceFields_selected": "Clear source fields",
|
||||
"Maintenance_Tool_clearSourceFields_selected_noti": "Clear sources",
|
||||
"Maintenance_Tool_clearSourceFields_selected_text": "This will clear all source fields of the selected devices. This action cannot be undone.",
|
||||
"Maintenance_Tool_darkmode": "Toggle Modes (Dark/Light)",
|
||||
"Maintenance_Tool_darkmode_noti": "Toggle Modes",
|
||||
"Maintenance_Tool_darkmode_noti_text": "After the theme switch, the page tries to reload itself to activate the change. If necessary, the cache must be cleared.",
|
||||
|
||||
@@ -443,6 +443,9 @@
|
||||
"Maintenance_Tool_backup_noti_text": "¿Estás seguro de que quieres exactos la copia de seguridad de DB? Asegúrese de que ningún escaneo se esté ejecutando actualmente.",
|
||||
"Maintenance_Tool_backup_text": "Las copias de seguridad de la base de datos se encuentran en el directorio de la base de datos como una Zip-Archive, nombrada con la fecha de creación. No hay un número máximo de copias de seguridad.",
|
||||
"Maintenance_Tool_check_visible": "Desactivar para ocultar columna.",
|
||||
"Maintenance_Tool_clearSourceFields_selected": "",
|
||||
"Maintenance_Tool_clearSourceFields_selected_noti": "",
|
||||
"Maintenance_Tool_clearSourceFields_selected_text": "",
|
||||
"Maintenance_Tool_darkmode": "Cambiar Modo (Dark/Light)",
|
||||
"Maintenance_Tool_darkmode_noti": "Cambiar Modo",
|
||||
"Maintenance_Tool_darkmode_noti_text": "Después del cambio de tema, la página intenta volver a cargar para activar el cambio. Si es necesario, el caché debe ser eliminado.",
|
||||
|
||||
@@ -427,6 +427,9 @@
|
||||
"Maintenance_Tool_backup_noti_text": "",
|
||||
"Maintenance_Tool_backup_text": "",
|
||||
"Maintenance_Tool_check_visible": "",
|
||||
"Maintenance_Tool_clearSourceFields_selected": "",
|
||||
"Maintenance_Tool_clearSourceFields_selected_noti": "",
|
||||
"Maintenance_Tool_clearSourceFields_selected_text": "",
|
||||
"Maintenance_Tool_darkmode": "",
|
||||
"Maintenance_Tool_darkmode_noti": "",
|
||||
"Maintenance_Tool_darkmode_noti_text": "",
|
||||
|
||||
@@ -427,6 +427,9 @@
|
||||
"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": "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": "Décocher pour masquer la colonne.",
|
||||
"Maintenance_Tool_clearSourceFields_selected": "",
|
||||
"Maintenance_Tool_clearSourceFields_selected_noti": "",
|
||||
"Maintenance_Tool_clearSourceFields_selected_text": "",
|
||||
"Maintenance_Tool_darkmode": "Basculer de mode (clair/sombre)",
|
||||
"Maintenance_Tool_darkmode_noti": "Basculer de mode",
|
||||
"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é.",
|
||||
@@ -786,4 +789,4 @@
|
||||
"settings_system_label": "Système",
|
||||
"settings_update_item_warning": "Mettre à jour la valeur ci-dessous. Veillez à bien suivre le même format qu'auparavant. <b>Il n'y a pas de pas de contrôle.</b>",
|
||||
"test_event_tooltip": "Enregistrer d'abord vos modifications avant de tester vôtre paramétrage."
|
||||
}
|
||||
}
|
||||
@@ -427,6 +427,9 @@
|
||||
"Maintenance_Tool_backup_noti_text": "Sei sicuro di voler eseguire il backup del DB? Assicurati che nessuna scansione sia attualmente in esecuzione.",
|
||||
"Maintenance_Tool_backup_text": "I backup del database si trovano nella directory del database come archivio zip, denominato con la data di creazione. Non esiste un numero massimo di backup.",
|
||||
"Maintenance_Tool_check_visible": "Deseleziona per nascondere la colonna.",
|
||||
"Maintenance_Tool_clearSourceFields_selected": "",
|
||||
"Maintenance_Tool_clearSourceFields_selected_noti": "",
|
||||
"Maintenance_Tool_clearSourceFields_selected_text": "",
|
||||
"Maintenance_Tool_darkmode": "Alterna modalità (Scuro/Chiaro)",
|
||||
"Maintenance_Tool_darkmode_noti": "Alterna modalità",
|
||||
"Maintenance_Tool_darkmode_noti_text": "Dopo il cambio di tema, la pagina tenta di ricaricarsi per attivare la modifica. Potrebbe essere necessaria la cancellazione della cache.",
|
||||
@@ -786,4 +789,4 @@
|
||||
"settings_system_label": "Sistema",
|
||||
"settings_update_item_warning": "Aggiorna il valore qui sotto. Fai attenzione a seguire il formato precedente. <b>La convalida non viene eseguita.</b>",
|
||||
"test_event_tooltip": "Salva le modifiche prima di provare le nuove impostazioni."
|
||||
}
|
||||
}
|
||||
@@ -427,6 +427,9 @@
|
||||
"Maintenance_Tool_backup_noti_text": "データベースのバックアップを実行してもよろしいですか? 現在スキャンが実行されていないことを確認してください。",
|
||||
"Maintenance_Tool_backup_text": "データベースのバックアップは、作成日をファイル名としたzipアーカイブとしてデータベースディレクトリ内に配置されます。バックアップの最大数は存在しません。",
|
||||
"Maintenance_Tool_check_visible": "チェックを外すと列を非表示にします。",
|
||||
"Maintenance_Tool_clearSourceFields_selected": "",
|
||||
"Maintenance_Tool_clearSourceFields_selected_noti": "",
|
||||
"Maintenance_Tool_clearSourceFields_selected_text": "",
|
||||
"Maintenance_Tool_darkmode": "モード切替(ダーク/ライト)",
|
||||
"Maintenance_Tool_darkmode_noti": "モード切替",
|
||||
"Maintenance_Tool_darkmode_noti_text": "テーマ変更後、変更を有効化するためにページを再読み込みします。必要に応じて、キャッシュをクリアする必要があります。",
|
||||
|
||||
@@ -427,6 +427,9 @@
|
||||
"Maintenance_Tool_backup_noti_text": "Er du sikker på at du vil kjøre Database Sikkerhetskopiering? Pass på at ingen skanning kjører for øyeblikket.",
|
||||
"Maintenance_Tool_backup_text": "Databasesikkerhetskopiene er plassert i databasekatalogen som et zip-arkiv, navngitt med opprettelsesdatoen. Det er ikke noe maksimalt antall sikkerhetskopier.",
|
||||
"Maintenance_Tool_check_visible": "Fjern merket for å skjule kolonne.",
|
||||
"Maintenance_Tool_clearSourceFields_selected": "",
|
||||
"Maintenance_Tool_clearSourceFields_selected_noti": "",
|
||||
"Maintenance_Tool_clearSourceFields_selected_text": "",
|
||||
"Maintenance_Tool_darkmode": "Bytt Modus (mørk/lys)",
|
||||
"Maintenance_Tool_darkmode_noti": "Bytt Modus",
|
||||
"Maintenance_Tool_darkmode_noti_text": "Etter tema bytte, prøver siden å laste seg inn på nytt for å aktivere endringen. Om nødvendig må hurtigbufferen tømmes.",
|
||||
|
||||
@@ -427,6 +427,9 @@
|
||||
"Maintenance_Tool_backup_noti_text": "Czy na pewno chcesz wykonać kopię zapasową bazy danych? Upewnij się, że żadne skanowanie nie jest obecnie uruchomione.",
|
||||
"Maintenance_Tool_backup_text": "Kopie zapasowe bazy danych są zapisywane w katalogu bazy danych jako archiwum ZIP, nazwane zgodnie z datą utworzenia. Nie ma ustalonego limitu liczby kopii zapasowych.",
|
||||
"Maintenance_Tool_check_visible": "Usuń zaznaczenie, aby ukryć kolumnę.",
|
||||
"Maintenance_Tool_clearSourceFields_selected": "",
|
||||
"Maintenance_Tool_clearSourceFields_selected_noti": "",
|
||||
"Maintenance_Tool_clearSourceFields_selected_text": "",
|
||||
"Maintenance_Tool_darkmode": "Przełącz tryb (Ciemny/Jasny)",
|
||||
"Maintenance_Tool_darkmode_noti": "Przełącz tryb",
|
||||
"Maintenance_Tool_darkmode_noti_text": "Po zmianie motywu strona próbuje przeładować się, aby zastosować zmiany. W razie potrzeby należy wyczyścić pamięć podręczną (cache).",
|
||||
|
||||
@@ -427,6 +427,9 @@
|
||||
"Maintenance_Tool_backup_noti_text": "Tem a certeza de que pretende executar a cópia de segurança da BD? Certifique-se de que não está a ser executada nenhuma verificação.",
|
||||
"Maintenance_Tool_backup_text": "Os backups do banco de dados estão localizados no diretório do banco de dados como um zip-archive, nomeado com a data de criação. Não há nenhum número máximo de backups.",
|
||||
"Maintenance_Tool_check_visible": "Desmarque para esconder a coluna.",
|
||||
"Maintenance_Tool_clearSourceFields_selected": "",
|
||||
"Maintenance_Tool_clearSourceFields_selected_noti": "",
|
||||
"Maintenance_Tool_clearSourceFields_selected_text": "",
|
||||
"Maintenance_Tool_darkmode": "Modos de alternância (escuro/claro)",
|
||||
"Maintenance_Tool_darkmode_noti": "Modos de alternância",
|
||||
"Maintenance_Tool_darkmode_noti_text": "Após a mudança de tema, a página tenta recarregar-se para ativar a alteração. Se necessário, a cache deve ser limpa.",
|
||||
|
||||
@@ -427,6 +427,9 @@
|
||||
"Maintenance_Tool_backup_noti_text": "Tem a certeza de que pretende executar a cópia de segurança da BD? Certifique-se de que não está a ser executada nenhuma verificação.",
|
||||
"Maintenance_Tool_backup_text": "Os backups da base de dados estão localizadas no diretório da base de dados como um arquivo zip, nomeado com a data de criação. Não há nenhum número máximo de backups.",
|
||||
"Maintenance_Tool_check_visible": "Desmarque para esconder a coluna.",
|
||||
"Maintenance_Tool_clearSourceFields_selected": "",
|
||||
"Maintenance_Tool_clearSourceFields_selected_noti": "",
|
||||
"Maintenance_Tool_clearSourceFields_selected_text": "",
|
||||
"Maintenance_Tool_darkmode": "Modos de alternância (escuro/claro)",
|
||||
"Maintenance_Tool_darkmode_noti": "Modos de alternância",
|
||||
"Maintenance_Tool_darkmode_noti_text": "Após a mudança de tema, a página tenta recarregar-se para ativar a alteração. Se necessário, a cache deve ser limpa.",
|
||||
|
||||
@@ -427,6 +427,9 @@
|
||||
"Maintenance_Tool_backup_noti_text": "Вы уверены, что хотите выполнить резервное копирование БД? Убедитесь, что в данный момент сканирование не выполняется.",
|
||||
"Maintenance_Tool_backup_text": "Резервные копии базы данных располагаются в каталоге базы данных в виде zip-архива, имя которого соответствует дате создания. Максимального количества резервных копий не существует.",
|
||||
"Maintenance_Tool_check_visible": "Снимите флажок, чтобы скрыть столбец.",
|
||||
"Maintenance_Tool_clearSourceFields_selected": "",
|
||||
"Maintenance_Tool_clearSourceFields_selected_noti": "",
|
||||
"Maintenance_Tool_clearSourceFields_selected_text": "",
|
||||
"Maintenance_Tool_darkmode": "Тема (Темная/Светлая)",
|
||||
"Maintenance_Tool_darkmode_noti": "Переключение режимов",
|
||||
"Maintenance_Tool_darkmode_noti_text": "После переключения темы страница пытается перезагрузиться, чтобы активировать изменение. При необходимости кэш необходимо очистить.",
|
||||
|
||||
@@ -427,6 +427,9 @@
|
||||
"Maintenance_Tool_backup_noti_text": "",
|
||||
"Maintenance_Tool_backup_text": "",
|
||||
"Maintenance_Tool_check_visible": "",
|
||||
"Maintenance_Tool_clearSourceFields_selected": "",
|
||||
"Maintenance_Tool_clearSourceFields_selected_noti": "",
|
||||
"Maintenance_Tool_clearSourceFields_selected_text": "",
|
||||
"Maintenance_Tool_darkmode": "",
|
||||
"Maintenance_Tool_darkmode_noti": "",
|
||||
"Maintenance_Tool_darkmode_noti_text": "",
|
||||
|
||||
@@ -427,6 +427,9 @@
|
||||
"Maintenance_Tool_backup_noti_text": "DB Yedeklemesini yürütmek istediğinizden emin misiniz? Şu anda hiçbir taramanın çalışmadığından emin olun.",
|
||||
"Maintenance_Tool_backup_text": "Veritabanı yedekleri, veritabanı dizininde, oluşturulma tarihiyle adlandırılan bir zip arşivi olarak bulunur. Maksimum yedekleme sayısı yoktur.",
|
||||
"Maintenance_Tool_check_visible": "Sütunu gizlemek için işareti kaldırın.",
|
||||
"Maintenance_Tool_clearSourceFields_selected": "",
|
||||
"Maintenance_Tool_clearSourceFields_selected_noti": "",
|
||||
"Maintenance_Tool_clearSourceFields_selected_text": "",
|
||||
"Maintenance_Tool_darkmode": "Modları Değiştir (Koyu/Açık)",
|
||||
"Maintenance_Tool_darkmode_noti": "Modları Aç/Kapat",
|
||||
"Maintenance_Tool_darkmode_noti_text": "Tema geçişinden sonra sayfa, değişikliği etkinleştirmek için kendini yeniden yüklemeye çalışır. Gerekirse, önbellek temizlenmelidir.",
|
||||
|
||||
@@ -427,6 +427,9 @@
|
||||
"Maintenance_Tool_backup_noti_text": "Ви впевнені, що хочете виконати резервне копіювання БД? Переконайтеся, що сканування наразі не виконується.",
|
||||
"Maintenance_Tool_backup_text": "Резервні копії бази даних зберігаються в каталозі бази даних у вигляді zip-архіву з датою створення. Немає максимальної кількості резервних копій.",
|
||||
"Maintenance_Tool_check_visible": "Зніміть прапорець, щоб приховати стовпець.",
|
||||
"Maintenance_Tool_clearSourceFields_selected": "",
|
||||
"Maintenance_Tool_clearSourceFields_selected_noti": "",
|
||||
"Maintenance_Tool_clearSourceFields_selected_text": "",
|
||||
"Maintenance_Tool_darkmode": "Перемикати режими (темний/світлий)",
|
||||
"Maintenance_Tool_darkmode_noti": "Перемикати режими",
|
||||
"Maintenance_Tool_darkmode_noti_text": "Після перемикання теми сторінка намагається перезавантажитися, щоб активувати зміну. При необхідності необхідно очистити кеш.",
|
||||
|
||||
@@ -427,6 +427,9 @@
|
||||
"Maintenance_Tool_backup_noti_text": "您确定要执行数据库备份吗?请确保当前没有正在运行的扫描。",
|
||||
"Maintenance_Tool_backup_text": "数据库备份以 zip 存档形式位于数据库目录中,以创建日期命名。备份数量没有上限。",
|
||||
"Maintenance_Tool_check_visible": "取消选择隐藏列。",
|
||||
"Maintenance_Tool_clearSourceFields_selected": "",
|
||||
"Maintenance_Tool_clearSourceFields_selected_noti": "",
|
||||
"Maintenance_Tool_clearSourceFields_selected_text": "",
|
||||
"Maintenance_Tool_darkmode": "切换模式(暗/亮)",
|
||||
"Maintenance_Tool_darkmode_noti": "切换模式",
|
||||
"Maintenance_Tool_darkmode_noti_text": "主题切换后,页面会尝试重新加载以激活更改。如有必要,必须清除缓存。",
|
||||
@@ -760,7 +763,7 @@
|
||||
"run_event_tooltip": "在运行之前,请先启用设置并保存更改。",
|
||||
"select_icon_event_tooltip": "选择图标",
|
||||
"settings_core_icon": "fa-solid fa-gem",
|
||||
"settings_core_label": "核心",
|
||||
"settings_core_label": "主要",
|
||||
"settings_device_scanners": "设备扫描器用于发现写入当前扫描数据库表的设备。",
|
||||
"settings_device_scanners_icon": "fa-solid fa-magnifying-glass-plus",
|
||||
"settings_device_scanners_info": "使用 <a href=\"/settings.php#LOADED_PLUGINS\">LOADED_PLUGINS</a> 设置加载更多设备扫描仪",
|
||||
@@ -786,4 +789,4 @@
|
||||
"settings_system_label": "系统",
|
||||
"settings_update_item_warning": "更新下面的值。请注意遵循先前的格式。<b>未执行验证。</b>",
|
||||
"test_event_tooltip": "在测试设置之前,请先保存更改。"
|
||||
}
|
||||
}
|
||||
@@ -418,7 +418,6 @@
|
||||
},
|
||||
{
|
||||
"column": "Watched_Value1",
|
||||
"mapped_to_column": "scanName",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
site_name: NetAlertX Documentation
|
||||
site_name: Documentation
|
||||
site_url: https://docs.netalertx.com
|
||||
repo_url: https://github.com/jokob-sk/NetAlertX/
|
||||
repo_url: https://github.com/netalertx/NetAlertX/
|
||||
edit_uri: blob/main/docs/
|
||||
docs_dir: docs
|
||||
use_directory_urls: true
|
||||
@@ -141,7 +141,7 @@ theme:
|
||||
custom_dir: docs/overrides
|
||||
metadata:
|
||||
description: "NetAlertX Documentation - The go-to resource for all things related to NetAlertX."
|
||||
image: "https://raw.githubusercontent.com/jokob-sk/NetAlertX/main/front/img/netalertx_docs.png"
|
||||
image: "https://raw.githubusercontent.com/netalertx/NetAlertX/main/front/img/netalertx_docs.png"
|
||||
extra:
|
||||
home_hide_sidebar: true
|
||||
analytics:
|
||||
|
||||
@@ -4,7 +4,7 @@ import os
|
||||
|
||||
# flake8: noqa: E402
|
||||
|
||||
from flask import Flask, request, jsonify, Response
|
||||
from flask import Flask, redirect, request, jsonify, url_for, Response
|
||||
from models.device_instance import DeviceInstance # noqa: E402
|
||||
from flask_cors import CORS
|
||||
from werkzeug.exceptions import HTTPException
|
||||
@@ -1165,6 +1165,11 @@ def api_docs():
|
||||
return send_from_directory(openapi_dir, 'swagger.html')
|
||||
|
||||
|
||||
@app.route('/')
|
||||
def index_redirect():
|
||||
"""Redirect root to API documentation."""
|
||||
return redirect(url_for('api_docs'))
|
||||
|
||||
# --------------------------
|
||||
# DB query
|
||||
# --------------------------
|
||||
@@ -1401,7 +1406,7 @@ def api_create_event(mac, payload=None):
|
||||
def api_events_by_mac(mac, payload=None):
|
||||
"""Delete events for a specific device MAC; string converter keeps this distinct from /events/<int:days>."""
|
||||
device_handler = DeviceInstance()
|
||||
|
||||
|
||||
result = device_handler.deleteDeviceEvents(mac)
|
||||
return jsonify(result)
|
||||
|
||||
@@ -1740,7 +1745,8 @@ def api_write_notification(payload=None):
|
||||
auth_callable=is_authorized
|
||||
)
|
||||
def api_get_unread_notifications(payload=None):
|
||||
return get_unread_notifications()
|
||||
notifications = get_unread_notifications()
|
||||
return jsonify(notifications)
|
||||
|
||||
|
||||
@app.route("/messaging/in-app/read/all", methods=["POST"])
|
||||
|
||||
@@ -231,7 +231,7 @@ def get_unread_notifications():
|
||||
notifications = json.load(f)
|
||||
|
||||
unread = [n for n in notifications if n.get("read", 0) == 0]
|
||||
return jsonify(unread)
|
||||
return unread
|
||||
|
||||
|
||||
def mark_notification_as_read(guid=None, max_attempts=3):
|
||||
@@ -283,6 +283,13 @@ def mark_notification_as_read(guid=None, max_attempts=3):
|
||||
return {"success": False, "error": error_msg}
|
||||
|
||||
|
||||
def update_unread_notifications_count():
|
||||
"""
|
||||
Re-broadcast unread notifications for the frontend .
|
||||
"""
|
||||
broadcast_unread_notifications_count(len(get_unread_notifications()))
|
||||
|
||||
|
||||
def delete_notification(guid):
|
||||
"""
|
||||
Delete a notification from the notifications file based on its GUID.
|
||||
|
||||
@@ -18,7 +18,7 @@ from db.authoritative_handler import (
|
||||
unlock_fields
|
||||
)
|
||||
from helper import is_random_mac, get_setting_value
|
||||
from utils.datetime_utils import timeNowDB, format_date
|
||||
from utils.datetime_utils import timeNowDB
|
||||
|
||||
|
||||
class DeviceInstance:
|
||||
@@ -489,8 +489,8 @@ class DeviceInstance:
|
||||
return None
|
||||
|
||||
device_data = row_to_json(list(row.keys()), row)
|
||||
device_data["devFirstConnection"] = format_date(device_data["devFirstConnection"])
|
||||
device_data["devLastConnection"] = format_date(device_data["devLastConnection"])
|
||||
device_data["devFirstConnection"] = device_data["devFirstConnection"]
|
||||
device_data["devLastConnection"] = device_data["devLastConnection"]
|
||||
device_data["devIsRandomMAC"] = is_random_mac(device_data["devMac"])
|
||||
|
||||
# Fetch children
|
||||
|
||||
@@ -212,8 +212,8 @@ class plugin_manager:
|
||||
# Run test
|
||||
self.handle_run(runType)
|
||||
|
||||
# Remove sample notification
|
||||
notificationObj.remove(notificationObj.GUID)
|
||||
# Save notification
|
||||
notificationObj.upsert()
|
||||
|
||||
mylog("minimal", ["[Test] END Test: ", runType])
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ from db.db_helper import print_table_schema
|
||||
from utils.datetime_utils import timeNowDB
|
||||
from logger import mylog, Logger
|
||||
from messaging.reporting import skip_repeated_notifications
|
||||
from messaging.in_app import update_unread_notifications_count
|
||||
|
||||
|
||||
# Make sure log level is initialized correctly
|
||||
@@ -104,6 +105,9 @@ def process_scan(db):
|
||||
# 🐛 CurrentScan DEBUG: comment out below when debugging to keep the CurrentScan table after restarts/scan finishes
|
||||
db.sql.execute("DELETE FROM CurrentScan")
|
||||
|
||||
# re-broadcast unread notifiation count to update FE
|
||||
update_unread_notifications_count()
|
||||
|
||||
# Commit changes
|
||||
db.commitDB()
|
||||
|
||||
|
||||
@@ -112,12 +112,29 @@ def normalizeTimeStamp(inputTimeStamp):
|
||||
|
||||
|
||||
# -------------------------------------------------------------------------------------------
|
||||
def format_date_iso(date1: str) -> Optional[str]:
|
||||
"""Return ISO 8601 string for a date or None if empty"""
|
||||
if not date1:
|
||||
def format_date_iso(date_val: str) -> Optional[str]:
|
||||
"""Ensures a date string from DB is returned as a proper ISO string with TZ."""
|
||||
if not date_val:
|
||||
return None
|
||||
dt = datetime.datetime.fromisoformat(date1) if isinstance(date1, str) else date1
|
||||
return dt.isoformat()
|
||||
|
||||
try:
|
||||
# 1. Parse the string from DB (e.g., "2026-01-20 07:58:18")
|
||||
if isinstance(date_val, str):
|
||||
# Use a more flexible parser if it's not strict ISO
|
||||
dt = datetime.datetime.fromisoformat(date_val.replace(" ", "T"))
|
||||
else:
|
||||
dt = date_val
|
||||
|
||||
# 2. If it has no timezone, ATTACH (don't convert) your config TZ
|
||||
if dt.tzinfo is None:
|
||||
target_tz = conf.tz if isinstance(conf.tz, datetime.tzinfo) else ZoneInfo(conf.tz)
|
||||
dt = dt.replace(tzinfo=target_tz)
|
||||
|
||||
# 3. Return the string. .isoformat() will now include the +11:00 or +10:00
|
||||
return dt.isoformat()
|
||||
except Exception as e:
|
||||
print(f"Error formatting date: {e}")
|
||||
return str(date_val)
|
||||
|
||||
|
||||
# -------------------------------------------------------------------------------------------
|
||||
@@ -156,21 +173,35 @@ def parse_datetime(dt_str):
|
||||
|
||||
def format_date(date_str: str) -> str:
|
||||
try:
|
||||
if isinstance(date_str, str):
|
||||
# collapse all whitespace into single spaces
|
||||
date_str = re.sub(r"\s+", " ", date_str.strip())
|
||||
if not date_str:
|
||||
return ""
|
||||
|
||||
date_str = re.sub(r"\s+", " ", str(date_str).strip())
|
||||
dt = parse_datetime(date_str)
|
||||
|
||||
if dt.tzinfo is None:
|
||||
if isinstance(conf.tz, str):
|
||||
dt = dt.replace(tzinfo=ZoneInfo(conf.tz))
|
||||
else:
|
||||
dt = dt.replace(tzinfo=conf.tz)
|
||||
|
||||
if not dt:
|
||||
return f"invalid:{repr(date_str)}"
|
||||
|
||||
# If the DB has no timezone, we tell Python what it IS,
|
||||
# we don't CONVERT it.
|
||||
if dt.tzinfo is None:
|
||||
# Option A: If the DB time is already AEDT, use AEDT.
|
||||
# Option B: Use conf.tz if that is your 'source of truth'
|
||||
dt = dt.replace(tzinfo=conf.tz)
|
||||
|
||||
return dt.astimezone().isoformat()
|
||||
# IMPORTANT: Return the ISO format of the object AS IS.
|
||||
# Calling .astimezone() here triggers a conversion to the
|
||||
# System Local Time , which is causing your shift.
|
||||
return dt.isoformat()
|
||||
|
||||
except Exception:
|
||||
return f"invalid:{repr(date_str)}"
|
||||
except Exception as e:
|
||||
return f"invalid:{repr(date_str)} e: {e}"
|
||||
|
||||
|
||||
def format_date_diff(date1, date2, tz_name):
|
||||
|
||||
23
test/api_endpoints/test_docs.py
Normal file
@@ -0,0 +1,23 @@
|
||||
# test/api_endpoints/test_docs.py - Tests for root redirect and API docs endpoints
|
||||
|
||||
|
||||
from api_server import api_server_start
|
||||
|
||||
|
||||
def test_index_redirect_logic():
|
||||
"""Test the redirect function logic directly."""
|
||||
with api_server_start.app.test_client() as client:
|
||||
response = client.get("/", follow_redirects=False)
|
||||
assert response.status_code == 302
|
||||
assert response.location == '/docs'
|
||||
|
||||
|
||||
def test_api_docs_logic():
|
||||
"""Test that api_docs attempts to serve the correct file."""
|
||||
with api_server_start.app.test_client() as client:
|
||||
response = client.get("/docs")
|
||||
assert response.status_code == 200
|
||||
assert response.mimetype == "text/html"
|
||||
response.direct_passthrough = False
|
||||
data = response.get_data()
|
||||
assert b"<!DOCTYPE html>" in data or b"<html>" in data
|
||||