Compare commits

..

14 Commits

Author SHA1 Message Date
jokob-sk
e1f9ca05b7 wf docs 2025-04-01 08:20:00 +11:00
Максим Горпиніч
4aaf86f0fc Translated using Weblate (Ukrainian)
Some checks are pending
URL Path Check / check-url-paths (push) Waiting to run
docker / docker_dev (push) Waiting to run
Deploy MkDocs / deploy (push) Waiting to run
Currently translated at 100.0% (743 of 743 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/uk/
2025-03-31 13:27:45 +02:00
jokob-sk
9bb21ad303 wf docs 2025-03-31 18:46:55 +11:00
jokob-sk
e1197eb3f8 wf work + docs 2025-03-31 18:05:15 +11:00
jokob-sk
2c445ccaeb wf work + docs 2025-03-31 18:04:56 +11:00
jokob-sk
8a07f7067b Merge branch 'main' of https://github.com/jokob-sk/NetAlertX
Some checks are pending
URL Path Check / check-url-paths (push) Waiting to run
docker / docker_dev (push) Waiting to run
Deploy MkDocs / deploy (push) Waiting to run
2025-03-31 08:12:57 +11:00
jokob-sk
d86c2a5023 Move ObjectGUID to the end 2025-03-31 08:12:32 +11:00
Максим Горпиніч
2b51674e52 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (737 of 737 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/uk/
2025-03-30 19:39:24 +02:00
Sylvain Pichon
eb6820dd93 Translated using Weblate (French)
Currently translated at 100.0% (737 of 737 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/fr/
2025-03-30 19:39:24 +02:00
Ettore Atalan
b156246cb0 Translated using Weblate (German)
Currently translated at 89.2% (658 of 737 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/de/
2025-03-30 19:39:24 +02:00
Hosted Weblate
716c6a4046 Merge branch 'origin/main' into Weblate.
Some checks are pending
URL Path Check / check-url-paths (push) Waiting to run
docker / docker_dev (push) Waiting to run
Deploy MkDocs / deploy (push) Waiting to run
2025-03-30 08:30:09 +02:00
Massimo Pissarello
114b5a2621 Translated using Weblate (Italian)
Currently translated at 100.0% (737 of 737 strings)

Translation: NetAlertX/core
Translate-URL: https://hosted.weblate.org/projects/pialert/core/it/
2025-03-30 08:30:09 +02:00
jokob-sk
02b19c833e Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2025-03-30 17:29:56 +11:00
jokob-sk
e0c06548ba wf work + fa upgrade + css cleanup + network tweaks 2025-03-30 17:29:22 +11:00
41 changed files with 509 additions and 1808 deletions

View File

@@ -103,3 +103,42 @@ DEV_LOCATION=/path/to/local/source/code
```
To run the container execute: `sudo docker-compose --env-file /path/to/.env up`
### Example 4: Docker swarm
Notice how the host network is defined in a swarm setup:
```yaml
services:
netalertx:
# Use the below line if you want to test the latest dev image
# image: "jokobsk/netalertx-dev:latest"
image: "ghcr.io/jokob-sk/netalertx:latest"
volumes:
- /mnt/MYSERVER/netalertx/config:/config:rw
- /mnt/MYSERVER/netalertx/db:/netalertx/db:rw
- /mnt/MYSERVER/netalertx/logs:/netalertx/front/log:rw
environment:
- TZ=Europe/London
- PORT=20211
# network_mode: host
networks:
- outside
deploy:
mode: replicated
replicas: 1
restart_policy:
condition: on-failure
# placement: # ✅ Placement is now correctly inside deploy
# constraints:
# - node.role == manager
# - node.labels.device == NUC2
networks:
outside:
external:
name: "host"
```

View File

@@ -21,6 +21,9 @@ There are 4 settings on the device for influencing notifications. You can:
2. **Alert Down** - Alerts when a device goes down. This setting overrides a disabled **Alert Events** setting, so you will get a notification of a device going down even if you don't have **Alert Events** ticked. Disabling this will disable down and down reconnected notifications on the device.
3. **Skip repeated notifications**, if for example you know there is a temporary issue and want to pause the same notification for this device for a given time.
> [!NOTE]
> Please read through the [NTFPRCS plugin](https://github.com/jokob-sk/NetAlertX/blob/main/front/plugins/notification_processing/README.md) documentation to understand how device and global settings influence the notification processing.
## Plugin settings 🔌
![Plugin notification settings](./img/NOTIFICATIONS/Plugin-notification-settings.png)
@@ -38,7 +41,7 @@ Click the **Read more in the docs.** Link at the top of each plugin to get more
In Notification Processing settings, you can specify blanket rules. These allow you to specify exceptions to the Plugin and Device settings and will override those.
1. Notify on (`NTFPRCS_INCLUDED_SECTIONS`) allows you to specify which events trigger notifications. Usual setups will have `new_devices`, `down_devices`, and possibly `down_reconnected` set. Including `plugin` (dependenton the Plugin `<plugin>_WATCH` and `<plugin>_REPORT_ON` settings) and `events` (dependent on the on-device **Alert Events** setting) might be too noisy for most setups. More info in the [NTFPRCS plugin](/front/plugins/notification_processing/README.md) on what events these selections include.
1. Notify on (`NTFPRCS_INCLUDED_SECTIONS`) allows you to specify which events trigger notifications. Usual setups will have `new_devices`, `down_devices`, and possibly `down_reconnected` set. Including `plugin` (dependenton the Plugin `<plugin>_WATCH` and `<plugin>_REPORT_ON` settings) and `events` (dependent on the on-device **Alert Events** setting) might be too noisy for most setups. More info in the [NTFPRCS plugin](https://github.com/jokob-sk/NetAlertX/blob/main/front/plugins/notification_processing/README.md) on what events these selections include.
2. Alert down after (`NTFPRCS_alert_down_time`) is useful if you want to wait for some time before the system sends out a down notification for a device. This is related to the on-device **Alert down** setting and only devices with this checked will trigger a down notification.
3. A filter to allow you to set device-specific exceptions to New devices being added to the app.
4. A filter to allow you to set device-specific exceptions to generated Events.

View File

@@ -1,25 +1,31 @@
# Workflows Overview
The workflows module in NetAlertX allows you to automate repetitive tasks, making network management more efficient. Whether you need to assign newly discovered devices to a specific Network Node, auto-group devices from a given vendor, unarchive a device if detected online, or automatically delete or archive devices, this module provides the flexibility to tailor the automations to your needs.
The workflows module in NetAlertX allows to automate repetitive tasks, making network management more efficient. Whether you need to assign newly discovered devices to a specific Network Node, auto-group devices from a given vendor, unarchive a device if detected online, or automatically delete devices, this module provides the flexibility to tailor the automations to your needs.
![Workflow example](./img/WORKFLOWS/workflows.png)
![Workflows diagram](./img/WORKFLOWS/workflows_diagram.png)
Below are a few examples that demonstrate how this module can be used to simplify network management tasks.
## Updating Workflows
> [!NOTE]
> In order to apply a workflow change, you must first **Save** the changes and then reload the application by clicking **Restart server**.
## Triggers
## Workflow components
### Triggers
Triggers define the event that activates a workflow. They monitor changes to objects within the system, such as updates to devices or the insertion of new entries. When the specified event occurs, the workflow is executed.
### Example Trigger:
#### Example Trigger:
- **Object Type**: `Devices`
- **Event Type**: `update`
This trigger will activate when a `Device` object is updated.
## Conditions
### Conditions
![Conditions example](./img/WORKFLOWS/conditions.png)
Conditions determine whether a workflow should proceed based on certain criteria. These criteria can be set for specific fields, such as whether a device is from a certain vendor, or whether it is new or archived. You can combine conditions using logical operators (`AND`, `OR`).
@@ -29,15 +35,19 @@ Conditions determine whether a workflow should proceed based on certain criteria
### Example Condition:
- **Logic**: `AND`
- **Field**: `devVendor`
- **Operator**: `contains`
- **Operator**: `contains` (case in-sensitive)
- **Value**: `Google`
This condition checks if the device's vendor is `Google`. The workflow will only proceed if the condition is true.
## Actions
### Actions
![Actions example](./img/WORKFLOWS/actions.jpg)
Actions define the tasks that the workflow will perform once the conditions are met. Actions can include updating fields or deleting devices.
You can include multiple actions that should execute once the conditions are met.
### Example Action:
- **Action Type**: `update_field`
- **Field**: `devIsNew`
@@ -50,13 +60,17 @@ Actions define the tasks that the workflow will perform once the conditions are
Below you can find a couple of configuration examples.
![Workflow example](./img/WORKFLOWS/workflows.png)
---
## Example 1: Assign Device to Network Node Based on IP
This workflow assigns newly added devices with IP addresses in the `192.168.1.*` range to the device with the MAC address `6c:6d:6d:6c:6c:6c`.
### Trigger:
- **Object Type**: `Devices`
- **Event Type**: `create`
- **Event Type**: `insert`
### Conditions:
- **Logic**: `AND`
@@ -71,12 +85,12 @@ Below you can find a couple of configuration examples.
- **Field**: `devNetworkNode`
- **Value**: `6c:6d:6d:6c:6c:6c`
This workflow assigns newly added devices with IP addresses in the `192.168.1.*` range to the device with the MAC address `6c:6d:6d:6c:6c:6c`.
---
## Example 2: Mark Device as Not New and Delete If from Google Vendor
This workflow automates the process of marking Google devices as not new and deleting them if they meet the criteria.
### Trigger:
- **Object Type**: `Devices`
- **Event Type**: `update`
@@ -107,10 +121,5 @@ This workflow assigns newly added devices with IP addresses in the `192.168.1.*`
This action deletes the device after it is marked as not new.
This workflow automates the process of marking Google devices as not new and deleting them if they meet the criteria.
---
### Conclusion
With workflows, NetAlertX can automatically adjust to network changes, saving time and reducing the manual overhead involved in maintaining your devices. You can create highly tailored automation rules to handle everything from basic updates to more complex device management.
> [!TIP]
> Share your workflows in [Discord](https://discord.com/invite/NczTUTWyRr) or [GitHub Discussions](https://github.com/jokob-sk/NetAlertX/discussions).

BIN
docs/img/WORKFLOWS/actions.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
docs/img/WORKFLOWS/conditions.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 89 KiB

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

View File

@@ -1517,10 +1517,9 @@ input[readonly] {
/* AdminLTE overrides */
#networkTree .box
{
border-top:1px;
/* border-top:1px; */
border-top-color:grey;
padding:0px;
padding-top:6px;
margin:0px;
align-items:center;
border-radius:20px;
@@ -1528,7 +1527,7 @@ input[readonly] {
/* display:flex; */
flex-direction:column;
justify-content:center;
display: inline-grid;
/* display: inline-grid; */
}
.helpIcon
{
@@ -1577,17 +1576,16 @@ input[readonly] {
width: auto;
}
#networkTree .netCollapse
{
display: block;
position: absolute;
margin-left: 170px;
font-size: large;
left: -15px;
right: 0;
margin-right: -3px;
}
#networkTree .highlightedNode
{
border: solid;
/* border: solid; */
border-color:cyan;
}
#networkTree .netStatus-Off-line i,
@@ -1598,7 +1596,6 @@ input[readonly] {
.spanNetworkTree {
display: inline-block;
/* width: 135px; */
white-space: nowrap;
overflow: hidden !important;
text-overflow: ellipsis;
@@ -1614,6 +1611,11 @@ input[readonly] {
/* margin-left: 0.2em; */
}
.networkTable .networkNodeTabHeaders a {
display: block;
height: 3em;
}
.networkTable .icon {
/* padding-left:2em; */
width:2em;
@@ -1632,7 +1634,6 @@ input[readonly] {
.networkNodeTabHeaders
{
max-width: 200px;
text-overflow: ellipsis;
overflow: hidden;
text-wrap: nowrap;
@@ -1710,13 +1711,6 @@ input[readonly] {
padding-top: 20px;
}
.login-page .login-custom
{
width:480px;
}
/*Hidden special button*/
@media (max-width: 365px) {
@@ -1975,6 +1969,7 @@ input[readonly] {
right: 0.1em;
}
.workflows .remove-condition
{
z-index: 1;

View File

@@ -74,10 +74,10 @@
<!-- box-header -->
<div class="box-header">
<div class=" col-md-9 ">
<div class=" col-sm-8 ">
<h3 id="tableDevicesTitle" class="box-title text-gray "></h3>
</div>
<div class="dummyDevice col-md-3 ">
<div class="dummyDevice col-sm-4 ">
<span id="multiEditPlc">
<!-- multi edit button placeholder -->
</span>

View File

@@ -92,10 +92,8 @@ if (isset ($_SESSION["login"]) == FALSE || $_SESSION["login"] != 1)
<!-- iCheck -->
<link rel="stylesheet" href="lib/iCheck/square/blue.css">
<!-- Font Awesome -->
<link rel="stylesheet" href="lib/font-awesome/fontawesome.min.css">
<link rel="stylesheet" href="lib/font-awesome/solid.css">
<link rel="stylesheet" href="lib/font-awesome/brands.css">
<link rel="stylesheet" href="lib/font-awesome/v5-font-face.css">
<link rel="stylesheet" href="lib/font-awesome/all.min.css">
<!-- Favicon -->
<link id="favicon" rel="icon" type="image/x-icon" href="img/NetAlertX_logo.png">
@@ -112,7 +110,7 @@ switch ($UI_THEME) {
?>
<link rel="stylesheet" href="/css/offline-font.css">
</head>
<body class="hold-transition login-page">
<body class="hold-transition login-page col-sm-12 col-sx-12">
<div class="login-box login-custom">
<div class="login-logo">
<a href="/index2.php">Net<b>Alert</b><sup>x</sup></a>

View File

@@ -68,11 +68,13 @@ function showModalWarning(
callbackFunction = null,
triggeredBy = null
) {
prefix = "modal-warning";
// set captions
$("#modal-warning-title").html(title);
$("#modal-warning-message").html(message);
$("#modal-warning-cancel").html(btnCancel);
$("#modal-warning-OK").html(btnOK);
$(`#${prefix}-title`).html(title);
$(`#${prefix}-message`).html(message);
$(`#${prefix}-cancel`).html(btnCancel);
$(`#${prefix}-OK`).html(btnOK);
if (callbackFunction != null) {
modalCallbackFunction = callbackFunction;
@@ -83,7 +85,7 @@ function showModalWarning(
}
// Show modal
$("#modal-warning").modal("show");
$(`#${prefix}`).modal("show");
}
// -----------------------------------------------------------------------------
@@ -93,7 +95,8 @@ function showModalInput(
btnCancel = getString("Gen_Cancel"),
btnOK = getString("Gen_Okay"),
callbackFunction = null,
triggeredBy = null
triggeredBy = null,
defaultValue = ""
) {
prefix = "modal-input";
@@ -102,6 +105,7 @@ function showModalInput(
$(`#${prefix}-message`).html(message);
$(`#${prefix}-cancel`).html(btnCancel);
$(`#${prefix}-OK`).html(btnOK);
$(`#${prefix}-textarea`).val(defaultValue);
if (callbackFunction != null) {
modalCallbackFunction = callbackFunction;

9
front/lib/font-awesome/all.min.css vendored Executable file

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,19 +0,0 @@
/*!
* Font Awesome Free 6.2.1 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
* Copyright 2022 Fonticons, Inc.
*/
:root, :host {
--fa-style-family-classic: 'Font Awesome 6 Free';
--fa-font-solid: normal 900 1em/1 'Font Awesome 6 Free'; }
@font-face {
font-family: 'Font Awesome 6 Free';
font-style: normal;
font-weight: 900;
font-display: block;
src: url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.ttf") format("truetype"); }
.fas,
.fa-solid {
font-weight: 900; }

View File

@@ -1,6 +0,0 @@
/*!
* Font Awesome Free 6.2.1 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
* Copyright 2022 Fonticons, Inc.
*/
:host,:root{--fa-style-family-classic:"Font Awesome 6 Free";--fa-font-solid:normal 900 1em/1 "Font Awesome 6 Free"}@font-face{font-family:"Font Awesome 6 Free";font-style:normal;font-weight:900;font-display:block;src:url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.ttf) format("truetype")}.fa-solid,.fas{font-weight:900}

View File

@@ -1,22 +0,0 @@
/*!
* Font Awesome Free 6.2.1 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
* Copyright 2022 Fonticons, Inc.
*/
@font-face {
font-family: 'Font Awesome 5 Brands';
font-display: block;
font-weight: 400;
src: url("../webfonts/fa-brands-400.woff2") format("woff2"), url("../webfonts/fa-brands-400.ttf") format("truetype"); }
@font-face {
font-family: 'Font Awesome 5 Free';
font-display: block;
font-weight: 900;
src: url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.ttf") format("truetype"); }
@font-face {
font-family: 'Font Awesome 5 Free';
font-display: block;
font-weight: 400;
src: url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.ttf") format("truetype"); }

View File

@@ -1,6 +0,0 @@
/*!
* Font Awesome Free 6.2.1 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
* Copyright 2022 Fonticons, Inc.
*/
@font-face{font-family:"Font Awesome 5 Brands";font-display:block;font-weight:400;src:url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.ttf) format("truetype")}@font-face{font-family:"Font Awesome 5 Free";font-display:block;font-weight:900;src:url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.ttf) format("truetype")}@font-face{font-family:"Font Awesome 5 Free";font-display:block;font-weight:400;src:url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.ttf) format("truetype")}

View File

@@ -6,8 +6,6 @@
// online / offline badges HTML snippets
define('badge_online', '<div class="badge bg-green text-white" style="width: 60px;">Online</div>');
define('badge_offline', '<div class="badge bg-red text-white" style="width: 60px;">Offline</div>');
define('circle_online', '<div class="badge bg-green text-white" style="width: 10px; height: 10px; padding:2px; margin-top: -25px;">&nbsp;</div>');
define('circle_offline', '<div class="badge bg-red text-white" style="width: 10px; height: 10px; padding:2px; margin-top: -25px;">&nbsp;</div>');
define('sortable_column', ' <span class="sort-btn" onclick="sortColumn(this)"><i class="fa-solid fa-arrow-up-short-wide"></i></span>');
?>
@@ -39,21 +37,18 @@
}
// online/offline status circle (red/green)
$node_badge = "";
if($node_status == 1) // 1 means online, 0 offline
$icon_style = "";
if($node_status == 0) // 1 means online, 0 offline
{
$node_badge = circle_online;
} else
{
$node_badge = circle_offline;
}
$icon_style = "style=\"color:var(--color-red);\"";
}
$decoded_icon = base64_decode($icon);
$idFromMac = str_replace(":", "_", $node_mac);
$str_tab_header = '<li class="networkNodeTabHeaders '.$activetab.' " >
<a href="#'.$idFromMac.'" data-mytabmac="'.$node_mac.'" id="'.$idFromMac.'_id" data-toggle="tab" title="'.$node_name.' ">' // _id is added so it doesn't conflict with AdminLTE tab behavior
.'<div class="icon">'.$decoded_icon.' </div> <span class="node-name">'.$node_name.'</span>' .$str_port.$node_badge.
.'<div class="icon" '.$icon_style.'>'.$decoded_icon.' </div> <span class="node-name">'.$node_name.'</span>' .$str_port.
'</a>
</li>';
@@ -697,34 +692,56 @@ function attachTreeEvents()
// ---------------------------------------------------------------------------
// Handle network node click - select correct tab in the bottom table
function handleNodeClick(nodeData)
function handleNodeClick(el)
{
const targetTabMAC = nodeData.data.mac;
const targetTabMAC = $(el).attr("data-mytreemacmain");
var targetTab = $(`a[data-mytabmac="${targetTabMAC}"]`);
// Simulate a click event on the target tab
targetTab.click();
if (targetTab.length) {
// Simulate a click event on the target tab
targetTab.click();
// Smooth scroll to the tab content
$('html, body').animate({
scrollTop: targetTab.offset().top - 50
}, 500); // Adjust the duration as needed
}
}
// ---------------------------------------------------------------------------
var myTree;
var visibleTreeArea = $(window).height()-155;
var nodeWidth = 120;
var emSize;
var nodeHeight;
var sizeCoefficient = 1.4
// var sizeCoefficient = 1.4
function pxToEm(px, element) {
var baseFontSize = parseFloat($(element || "body").css("font-size"));
return px / baseFontSize;
}
function emToPx(em, element) {
var baseFontSize = parseFloat($(element || "body").css("font-size"));
return Math.round(em * baseFontSize);
}
function initTree(myHierarchy)
{
// calculate the drawing area based on teh tree width and available screen size
var treeAreaHeight = visibleTreeArea > 800 ? 800 : visibleTreeArea;
let screenWidth = $('.content-header').width();
let treeWidth = (nodeWidth + 20) * parentNodesCount;
let treeAreaWidth = screenWidth < treeWidth ? treeWidth : screenWidth;
let baseFontSize = parseFloat($('html').css('font-size'));
let treeAreaHeight = ($(window).height() - 155); ;
// calculate the font size of the leaf nodes to fit everything into the tree area
leafNodesCount == 0 ? 1 : leafNodesCount;
emSize = pxToEm((treeAreaHeight/(leafNodesCount)).toFixed(2));
let screenWidthEm = pxToEm($('.networkTable').width());
// init the drawing area size
$("#networkTree").attr('style', `height:${treeAreaHeight}px; width:${treeAreaWidth}px`)
$("#networkTree").attr('style', `height:${treeAreaHeight}px; width:${emToPx(screenWidthEm)}px`)
if(myHierarchy.type == "")
{
@@ -733,13 +750,14 @@ function initTree(myHierarchy)
return;
}
// calculate the font size of the leaf nodes to fit everything into the tree area
leafNodesCount == 0 ? 1 : leafNodesCount;
emSize = ((treeAreaHeight/(25*leafNodesCount)).toFixed(2));
emSize = emSize > 1 ? 1 : emSize;
// handle if only a few nodes
emSize > 1 ? emSize = 1 : emSize = emSize;
// nodeHeight = ((emSize*100*0.30).toFixed(0))
nodeHeight = ((emSize*100*0.30).toFixed(0))
let nodeHeightPx = emToPx(emSize*1);
let nodeWidthPx = emToPx(screenWidthEm / (parentNodesCount));
// handle if only a few nodes
nodeWidthPx > 160 ? nodeWidthPx = 160 : nodeWidthPx = nodeWidthPx;
console.log(Treeviz);
@@ -747,8 +765,7 @@ function initTree(myHierarchy)
htmlId: "networkTree",
renderNode: nodeData => {
var fontSize = "font-size:"+emSize+"em;";
(!emptyArr.includes(nodeData.data.port )) ? port = nodeData.data.port : port = "";
(port == "" || port == 0 || port == 'None' ) ? portBckgIcon = `<i class="fa fa-wifi"></i>` : portBckgIcon = `<i class="fa fa-ethernet"></i>`;
@@ -761,10 +778,10 @@ function initTree(myHierarchy)
${atob(nodeData.data.icon)}
</div>` : "";
devicePort = `<div class="netPort"
style="width:${emSize*sizeCoefficient}em;height:${emSize*sizeCoefficient}em">
style="width:${emSize}em;height:${emSize}em">
${portHtml}</div>
<div class="portBckgIcon"
style="margin-left:-${emSize*sizeCoefficient}em;">
style="margin-left:-${emSize}em;">
${portBckgIcon}
</div>`;
collapseExpandIcon = nodeData.data.hiddenChildren ?
@@ -773,7 +790,7 @@ function initTree(myHierarchy)
// generate +/- icon if node has children nodes
collapseExpandHtml = nodeData.data.hasChildren ?
`<div class="netCollapse"
style="font-size:${emSize*sizeCoefficient}em;top:${emSize/6}em"
style="font-size:${nodeHeightPx/2}px;top:${nodeHeightPx/4}px"
data-mytreepath="${nodeData.data.path}"
data-mytreemac="${nodeData.data.mac}">
<i class="fa fa-${collapseExpandIcon} pointer"></i>
@@ -787,21 +804,24 @@ function initTree(myHierarchy)
// css indicating online/offline status
statusCss = ` netStatus-${nodeData.data.status}`;
return result = `<div class="box ${nodeData.data.hasChildren ? "pointer":""} ${statusCss} ${highlightedCss}"
return result = `<div
class="node-inner box ${nodeData.data.hasChildren ? "pointer":""} ${statusCss} ${highlightedCss}"
data-mytreemacmain="${nodeData.data.mac}"
style="height:${nodeData.settings.nodeHeight}px;${fontSize}"
style="height:${nodeHeightPx}px;font-size:${nodeHeightPx-5}px;"
onclick="handleNodeClick(this)"
>
<div class="netNodeText">
<strong>${devicePort} ${deviceIcon}
<span class="spanNetworkTree anonymizeDev" >${nodeData.data.name}</span>
</strong>
${collapseExpandHtml}
</div>
</div>`;
<span class="spanNetworkTree anonymizeDev" style="width:${nodeWidthPx-50}px">${nodeData.data.name}</span>
</strong>
</div>
</div>
${collapseExpandHtml}`;
},
mainAxisNodeSpacing: 'auto',
secondaryAxisNodeSpacing: 0.3,
nodeHeight: nodeHeight.toString(),
// secondaryAxisNodeSpacing: 0.3,
nodeHeight: nodeHeightPx,
nodeWidth: nodeWidthPx,
marginTop: '5',
isHorizontal : true,
hasZoom: true,
@@ -811,8 +831,8 @@ function initTree(myHierarchy)
hasFlatData: false,
relationnalField: "children",
linkWidth: (nodeData) => 3,
linkColor: (nodeData) => "#ffcc80",
onNodeClick: (nodeData) => handleNodeClick(nodeData),
linkColor: (nodeData) => "#ffcc80"
// onNodeClick: (nodeData) => handleNodeClick(nodeData),
});
console.log(deviceListGlobal);

View File

@@ -30,7 +30,7 @@
<div class="pull-right no-hidden-xs">
| <a href="https://gurubase.io/g/netalertx" class="pointer" target="_blank" title="Ask AI"><i class="fa-regular fa-comment-dots fa-flip-horizontal"></i></a>
| <a href="https://jokob-sk.github.io/NetAlertX/" class="pointer" target="_blank" title="Documentation"><i class="fa fa-book"></i></a>
| <a href="https://github.com/jokob-sk/NetAlertX/issues" class="pointer" target="_blank"><i class="fa-solid fa-bug" title="Report a bug"></i></a>
| <a href="https://github.com/jokob-sk/NetAlertX/issues" class="pointer" target="_blank"><i class="fa fa-bug" title="Report a bug"></i></a>
| <a href="https://discord.com/invite/NczTUTWyRr" class="pointer" target="_blank"><i class="fa-brands fa-discord" title="Join Discord"></i></a>
| <?= lang('Maintenance_built_on');?>: <?php include 'php/templates/build.php'; ?>
| Version: <?php include 'php/templates/version.php'; ?>

View File

@@ -59,10 +59,7 @@
<!-- Font Awesome -->
<link rel="stylesheet" href="lib/font-awesome/fontawesome.min.css">
<link rel="stylesheet" href="lib/font-awesome/solid.css">
<link rel="stylesheet" href="lib/font-awesome/brands.css">
<link rel="stylesheet" href="lib/font-awesome/v5-font-face.css">
<link rel="stylesheet" href="lib/font-awesome/all.min.css">
<!-- Ionicons -->
<link rel="stylesheet" href="lib/Ionicons/ionicons.min.css">
@@ -421,20 +418,15 @@
</li>
<!-- Integrations menu item -->
<li class=" treeview <?php if (in_array (basename($_SERVER['SCRIPT_NAME']), array('plugins.php', 'workflows.php', 'appEvents.php' ) ) ){ echo 'active menu-open'; } ?>">
<li class=" treeview <?php if (in_array (basename($_SERVER['SCRIPT_NAME']), array('plugins.php', 'appEvents.php' ) ) ){ echo 'active menu-open'; } ?>">
<a href="#">
<i class="fa fa-fw fa-plug"></i> <span><?= lang('Navigation_Integrations');?></span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu " style="display: <?php if (in_array (basename($_SERVER['SCRIPT_NAME']), array('plugins.php', 'workflows.php', 'appEvents.php' ) ) ){ echo 'block'; } else {echo 'none';} ?>;">
<ul class="treeview-menu " style="display: <?php if (in_array (basename($_SERVER['SCRIPT_NAME']), array('plugins.php', 'appEvents.php' ) ) ){ echo 'block'; } else {echo 'none';} ?>;">
<li>
<div class="info-icon-nav"> </div>
<a href="workflows.php"><?= lang('Navigation_Workflows');?></a>
</li>
<li>
<div class="info-icon-nav"> </div>
<a href="appEvents.php"><?= lang('Navigation_AppEvents');?></a>
</li>
<li>
@@ -443,6 +435,11 @@
</ul>
</li>
<!-- workflows menu item -->
<li class=" <?php if (in_array (basename($_SERVER['SCRIPT_NAME']), array('workflows.php') ) ){ echo 'active'; } ?>">
<a href="workflows.php"><i class="fa fa-fw fa-shuffle"></i> <span><?= lang('Navigation_Workflows');?></span></a>
</li>
<!-- system info menu item -->
<li class=" <?php if (in_array (basename($_SERVER['SCRIPT_NAME']), array('systeminfo.php') ) ){ echo 'active'; } ?>">
<a href="systeminfo.php"><i class="fa fa-fw fa-info-circle"></i> <span><?= lang('Navigation_SystemInfo');?></span></a>

View File

@@ -683,9 +683,15 @@
"WF_Condition_value": "",
"WF_Conditions": "",
"WF_Conditions_logic_rules": "",
"WF_Duplicate": "",
"WF_Enabled": "",
"WF_Export": "",
"WF_Export_Copy": "",
"WF_Import": "",
"WF_Import_Copy": "",
"WF_Name": "",
"WF_Remove": "",
"WF_Remove_Copy": "",
"WF_Save": "",
"WF_Trigger": "",
"WF_Trigger_event_type": "",

8
front/php/templates/language/ca_ca.json Normal file → Executable file
View File

@@ -683,9 +683,15 @@
"WF_Condition_value": "",
"WF_Conditions": "",
"WF_Conditions_logic_rules": "",
"WF_Duplicate": "",
"WF_Enabled": "",
"WF_Export": "",
"WF_Export_Copy": "",
"WF_Import": "",
"WF_Import_Copy": "",
"WF_Name": "",
"WF_Remove": "",
"WF_Remove_Copy": "",
"WF_Save": "",
"WF_Trigger": "",
"WF_Trigger_event_type": "",
@@ -736,4 +742,4 @@
"settings_update_item_warning": "Actualitza el valor sota. Sigues curós de seguir el format anterior. <b>No hi ha validació.</b>",
"test_event_icon": "fa-vial-circle-check",
"test_event_tooltip": "Deseu els canvis primer abans de comprovar la configuració."
}
}

View File

@@ -683,9 +683,15 @@
"WF_Condition_value": "",
"WF_Conditions": "",
"WF_Conditions_logic_rules": "",
"WF_Duplicate": "",
"WF_Enabled": "",
"WF_Export": "",
"WF_Export_Copy": "",
"WF_Import": "",
"WF_Import_Copy": "",
"WF_Name": "",
"WF_Remove": "",
"WF_Remove_Copy": "",
"WF_Save": "",
"WF_Trigger": "",
"WF_Trigger_event_type": "",

46
front/php/templates/language/de_de.json Normal file → Executable file
View File

@@ -16,8 +16,8 @@
"About_Design": "Entworfen für:",
"About_Exit": "Abmelden",
"About_Title": "Netzwerksicherheitsscanner und Benachrichtigungsframework",
"AppEvents_AppEventProcessed": "",
"AppEvents_DateTimeCreated": "protokolliert",
"AppEvents_AppEventProcessed": "Verarbeitet",
"AppEvents_DateTimeCreated": "Protokolliert",
"AppEvents_Extra": "Extra",
"AppEvents_GUID": "Anwendungsereignis-GUID",
"AppEvents_Helper1": "Helfer 1",
@@ -30,7 +30,7 @@
"AppEvents_ObjectPlugin": "Verknüpfte Plugins",
"AppEvents_ObjectPrimaryID": "Primär ID",
"AppEvents_ObjectSecondaryID": "Sekundär ID",
"AppEvents_ObjectStatus": "Status (zum Log-Zeitpunkt)",
"AppEvents_ObjectStatus": "Protokollierter Status",
"AppEvents_ObjectStatusColumn": "Statusspalte",
"AppEvents_ObjectType": "Objekttyp",
"AppEvents_Plugin": "Plugin",
@@ -237,7 +237,7 @@
"Device_TableHead_Name": "Name",
"Device_TableHead_NetworkSite": "Netzwerkseite",
"Device_TableHead_Owner": "Eigentümer",
"Device_TableHead_Parent_MAC": "Übergeordnete MAC",
"Device_TableHead_Parent_MAC": "Übergeordneter Netzwerkknoten",
"Device_TableHead_Port": "Port",
"Device_TableHead_PresentLastScan": "Anwesenheit",
"Device_TableHead_RowID": "Zeilen ID",
@@ -499,7 +499,7 @@
"NTFY_display_name": "NTFY",
"NTFY_icon": "<i class=\"fa fa-terminal\"></i>",
"Navigation_About": "Über",
"Navigation_AppEvents": "",
"Navigation_AppEvents": "App-Ereignisse",
"Navigation_Devices": "Geräte",
"Navigation_Donations": "Spenden",
"Navigation_Events": "Ereignisse",
@@ -753,28 +753,34 @@
"WF_Action_field": "",
"WF_Action_type": "",
"WF_Action_value": "",
"WF_Actions": "",
"WF_Actions": "Aktionen",
"WF_Add": "",
"WF_Add_Condition": "",
"WF_Add_Group": "",
"WF_Condition_field": "",
"WF_Condition_operator": "",
"WF_Condition_value": "",
"WF_Conditions": "",
"WF_Conditions_logic_rules": "",
"WF_Add_Condition": "Bedingung hinzufügen",
"WF_Add_Group": "Gruppe hinzufügen",
"WF_Condition_field": "Feld",
"WF_Condition_operator": "Betreiber",
"WF_Condition_value": "Wert",
"WF_Conditions": "Bedingungen",
"WF_Conditions_logic_rules": "Logikregeln",
"WF_Duplicate": "",
"WF_Enabled": "",
"WF_Export": "",
"WF_Export_Copy": "",
"WF_Import": "",
"WF_Import_Copy": "",
"WF_Name": "",
"WF_Remove": "",
"WF_Remove_Copy": "",
"WF_Save": "",
"WF_Trigger": "",
"WF_Trigger_event_type": "",
"WF_Trigger_type": "",
"WF_Trigger": "Auslöser",
"WF_Trigger_event_type": "Ereignistyp",
"WF_Trigger_type": "Auslösertyp",
"Webhooks_display_name": "Webhooks",
"Webhooks_icon": "<i class=\"fa fa-circle-nodes\"></i>",
"add_icon_event_icon": "",
"add_icon_event_tooltip": "",
"add_icon_event_tooltip": "Neues Symbol hinzufügen",
"add_option_event_icon": "",
"add_option_event_tooltip": "",
"add_option_event_tooltip": "Neuen Wert hinzufügen",
"copy_icons_event_icon": "",
"copy_icons_event_tooltip": "Icons aller Geräte mit demselben Gerätetyp überschreiben",
"devices_old": "Aktualisiert...",
@@ -782,7 +788,7 @@
"general_event_title": "",
"go_to_node_event_icon": "",
"go_to_node_event_tooltip": "",
"new_version_available": "",
"new_version_available": "Es ist eine neue Version verfügbar.",
"report_guid": "",
"report_guid_missing": "",
"report_select_format": "Format auswählen:",
@@ -817,4 +823,4 @@
"settings_update_item_warning": "",
"test_event_icon": "",
"test_event_tooltip": "Speichere die Änderungen, bevor Sie die Einstellungen testen."
}
}

View File

@@ -683,9 +683,15 @@
"WF_Condition_value": "Value",
"WF_Conditions": "Conditions",
"WF_Conditions_logic_rules": "Logic rules",
"WF_Duplicate": "Duplicate Workflow",
"WF_Enabled": "Workflow enabled",
"WF_Export": "Export Workflow",
"WF_Export_Copy": "Copy the below workflow and import it where needed.",
"WF_Import": "Import Workflow",
"WF_Import_Copy": "Paste in the workflow you copied previously.",
"WF_Name": "Workflow name",
"WF_Remove": "Remove Workflow",
"WF_Remove_Copy": "Do you want to remove this workflow?",
"WF_Save": "Save Workflows",
"WF_Trigger": "Trigger",
"WF_Trigger_event_type": "Event type",

8
front/php/templates/language/es_es.json Normal file → Executable file
View File

@@ -759,9 +759,15 @@
"WF_Condition_value": "",
"WF_Conditions": "",
"WF_Conditions_logic_rules": "",
"WF_Duplicate": "",
"WF_Enabled": "",
"WF_Export": "",
"WF_Export_Copy": "",
"WF_Import": "",
"WF_Import_Copy": "",
"WF_Name": "",
"WF_Remove": "",
"WF_Remove_Copy": "",
"WF_Save": "",
"WF_Trigger": "",
"WF_Trigger_event_type": "",
@@ -815,4 +821,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>",
"test_event_icon": "fa-vial-circle-check",
"test_event_tooltip": "Guarda tus cambios antes de probar nuevos ajustes."
}
}

54
front/php/templates/language/fr_fr.json Normal file → Executable file
View File

@@ -22,7 +22,7 @@
"AppEvents_ObjectPlugin": "Plugin lié",
"AppEvents_ObjectPrimaryID": "Identité primaire",
"AppEvents_ObjectSecondaryID": "Identité secondaire",
"AppEvents_ObjectStatus": "État (au moment de l'enregistrement)",
"AppEvents_ObjectStatus": "État enregistré",
"AppEvents_ObjectStatusColumn": "Colonne d'état",
"AppEvents_ObjectType": "Type d'objet",
"AppEvents_Plugin": "Plugin",
@@ -363,8 +363,8 @@
"Maintenance_Title": "Outils de maintenance",
"Maintenance_Tool_DownloadConfig": "Export des paramètres",
"Maintenance_Tool_DownloadConfig_text": "Télécharger une sauvegarde complète de vos paramètres stockés dans le fichier <code>app.conf</code>.",
"Maintenance_Tool_DownloadWorkflows": "",
"Maintenance_Tool_DownloadWorkflows_text": "",
"Maintenance_Tool_DownloadWorkflows": "Export des workflows",
"Maintenance_Tool_DownloadWorkflows_text": "Télécharger une sauvegarde complète de vos workflows enregistrés dans le fichier <code>workflows.json</code>.",
"Maintenance_Tool_ExportCSV": "Export des appareils (csv)",
"Maintenance_Tool_ExportCSV_noti": "Export des appareils (csv)",
"Maintenance_Tool_ExportCSV_noti_text": "Êtes-vous sûr de vouloir générer un fichier CSV?",
@@ -670,26 +670,32 @@
"UI_REFRESH_name": "Rafraîchir automatiquement l'interface graphique",
"VERSION_description": "Valeur de la version ou du timestamp d'aide à vérifier si l'application a été mise à jour.",
"VERSION_name": "Version ou Timestamp",
"WF_Action_Add": "",
"WF_Action_field": "",
"WF_Action_type": "",
"WF_Action_value": "",
"WF_Actions": "",
"WF_Add": "",
"WF_Add_Condition": "",
"WF_Add_Group": "",
"WF_Condition_field": "",
"WF_Condition_operator": "",
"WF_Condition_value": "",
"WF_Conditions": "",
"WF_Conditions_logic_rules": "",
"WF_Enabled": "",
"WF_Name": "",
"WF_Remove": "",
"WF_Save": "",
"WF_Trigger": "",
"WF_Trigger_event_type": "",
"WF_Trigger_type": "",
"WF_Action_Add": "Ajouter une action",
"WF_Action_field": "Champ",
"WF_Action_type": "Type",
"WF_Action_value": "Valeur",
"WF_Actions": "Actions",
"WF_Add": "Ajouter un workflow",
"WF_Add_Condition": "Ajouter une condition",
"WF_Add_Group": "Ajouter un groupe",
"WF_Condition_field": "Champ",
"WF_Condition_operator": "Opérateur",
"WF_Condition_value": "Valeur",
"WF_Conditions": "Conditions",
"WF_Conditions_logic_rules": "Règles logiques",
"WF_Duplicate": "",
"WF_Enabled": "Workflow activé",
"WF_Export": "",
"WF_Export_Copy": "",
"WF_Import": "",
"WF_Import_Copy": "",
"WF_Name": "Nom du workflow",
"WF_Remove": "Supprimer le workflow",
"WF_Remove_Copy": "",
"WF_Save": "Enregistrer les workflows",
"WF_Trigger": "Déclencheur",
"WF_Trigger_event_type": "Type d'événement",
"WF_Trigger_type": "Type de déclencheur",
"add_icon_event_icon": "fa-square-plus",
"add_icon_event_tooltip": "Ajouter une nouvelle icône",
"add_option_event_icon": "fa-square-plus",
@@ -736,4 +742,4 @@
"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": "fa-vial-circle-check",
"test_event_tooltip": "Enregistrer d'abord vos modifications avant de tester vôtre paramétrage."
}
}

60
front/php/templates/language/it_it.json Normal file → Executable file
View File

@@ -8,7 +8,7 @@
"About_Design": "Progettato per:",
"About_Exit": "Esci",
"About_Title": "Scanner di sicurezza di rete e framework di notifica",
"AppEvents_AppEventProcessed": "",
"AppEvents_AppEventProcessed": "Elaborato",
"AppEvents_DateTimeCreated": "Loggato",
"AppEvents_Extra": "Extra",
"AppEvents_GUID": "GUID evento applicazione",
@@ -22,7 +22,7 @@
"AppEvents_ObjectPlugin": "Plugin collegato",
"AppEvents_ObjectPrimaryID": "ID primario",
"AppEvents_ObjectSecondaryID": "ID secondario",
"AppEvents_ObjectStatus": "Stato (al momento del log)",
"AppEvents_ObjectStatus": "Stato registrato",
"AppEvents_ObjectStatusColumn": "Colonna di stato",
"AppEvents_ObjectType": "Tipo oggetto",
"AppEvents_Plugin": "Plugin",
@@ -225,7 +225,7 @@
"Device_TableHead_Name": "Nome",
"Device_TableHead_NetworkSite": "Sito di rete",
"Device_TableHead_Owner": "Proprietario",
"Device_TableHead_Parent_MAC": "MAC del nodo principale",
"Device_TableHead_Parent_MAC": "Nodo di rete principale",
"Device_TableHead_Port": "Porta",
"Device_TableHead_PresentLastScan": "Presenza",
"Device_TableHead_RowID": "ID riga",
@@ -363,8 +363,8 @@
"Maintenance_Title": "Strumenti di manutenzione",
"Maintenance_Tool_DownloadConfig": "Impostazioni Esporta",
"Maintenance_Tool_DownloadConfig_text": "Scarica un backup completo della configurazione delle tue Impostazioni memorizzata nel file <code>app.conf</code>.",
"Maintenance_Tool_DownloadWorkflows": "",
"Maintenance_Tool_DownloadWorkflows_text": "",
"Maintenance_Tool_DownloadWorkflows": "Esportazione flussi di lavoro",
"Maintenance_Tool_DownloadWorkflows_text": "Scarica un backup completo dei tuoi flussi di lavoro archiviati nel file <code>workflows.json</code>.",
"Maintenance_Tool_ExportCSV": "Esporta dispositivi (csv)",
"Maintenance_Tool_ExportCSV_noti": "Esporta dispositivi (csv)",
"Maintenance_Tool_ExportCSV_noti_text": "Sei sicuro di voler generare un file CSV?",
@@ -463,7 +463,7 @@
"NETWORK_DEVICE_TYPES_description": "Quali tipi di dispositivo possono essere utilizzati come dispositivi di rete nella vista Rete. Il tipo di dispositivo deve corrispondere esattamente all'impostazione <code>Tipo</code> su un dispositivo specifico nei Dettagli dispositivo. Aggiungilo sul Dispositivo tramite il pulsante <code>+</code>. Non rimuovere i tipi esistenti, aggiungine solo di nuovi.",
"NETWORK_DEVICE_TYPES_name": "Tipi di dispositivi di rete",
"Navigation_About": "Informazioni su",
"Navigation_AppEvents": "",
"Navigation_AppEvents": "Eventi app",
"Navigation_Devices": "Dispositivi",
"Navigation_Donations": "Donazioni",
"Navigation_Events": "Eventi",
@@ -670,26 +670,32 @@
"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",
"WF_Action_Add": "",
"WF_Action_field": "",
"WF_Action_type": "",
"WF_Action_value": "",
"WF_Actions": "",
"WF_Add": "",
"WF_Add_Condition": "",
"WF_Add_Group": "",
"WF_Condition_field": "",
"WF_Condition_operator": "",
"WF_Condition_value": "",
"WF_Conditions": "",
"WF_Conditions_logic_rules": "",
"WF_Enabled": "",
"WF_Name": "",
"WF_Remove": "",
"WF_Save": "",
"WF_Trigger": "",
"WF_Trigger_event_type": "",
"WF_Trigger_type": "",
"WF_Action_Add": "Aggiungi azione",
"WF_Action_field": "Campo",
"WF_Action_type": "Tipo",
"WF_Action_value": "Valore",
"WF_Actions": "Azioni",
"WF_Add": "Aggiungi flusso di lavoro",
"WF_Add_Condition": "Aggiungi condizione",
"WF_Add_Group": "Aggiungi gruppo",
"WF_Condition_field": "Campo",
"WF_Condition_operator": "Operatore",
"WF_Condition_value": "Valore",
"WF_Conditions": "Condizioni",
"WF_Conditions_logic_rules": "Regole logiche",
"WF_Duplicate": "",
"WF_Enabled": "Flusso di lavoro abilitato",
"WF_Export": "",
"WF_Export_Copy": "",
"WF_Import": "",
"WF_Import_Copy": "",
"WF_Name": "Nome flusso di lavoro",
"WF_Remove": "Rimuovi flusso di lavoro",
"WF_Remove_Copy": "",
"WF_Save": "Salva flussi di lavoro",
"WF_Trigger": "Trigger",
"WF_Trigger_event_type": "Tipo evento",
"WF_Trigger_type": "Tipo di trigger",
"add_icon_event_icon": "fa-square-plus",
"add_icon_event_tooltip": "Aggiungi nuova icona",
"add_option_event_icon": "fa-square-plus",
@@ -736,4 +742,4 @@
"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_tooltip": "Salva le modifiche prima di provare le nuove impostazioni."
}
}

8
front/php/templates/language/nb_no.json Normal file → Executable file
View File

@@ -683,9 +683,15 @@
"WF_Condition_value": "",
"WF_Conditions": "",
"WF_Conditions_logic_rules": "",
"WF_Duplicate": "",
"WF_Enabled": "",
"WF_Export": "",
"WF_Export_Copy": "",
"WF_Import": "",
"WF_Import_Copy": "",
"WF_Name": "",
"WF_Remove": "",
"WF_Remove_Copy": "",
"WF_Save": "",
"WF_Trigger": "",
"WF_Trigger_event_type": "",
@@ -736,4 +742,4 @@
"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_tooltip": "Lagre endringene først, før du tester innstillingene dine."
}
}

8
front/php/templates/language/pl_pl.json Normal file → Executable file
View File

@@ -683,9 +683,15 @@
"WF_Condition_value": "",
"WF_Conditions": "",
"WF_Conditions_logic_rules": "",
"WF_Duplicate": "",
"WF_Enabled": "",
"WF_Export": "",
"WF_Export_Copy": "",
"WF_Import": "",
"WF_Import_Copy": "",
"WF_Name": "",
"WF_Remove": "",
"WF_Remove_Copy": "",
"WF_Save": "",
"WF_Trigger": "",
"WF_Trigger_event_type": "",
@@ -736,4 +742,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>",
"test_event_icon": "fa-vial-circle-check",
"test_event_tooltip": "Zapisz zmiany zanim będziesz testować swoje ustawienia."
}
}

8
front/php/templates/language/pt_br.json Normal file → Executable file
View File

@@ -683,9 +683,15 @@
"WF_Condition_value": "",
"WF_Conditions": "",
"WF_Conditions_logic_rules": "",
"WF_Duplicate": "",
"WF_Enabled": "",
"WF_Export": "",
"WF_Export_Copy": "",
"WF_Import": "",
"WF_Import_Copy": "",
"WF_Name": "",
"WF_Remove": "",
"WF_Remove_Copy": "",
"WF_Save": "",
"WF_Trigger": "",
"WF_Trigger_event_type": "",
@@ -736,4 +742,4 @@
"settings_update_item_warning": "",
"test_event_icon": "",
"test_event_tooltip": "Guarde as alterações antes de testar as definições."
}
}

8
front/php/templates/language/ru_ru.json Normal file → Executable file
View File

@@ -683,9 +683,15 @@
"WF_Condition_value": "",
"WF_Conditions": "",
"WF_Conditions_logic_rules": "",
"WF_Duplicate": "",
"WF_Enabled": "",
"WF_Export": "",
"WF_Export_Copy": "",
"WF_Import": "",
"WF_Import_Copy": "",
"WF_Name": "",
"WF_Remove": "",
"WF_Remove_Copy": "",
"WF_Save": "",
"WF_Trigger": "",
"WF_Trigger_event_type": "",
@@ -736,4 +742,4 @@
"settings_update_item_warning": "Обновить значение ниже. Будьте осторожны, следуя предыдущему формату. <b>Проверка не выполняется.</b>",
"test_event_icon": "fa-vial-circle-check",
"test_event_tooltip": "Сначала сохраните изменения, прежде чем проверять настройки."
}
}

View File

@@ -683,9 +683,15 @@
"WF_Condition_value": "",
"WF_Conditions": "",
"WF_Conditions_logic_rules": "",
"WF_Duplicate": "",
"WF_Enabled": "",
"WF_Export": "",
"WF_Export_Copy": "",
"WF_Import": "",
"WF_Import_Copy": "",
"WF_Name": "",
"WF_Remove": "",
"WF_Remove_Copy": "",
"WF_Save": "",
"WF_Trigger": "",
"WF_Trigger_event_type": "",

View File

@@ -22,7 +22,7 @@
"AppEvents_ObjectPlugin": "Пов’язаний плагін",
"AppEvents_ObjectPrimaryID": "Основний ідентифікатор",
"AppEvents_ObjectSecondaryID": "Вторинний ідентифікатор",
"AppEvents_ObjectStatus": "Статус (під час журналу)",
"AppEvents_ObjectStatus": "Зареєстрований статус",
"AppEvents_ObjectStatusColumn": "Колонка статусу",
"AppEvents_ObjectType": "Тип об'єкта",
"AppEvents_Plugin": "Плагін",
@@ -363,8 +363,8 @@
"Maintenance_Title": "Інструменти обслуговування",
"Maintenance_Tool_DownloadConfig": "Експорт налаштувань",
"Maintenance_Tool_DownloadConfig_text": "Завантажте повну резервну копію конфігурації налаштувань, яка зберігається у файлі <code>app.conf</code>.",
"Maintenance_Tool_DownloadWorkflows": "",
"Maintenance_Tool_DownloadWorkflows_text": "",
"Maintenance_Tool_DownloadWorkflows": "Експорт робочих процесів",
"Maintenance_Tool_DownloadWorkflows_text": "Завантажте повну резервну копію робочих процесів, які зберігаються у файлі <code>workflows.json</code>.",
"Maintenance_Tool_ExportCSV": "Експорт пристроїв (csv)",
"Maintenance_Tool_ExportCSV_noti": "Експорт пристроїв (csv)",
"Maintenance_Tool_ExportCSV_noti_text": "Ви впевнені, що хочете створити файл CSV?",
@@ -670,26 +670,32 @@
"UI_REFRESH_name": "Автоматичне оновлення інтерфейсу користувача",
"VERSION_description": "Допоміжне значення версії або позначки часу, щоб перевірити, чи було оновлено додаток.",
"VERSION_name": "Версія або позначка часу",
"WF_Action_Add": "",
"WF_Action_field": "",
"WF_Action_type": "",
"WF_Action_value": "",
"WF_Actions": "",
"WF_Add": "",
"WF_Add_Condition": "",
"WF_Add_Group": "",
"WF_Condition_field": "",
"WF_Condition_operator": "",
"WF_Condition_value": "",
"WF_Conditions": "",
"WF_Conditions_logic_rules": "",
"WF_Enabled": "",
"WF_Name": "",
"WF_Remove": "",
"WF_Save": "",
"WF_Trigger": "",
"WF_Trigger_event_type": "",
"WF_Trigger_type": "",
"WF_Action_Add": "Додати дію",
"WF_Action_field": "Поле",
"WF_Action_type": "Тип",
"WF_Action_value": "Значення",
"WF_Actions": "Дії",
"WF_Add": "Додати робочий процес",
"WF_Add_Condition": "Додати умову",
"WF_Add_Group": "Додати групу",
"WF_Condition_field": "Поле",
"WF_Condition_operator": "Оператор",
"WF_Condition_value": "Значення",
"WF_Conditions": "Умови",
"WF_Conditions_logic_rules": "Логічні правила",
"WF_Duplicate": "Дубльований робочий процес",
"WF_Enabled": "Робочий процес увімкнено",
"WF_Export": "Робочий процес експорту",
"WF_Export_Copy": "Скопіюйте наведений нижче робочий процес і імпортуйте його, де потрібно.",
"WF_Import": "Робочий процес імпорту",
"WF_Import_Copy": "Вставте робочий процес, який ви скопіювали раніше.",
"WF_Name": "Назва робочого процесу",
"WF_Remove": "Видалити робочий процес",
"WF_Remove_Copy": "Ви хочете видалити цей робочий процес?",
"WF_Save": "Зберегти робочі процеси",
"WF_Trigger": "Тригер",
"WF_Trigger_event_type": "Тип події",
"WF_Trigger_type": "Тип тригера",
"add_icon_event_icon": "фа-квадрат-плюс",
"add_icon_event_tooltip": "додати новий значок",
"add_option_event_icon": "фа-квадрат-плюс",

8
front/php/templates/language/zh_cn.json Normal file → Executable file
View File

@@ -683,9 +683,15 @@
"WF_Condition_value": "",
"WF_Conditions": "",
"WF_Conditions_logic_rules": "",
"WF_Duplicate": "",
"WF_Enabled": "",
"WF_Export": "",
"WF_Export_Copy": "",
"WF_Import": "",
"WF_Import_Copy": "",
"WF_Name": "",
"WF_Remove": "",
"WF_Remove_Copy": "",
"WF_Save": "",
"WF_Trigger": "",
"WF_Trigger_event_type": "",
@@ -736,4 +742,4 @@
"settings_update_item_warning": "更新下面的值。请注意遵循先前的格式。<b>未执行验证。</b>",
"test_event_icon": "",
"test_event_tooltip": "在测试设置之前,请先保存更改。"
}
}

View File

@@ -11,19 +11,24 @@
</div>
<div id="buttons" class="bottom-buttons col-sm-12 col-xs-12">
<div class="add-workflow col-sm-12 col-xs-12">
<div class="add-workflow col-sm-4 col-xs-12">
<button type="button" class="btn btn-primary add-workflow-btn col-sm-12 col-xs-12" id="add">
<?= lang('WF_Add');?>
<i class="fa fa-fw fa-plus"></i> <?= lang('WF_Add');?>
</button>
</div>
<div class="save-workflows col-sm-12 col-xs-12">
<button type="button" class="btn btn-primary col-sm-12 col-xs-12" id="save" onclick="saveWorkflows()">
<?= lang('WF_Save');?>
<div class="import-wf col-sm-4 col-xs-12">
<button type="button" class="btn btn-primary col-sm-12 col-xs-12" id="import">
<i class="fa fa-fw fa-file-import"></i> <?= lang('WF_Import');?>
</button>
</div>
<div class="restart-app col-sm-12 col-xs-12">
<div class="restart-app col-sm-4 col-xs-12">
<button type="button" class="btn btn-primary col-sm-12 col-xs-12" id="save" onclick="askRestartBackend()">
<?= lang('Maint_RestartServer');?>
<i class="fa fa-fw fa-arrow-rotate-right"></i> <?= lang('Maint_RestartServer');?>
</button>
</div>
<div class="save-workflows col-xs-12">
<button type="button" class="btn btn-primary bg-green col-sm-12 col-xs-12" id="save" onclick="saveWorkflows()">
<i class="fa fa-fw fa-floppy-disk"></i> <?= lang('WF_Save');?>
</button>
</div>
</div>
@@ -45,6 +50,9 @@ let fieldOptions = [
let triggerTypes = [
"Devices"
];
let triggerEvents = [
"update", "insert", "delete"
];
let wfEnabledOptions = [
"Yes", "No"
@@ -108,6 +116,8 @@ function renderWorkflows() {
// Generate UI for a single workflow
function generateWorkflowUI(wf, wfIndex) {
let wfEnabled = (wf?.enabled ?? "No") == "Yes";
let $wfContainer = $("<div>", {
class: "workflow-card panel col-sm-12 col-sx-12",
id: `wf-${wfIndex}-container`
@@ -121,6 +131,11 @@ function generateWorkflowUI(wf, wfIndex) {
}
)
let $wfEnabledIcon = $("<i>", {
class: `alignRight fa-regular ${wfEnabled ? "fa-dot-circle" : "fa-circle" }`
});
let $wfHeaderLink = $("<a>",
{
"class": "pointer ",
@@ -137,7 +152,7 @@ function generateWorkflowUI(wf, wfIndex) {
}
).text(wf.name)
$wfContainer.append($wfHeaderLink.append($wfLinkWrap.append($wfHeaderHeading)));
$wfContainer.append($wfHeaderLink.append($wfLinkWrap.append($wfHeaderHeading.append($wfEnabledIcon))));
// Collapsible panel start
@@ -157,7 +172,7 @@ function generateWorkflowUI(wf, wfIndex) {
`[${wfIndex}].enabled`,
getString("WF_Enabled"),
wfEnabledOptions,
wf?.enabled ?? "No",
wfEnabled ? "Yes" :"No",
`wf-${wfIndex}-enabled`
);
@@ -201,7 +216,7 @@ function generateWorkflowUI(wf, wfIndex) {
let $eventTypeDropdown = createEditableDropdown(
`[${wfIndex}].trigger.event_type`,
getString("WF_Trigger_event_type"),
["update", "create", "delete"],
triggerEvents,
wf.trigger.event_type,
`wf-${wfIndex}-trigger-event-type`
);
@@ -210,9 +225,10 @@ function generateWorkflowUI(wf, wfIndex) {
class: "fa-solid fa-bolt bckg-icon-2-line"
});
$triggerSection.append($triggerIcon);
$triggerSection.append($triggerTypeDropdown);
$triggerSection.append($eventTypeDropdown);
$triggerSection.append($triggerIcon);
$wfCollapsiblePanel.append($triggerSection);
// Conditions
@@ -323,11 +339,13 @@ function generateWorkflowUI(wf, wfIndex) {
$actionRemoveButtonWrap.append($actionRemoveButton);
let $actionIcon = $("<i>", {
class: `fa-solid fa-person-running fa-flip-horizontal bckg-icon-${numberOfLines}-line `
});
class: `fa-solid fa-person-running fa-flip-horizontal bckg-icon-${numberOfLines}-line `
});
$actionEl.prepend($actionIcon)
$actionElWrap.append($actionEl)
$actionElWrap.append($actionIcon)
$actionElWrap.append($actionRemoveButtonWrap)
$actionsContainer.append($actionElWrap);
@@ -350,7 +368,7 @@ function generateWorkflowUI(wf, wfIndex) {
$actionsContainer.append($actionAddButtonWrap)
let $wfRemoveButtonWrap = $("<div>", { class: "button-container col-sm-12 col-sx-12" });
let $wfRemoveButtonWrap = $("<div>", { class: "button-container col-sm-4 col-sx-12" });
let $wfRemoveIcon = $("<i>", {
class: "fa-solid fa-trash"
@@ -362,10 +380,40 @@ function generateWorkflowUI(wf, wfIndex) {
})
.append($wfRemoveIcon) // Add icon
.append(` ${getString("WF_Remove")}`); // Add text
let $wfDuplicateButtonWrap = $("<div>", { class: "button-container col-sm-4 col-sx-12" });
let $wfDuplicateIcon = $("<i>", {
class: "fa-solid fa-copy"
});
let $wfDuplicateButton = $("<div>", {
class: "pointer duplicate-wf green-hover-text",
wfIndex: wfIndex
})
.append($wfDuplicateIcon) // Add icon
.append(` ${getString("WF_Duplicate")}`); // Add text
let $wfExportButtonWrap = $("<div>", { class: "button-container col-sm-4 col-sx-12" });
let $wfExportIcon = $("<i>", {
class: "fa-solid fa-file-export"
});
let $wfExportButton = $("<div>", {
class: "pointer export-wf green-hover-text",
wfIndex: wfIndex
})
.append($wfExportIcon) // Add icon
.append(` ${getString("WF_Export")}`); // Add text
$wfCollapsiblePanel.append($actionsContainer);
$wfCollapsiblePanel.append($wfDuplicateButtonWrap.append($wfDuplicateButton))
$wfCollapsiblePanel.append($wfExportButtonWrap.append($wfExportButton))
$wfCollapsiblePanel.append($wfRemoveButtonWrap.append($wfRemoveButton))
$wfContainer.append($wfCollapsiblePanel)
@@ -377,7 +425,7 @@ function generateWorkflowUI(wf, wfIndex) {
// Render conditions recursively
function renderConditions(wfIndex, parentIndexPath, conditionGroupsIndex, conditions) {
let $conditionList = $("<div>", {
class: "condition-list panel panel-secondary col-sm-12 col-sx-12",
class: "condition-list panel col-sm-12 col-sx-12",
parentIndexPath: parentIndexPath
});
@@ -755,7 +803,62 @@ function addWorkflow(workflows) {
// Function to remove a Workflow
function removeWorkflow(workflows, wfIndex) {
workflows.splice(wfIndex, 1);
showModalWarning ('<?= lang('WF_Remove');?>', '<?= lang('WF_Remove_Copy');?>',
'<?= lang('Gen_Cancel');?>', '<?= lang('Gen_Delete');?>', `executeRemoveWorkflow`, wfIndex);
}
// ---------------------------------------------------
// Function to execute the remove of a Workflow
function executeRemoveWorkflow() {
workflows = getWorkflowsJson()
workflows.splice($('#modal-warning').attr("data-myparam-triggered-by"), 1);
updateWorkflowsJson(workflows)
// Re-render the UI
renderWorkflows();
}
// ---------------------------------------------------
// Function to duplicate a Workflow
function duplicateWorkflow(workflows, wfIndex) {
workflows.push(workflows[wfIndex])
updateWorkflowsJson(workflows)
// Re-render the UI
renderWorkflows();
}
// ---------------------------------------------------
// Function to export a Workflow
function exportWorkflow(workflows, wfIndex) {
// Add new icon as base64 string
showModalInput ('<i class="fa fa-file-export pointer"></i> <?= lang('WF_Export');?>', '<?= lang('WF_Export_Copy');?>',
'<?= lang('Gen_Cancel');?>', '<?= lang('Gen_Okay');?>', null, null, JSON.stringify(workflows[wfIndex], null, 2));
}
// ---------------------------------------------------
// Function to import a Workflow
function importWorkflow(workflows, wfIndex) {
// Add new icon as base64 string
showModalInput ('<i class="fa fa-file-import pointer"></i> <?= lang('WF_Import');?>', '<?= lang('WF_Import_Copy');?>',
'<?= lang('Gen_Cancel');?>', '<?= lang('Gen_Okay');?>', 'importWorkflowExecute', null, "" );
}
function importWorkflowExecute()
{
var json = JSON.parse($('#modal-input-textarea').val());
workflows = getWorkflowsJson()
workflows.push(json);
updateWorkflowsJson(workflows)
@@ -1009,6 +1112,21 @@ $(document).on("click", ".remove-wf", function () {
removeWorkflow(getWorkflowsJson(), wfIndex);
});
$(document).on("click", ".duplicate-wf", function () {
let wfIndex = $(this).attr("wfindex");
duplicateWorkflow(getWorkflowsJson(), wfIndex);
});
$(document).on("click", ".export-wf", function () {
let wfIndex = $(this).attr("wfindex");
exportWorkflow(getWorkflowsJson(), wfIndex);
});
$(document).on("click", ".import-wf", function () {
let wfIndex = $(this).attr("wfindex");
importWorkflow(getWorkflowsJson(), wfIndex);
});
$(document).on("click", ".add-condition", function () {
let wfIndex = $(this).attr("wfindex");
let parentIndexPath = $(this).attr("parentIndexPath");

View File

@@ -542,8 +542,7 @@ class DB():
# Plugin state
sql_Plugins_Objects = """ CREATE TABLE IF NOT EXISTS Plugins_Objects(
"Index" INTEGER,
Plugin TEXT NOT NULL,
ObjectGUID TEXT,
Plugin TEXT NOT NULL,
Object_PrimaryID TEXT NOT NULL,
Object_SecondaryID TEXT NOT NULL,
DateTimeCreated TEXT NOT NULL,
@@ -561,6 +560,7 @@ class DB():
"HelpVal2" TEXT,
"HelpVal3" TEXT,
"HelpVal4" TEXT,
ObjectGUID TEXT,
PRIMARY KEY("Index" AUTOINCREMENT)
); """
self.sql.execute(sql_Plugins_Objects)

View File

@@ -797,7 +797,7 @@ class plugin_object_class:
def __init__(self, plugin, objDbRow):
self.index = objDbRow[0]
self.pluginPref = objDbRow[1]
self.primaryId = objDbRow[2]
self.primaryId = objDbRow[2]
self.secondaryId = objDbRow[3]
self.created = objDbRow[4] # can be null
self.changed = objDbRow[5] # never null (data coming from plugin)
@@ -819,7 +819,7 @@ class plugin_object_class:
# Check if self.status is valid
if self.status not in ["exists", "watched-changed", "watched-not-changed", "new", "not-processed", "missing-in-last-scan"]:
raise ValueError("Invalid status value for plugin object:", self.status)
raise ValueError(f"Invalid status value for plugin object ({self.pluginPref}|{self.primaryId}|{self.watched1}) invalid status: {self.status} on objDbRow:", objDbRow)
self.idsHash = str(hash(str(self.primaryId) + str(self.secondaryId)))
# self.idsHash = str(self.primaryId) + str(self.secondaryId)

View File

@@ -41,7 +41,7 @@ class Condition:
if self.operator == "equals":
result = str(obj_value) == str(self.value)
elif self.operator == "contains":
result = str(self.value) in str(obj_value)
result = str(self.value).lower() in str(obj_value).lower()
elif self.operator == "regex":
result = bool(re.match(self.value, str(obj_value)))
else: