🔌Plugins page rebuild with DataTables

This commit is contained in:
jokob-sk
2024-10-24 21:51:16 +11:00
parent 907a3e1df8
commit 4c46b27643
38 changed files with 1299 additions and 599 deletions

View File

@@ -18,9 +18,9 @@ There are 4 ways how to influence notifications:
There are 4 settings on the device for influencing notifications. You can: There are 4 settings on the device for influencing notifications. You can:
1. Completely disable the scanning of the device 1. **Scan device** - Completely disable the scanning of the device
2. **Alert all events**, connections, disconnections, IP changes (noisy, usually not recommended) 2. **Alert all events** - Enables extensive alerts of connections, disconnections, IP changes (noisy, usually not recommended)
3. **Alert down** - alerts when a device goes down. This setting overrides disabled Alert All Events, so you will get a notification of a device going down even if you don't have Alert All Events ticked. 3. **Alert down** - Alerts when a device goes down. This setting overrides disabled Alert All Events, so you will get a notification of a device going down even if you don't have **Alert All Events** ticked.
4. **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. 4. **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.
## Plugin settings 🔌 ## Plugin settings 🔌

View File

@@ -1208,7 +1208,7 @@ input[readonly] {
background-color:#606060 !important; background-color:#606060 !important;
} }
.networkPageHelp{ .helpIconSmallTopRight{
position: absolute; position: absolute;
font-size: x-small; font-size: x-small;
margin-bottom: 6px; margin-bottom: 6px;
@@ -1407,7 +1407,7 @@ input[readonly] {
.plugin-content #tabs-content-location .plugin-content #tabs-content-location
{ {
margin: 0px; margin: 0px;
padding-top: 0;
} }
.plugins-description .plugins-description
@@ -1462,6 +1462,33 @@ input[readonly] {
} }
.textOverflow
{
white-space: nowrap; /* Prevent text from wrapping to a new line */
overflow: hidden; /* Hide the overflowed text */
text-overflow: ellipsis; /* Show ellipsis (...) */
}
.table-stretched
{
min-width: -moz-available;
min-width: -webkit-fill-available;
}
.pluginBadge
{
float: right;
}
.pluginBadgeWrap
{
float: right;
display: ruby;
z-index: 1;
position: sticky;
margin-top: 1px;
}
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
Spin Spin
----------------------------------------------------------------------------- */ ----------------------------------------------------------------------------- */

View File

@@ -325,7 +325,7 @@
</div> </div>
<!-- Network --> <!-- Network -->
<h4 class="bottom-border-aqua"><?= lang('DevDetail_MainInfo_Network_Title');?><span class="networkPageHelp"> <a target="_blank" href="https://github.com/jokob-sk/NetAlertX/blob/main/docs/NETWORK_TREE.md"><i class="fa fa-circle-question"></i></a><span></h4> <h4 class="bottom-border-aqua"><?= lang('DevDetail_MainInfo_Network_Title');?><span class="helpIconSmallTopRight"> <a target="_blank" href="https://github.com/jokob-sk/NetAlertX/blob/main/docs/NETWORK_TREE.md"><i class="fa fa-circle-question"></i></a><span></h4>
<div class="form-group" title="<?= lang('DevDetail_Network_Node_hover');?>"> <div class="form-group" title="<?= lang('DevDetail_Network_Node_hover');?>">
<label class="col-sm-3 control-label"><?= lang('DevDetail_MainInfo_Network');?></label> <label class="col-sm-3 control-label"><?= lang('DevDetail_MainInfo_Network');?></label>
<div class="col-sm-9"> <div class="col-sm-9">
@@ -370,7 +370,8 @@
<!-- column 3 --> <!-- column 3 -->
<div class="col-lg-4 col-sm-6 col-xs-12"> <div class="col-lg-4 col-sm-6 col-xs-12">
<h4 class="bottom-border-aqua"><?= lang('DevDetail_EveandAl_Title');?></h4> <h4 class="bottom-border-aqua"><?= lang('DevDetail_EveandAl_Title');?>
<span class="helpIconSmallTopRight"> <a target="_blank" href="https://github.com/jokob-sk/NetAlertX/blob/main/docs/NOTIFICATIONS.md"><i class="fa fa-circle-question"></i></a><span></h4>
<div class="box-body form-horizontal"> <div class="box-body form-horizontal">
<!-- Scan Cycle --> <!-- Scan Cycle -->
@@ -455,7 +456,8 @@
<i style="font-size: 24px;" class="text-yellow glyphicon glyphicon-random"></i> &nbsp &nbsp </span> <i style="font-size: 24px;" class="text-yellow glyphicon glyphicon-random"></i> &nbsp &nbsp </span>
<a href="https://github.com/jokob-sk/NetAlertX/blob/main/docs/RANDOM_MAC.md" target="_blank" style="color: #777;"> <a href="https://github.com/jokob-sk/NetAlertX/blob/main/docs/RANDOM_MAC.md" target="_blank" style="color: #777;">
<i class="fa fa-info-circle"></i> </a> <i class="fa fa-info-circle"></i>
</a>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -167,6 +167,8 @@
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
function main () { function main () {
showSpinner();
//initialize the table headers in the correct order //initialize the table headers in the correct order
var availableColumns = getSettingOptions("UI_device_columns").split(","); var availableColumns = getSettingOptions("UI_device_columns").split(",");
var headersDefaultOrder = availableColumns.map(val => getString(val)); var headersDefaultOrder = availableColumns.map(val => getString(val));

View File

@@ -19,7 +19,7 @@
<?php require 'php/templates/notification.php'; ?> <?php require 'php/templates/notification.php'; ?>
<h1 id="pageTitle"> <h1 id="pageTitle">
<i class="fa fa-network-wired"></i> <?= lang('Network_Title');?> <i class="fa fa-network-wired"></i> <?= lang('Network_Title');?>
<span class="networkPageHelp"> <a target="_blank" href="https://github.com/jokob-sk/NetAlertX/blob/main/docs/NETWORK_TREE.md"><i class="fa fa-circle-question"></i></a><span> <span class="helpIconSmallTopRight"> <a target="_blank" href="https://github.com/jokob-sk/NetAlertX/blob/main/docs/NETWORK_TREE.md"><i class="fa fa-circle-question"></i></a><span>
</h1> </h1>
</section> </section>

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

View File

@@ -313,6 +313,21 @@
} }
], ],
"database_column_definitions": [ "database_column_definitions": [
{
"column": "Index",
"css_classes": "col-sm-2",
"show": true,
"type": "none",
"default_value": "",
"options": [],
"localized": ["name"],
"name": [
{
"language_code": "en_us",
"string": "Index"
}
]
},
{ {
"column": "Object_PrimaryID", "column": "Object_PrimaryID",
"mapped_to_column": "cur_MAC", "mapped_to_column": "cur_MAC",

View File

@@ -33,19 +33,15 @@
{ {
"column": "Index", "column": "Index",
"css_classes": "col-sm-2", "css_classes": "col-sm-2",
"show": false, "show": true,
"type": "label", "type": "none",
"default_value": "", "default_value": "",
"options": [], "options": [],
"localized": ["name"], "localized": ["name"],
"name": [ "name": [
{ {
"language_code": "en_us", "language_code": "en_us",
"string": "N/A" "string": "Index"
},
{
"language_code": "es_es",
"string": "N/A"
} }
] ]
}, },
@@ -104,7 +100,7 @@
}, },
{ {
"column": "DateTimeCreated", "column": "DateTimeCreated",
"css_classes": "col-sm-2", "css_classes": "col-sm-3",
"show": true, "show": true,
"type": "label", "type": "label",
"default_value": "", "default_value": "",
@@ -145,7 +141,7 @@
"options": [ "options": [
{ {
"type": "eval", "type": "eval",
"param": "`<a href='/report.php?guid=${value}'>${value}</a>`" "param": "`<a href='/report.php?guid=${value}'>Link</a>`"
} }
], ],
"localized": ["name"], "localized": ["name"],

View File

@@ -33,19 +33,15 @@
{ {
"column": "Index", "column": "Index",
"css_classes": "col-sm-2", "css_classes": "col-sm-2",
"show": false, "show": true,
"type": "label", "type": "none",
"default_value": "", "default_value": "",
"options": [], "options": [],
"localized": ["name"], "localized": ["name"],
"name": [ "name": [
{ {
"language_code": "en_us", "language_code": "en_us",
"string": "N/A" "string": "Index"
},
{
"language_code": "es_es",
"string": "N/A"
} }
] ]
}, },

View File

@@ -49,19 +49,15 @@
{ {
"column": "Index", "column": "Index",
"css_classes": "col-sm-2", "css_classes": "col-sm-2",
"show": false, "show": true,
"type": "label", "type": "none",
"default_value": "", "default_value": "",
"options": [], "options": [],
"localized": ["name"], "localized": ["name"],
"name": [ "name": [
{ {
"language_code": "en_us", "language_code": "en_us",
"string": "N/A" "string": "Index"
},
{
"language_code": "es_es",
"string": "N/A"
} }
] ]
}, },

View File

@@ -33,19 +33,15 @@
{ {
"column": "Index", "column": "Index",
"css_classes": "col-sm-2", "css_classes": "col-sm-2",
"show": false, "show": true,
"type": "label", "type": "none",
"default_value": "", "default_value": "",
"options": [], "options": [],
"localized": ["name"], "localized": ["name"],
"name": [ "name": [
{ {
"language_code": "en_us", "language_code": "en_us",
"string": "N/A" "string": "Index"
},
{
"language_code": "es_es",
"string": "N/A"
} }
] ]
}, },

View File

@@ -33,19 +33,15 @@
{ {
"column": "Index", "column": "Index",
"css_classes": "col-sm-2", "css_classes": "col-sm-2",
"show": false, "show": true,
"type": "label", "type": "none",
"default_value": "", "default_value": "",
"options": [], "options": [],
"localized": ["name"], "localized": ["name"],
"name": [ "name": [
{ {
"language_code": "en_us", "language_code": "en_us",
"string": "N/A" "string": "Index"
},
{
"language_code": "es_es",
"string": "N/A"
} }
] ]
}, },

View File

@@ -33,19 +33,15 @@
{ {
"column": "Index", "column": "Index",
"css_classes": "col-sm-2", "css_classes": "col-sm-2",
"show": false, "show": true,
"type": "label", "type": "none",
"default_value": "", "default_value": "",
"options": [], "options": [],
"localized": ["name"], "localized": ["name"],
"name": [ "name": [
{ {
"language_code": "en_us", "language_code": "en_us",
"string": "N/A" "string": "Index"
},
{
"language_code": "es_es",
"string": "N/A"
} }
] ]
}, },

View File

@@ -29,19 +29,15 @@
{ {
"column": "Index", "column": "Index",
"css_classes": "col-sm-2", "css_classes": "col-sm-2",
"show": false, "show": true,
"type": "label", "type": "none",
"default_value": "", "default_value": "",
"options": [], "options": [],
"localized": ["name"], "localized": ["name"],
"name": [ "name": [
{ {
"language_code": "en_us", "language_code": "en_us",
"string": "N/A" "string": "Index"
},
{
"language_code": "es_es",
"string": "N/A"
} }
] ]
}, },

View File

@@ -33,19 +33,15 @@
{ {
"column": "Index", "column": "Index",
"css_classes": "col-sm-2", "css_classes": "col-sm-2",
"show": false, "show": true,
"type": "label", "type": "none",
"default_value": "", "default_value": "",
"options": [], "options": [],
"localized": ["name"], "localized": ["name"],
"name": [ "name": [
{ {
"language_code": "en_us", "language_code": "en_us",
"string": "N/A" "string": "Index"
},
{
"language_code": "es_es",
"string": "N/A"
} }
] ]
}, },

View File

@@ -367,6 +367,21 @@
} }
], ],
"database_column_definitions": [ "database_column_definitions": [
{
"column": "Index",
"css_classes": "col-sm-2",
"show": true,
"type": "none",
"default_value": "",
"options": [],
"localized": ["name"],
"name": [
{
"language_code": "en_us",
"string": "Index"
}
]
},
{ {
"column": "Object_PrimaryID", "column": "Object_PrimaryID",
"mapped_to_column": "cur_MAC", "mapped_to_column": "cur_MAC",

View File

@@ -205,6 +205,21 @@
} }
], ],
"database_column_definitions": [ "database_column_definitions": [
{
"column": "Index",
"css_classes": "col-sm-2",
"show": true,
"type": "none",
"default_value": "",
"options": [],
"localized": ["name"],
"name": [
{
"language_code": "en_us",
"string": "Index"
}
]
},
{ {
"column": "Object_PrimaryID", "column": "Object_PrimaryID",
"css_classes": "col-sm-2", "css_classes": "col-sm-2",

View File

@@ -498,6 +498,21 @@
} }
], ],
"database_column_definitions": [ "database_column_definitions": [
{
"column": "Index",
"css_classes": "col-sm-2",
"show": true,
"type": "none",
"default_value": "",
"options": [],
"localized": ["name"],
"name": [
{
"language_code": "en_us",
"string": "Index"
}
]
},
{ {
"column": "Object_PrimaryID", "column": "Object_PrimaryID",
"css_classes": "col-sm-2", "css_classes": "col-sm-2",

View File

@@ -66,23 +66,15 @@
{ {
"column": "Index", "column": "Index",
"css_classes": "col-sm-2", "css_classes": "col-sm-2",
"show": false, "show": true,
"type": "label", "type": "none",
"default_value": "", "default_value": "",
"options": [], "options": [],
"localized": ["name"], "localized": ["name"],
"name": [ "name": [
{ {
"language_code": "en_us", "language_code": "en_us",
"string": "N/A" "string": "Index"
},
{
"language_code": "es_es",
"string": "N/A"
},
{
"language_code": "de_de",
"string": "N/A"
} }
] ]
}, },

View File

@@ -42,19 +42,15 @@
{ {
"column": "Index", "column": "Index",
"css_classes": "col-sm-2", "css_classes": "col-sm-2",
"show": false, "show": true,
"type": "label", "type": "none",
"default_value": "", "default_value": "",
"options": [], "options": [],
"localized": ["name"], "localized": ["name"],
"name": [ "name": [
{ {
"language_code": "en_us", "language_code": "en_us",
"string": "N/A" "string": "Index"
},
{
"language_code": "es_es",
"string": "N/A"
} }
] ]
}, },

View File

@@ -390,6 +390,21 @@
} }
], ],
"database_column_definitions": [ "database_column_definitions": [
{
"column": "Index",
"css_classes": "col-sm-2",
"show": true,
"type": "none",
"default_value": "",
"options": [],
"localized": ["name"],
"name": [
{
"language_code": "en_us",
"string": "Index"
}
]
},
{ {
"column": "Object_PrimaryID", "column": "Object_PrimaryID",
"mapped_to_column": "cur_MAC", "mapped_to_column": "cur_MAC",

View File

@@ -41,23 +41,15 @@
{ {
"column": "Index", "column": "Index",
"css_classes": "col-sm-2", "css_classes": "col-sm-2",
"show": false, "show": true,
"type": "label", "type": "none",
"default_value": "", "default_value": "",
"options": [], "options": [],
"localized": ["name"], "localized": ["name"],
"name": [ "name": [
{ {
"language_code": "en_us", "language_code": "en_us",
"string": "N/A" "string": "Index"
},
{
"language_code": "es_es",
"string": "N/A"
},
{
"language_code": "de_de",
"string": "N/A"
} }
] ]
}, },

View File

@@ -253,6 +253,21 @@
} }
], ],
"database_column_definitions": [ "database_column_definitions": [
{
"column": "Index",
"css_classes": "col-sm-2",
"show": true,
"type": "none",
"default_value": "",
"options": [],
"localized": ["name"],
"name": [
{
"language_code": "en_us",
"string": "Index"
}
]
},
{ {
"column": "Object_PrimaryID", "column": "Object_PrimaryID",
"mapped_to_column": "cur_MAC", "mapped_to_column": "cur_MAC",

View File

@@ -213,6 +213,21 @@
} }
], ],
"database_column_definitions": [ "database_column_definitions": [
{
"column": "Index",
"css_classes": "col-sm-2",
"show": true,
"type": "none",
"default_value": "",
"options": [],
"localized": ["name"],
"name": [
{
"language_code": "en_us",
"string": "Index"
}
]
},
{ {
"column": "Object_PrimaryID", "column": "Object_PrimaryID",
"css_classes": "col-sm-2", "css_classes": "col-sm-2",

View File

@@ -343,6 +343,21 @@
} }
], ],
"database_column_definitions": [ "database_column_definitions": [
{
"column": "Index",
"css_classes": "col-sm-2",
"show": true,
"type": "none",
"default_value": "",
"options": [],
"localized": ["name"],
"name": [
{
"language_code": "en_us",
"string": "Index"
}
]
},
{ {
"column": "Object_PrimaryID", "column": "Object_PrimaryID",
"mapped_to_column": "cur_MAC", "mapped_to_column": "cur_MAC",

View File

@@ -74,15 +74,15 @@
{ {
"column": "Index", "column": "Index",
"css_classes": "col-sm-2", "css_classes": "col-sm-2",
"show": false, "show": true,
"type": "label", "type": "none",
"default_value": "", "default_value": "",
"options": [], "options": [],
"localized": ["name"], "localized": ["name"],
"name": [ "name": [
{ {
"language_code": "en_us", "language_code": "en_us",
"string": "N/A" "string": "Index"
} }
] ]
}, },

View File

@@ -213,6 +213,21 @@
} }
], ],
"database_column_definitions": [ "database_column_definitions": [
{
"column": "Index",
"css_classes": "col-sm-2",
"show": true,
"type": "none",
"default_value": "",
"options": [],
"localized": ["name"],
"name": [
{
"language_code": "en_us",
"string": "Index"
}
]
},
{ {
"column": "Object_PrimaryID", "column": "Object_PrimaryID",
"css_classes": "col-sm-2", "css_classes": "col-sm-2",

View File

@@ -447,6 +447,21 @@
} }
], ],
"database_column_definitions": [ "database_column_definitions": [
{
"column": "Index",
"css_classes": "col-sm-2",
"show": true,
"type": "none",
"default_value": "",
"options": [],
"localized": ["name"],
"name": [
{
"language_code": "en_us",
"string": "Index"
}
]
},
{ {
"column": "Object_PrimaryID", "column": "Object_PrimaryID",
"mapped_to_column": "cur_MAC", "mapped_to_column": "cur_MAC",

View File

@@ -323,6 +323,21 @@
} }
], ],
"database_column_definitions": [ "database_column_definitions": [
{
"column": "Index",
"css_classes": "col-sm-2",
"show": true,
"type": "none",
"default_value": "",
"options": [],
"localized": ["name"],
"name": [
{
"language_code": "en_us",
"string": "Index"
}
]
},
{ {
"column": "Object_PrimaryID", "column": "Object_PrimaryID",
"mapped_to_column": "MAC", "mapped_to_column": "MAC",

View File

@@ -278,6 +278,21 @@
], ],
"database_column_definitions": [ "database_column_definitions": [
{
"column": "Index",
"css_classes": "col-sm-2",
"show": true,
"type": "none",
"default_value": "",
"options": [],
"localized": ["name"],
"name": [
{
"language_code": "en_us",
"string": "Index"
}
]
},
{ {
"column": "Object_PrimaryID", "column": "Object_PrimaryID",
"mapped_to_column": "cur_MAC", "mapped_to_column": "cur_MAC",

View File

@@ -66,19 +66,15 @@
{ {
"column": "Index", "column": "Index",
"css_classes": "col-sm-2", "css_classes": "col-sm-2",
"show": false, "show": true,
"type": "label", "type": "none",
"default_value": "", "default_value": "",
"options": [], "options": [],
"localized": ["name"], "localized": ["name"],
"name": [ "name": [
{ {
"language_code": "en_us", "language_code": "en_us",
"string": "N/A" "string": "Index"
},
{
"language_code": "es_es",
"string": "N/A"
} }
] ]
}, },

View File

@@ -471,6 +471,21 @@
} }
], ],
"database_column_definitions": [ "database_column_definitions": [
{
"column": "Index",
"css_classes": "col-sm-2",
"show": true,
"type": "none",
"default_value": "",
"options": [],
"localized": ["name"],
"name": [
{
"language_code": "en_us",
"string": "Index"
}
]
},
{ {
"column": "Object_PrimaryID", "column": "Object_PrimaryID",
"mapped_to_column": "cur_MAC", "mapped_to_column": "cur_MAC",

View File

@@ -385,6 +385,21 @@
} }
], ],
"database_column_definitions": [ "database_column_definitions": [
{
"column": "Index",
"css_classes": "col-sm-2",
"show": true,
"type": "none",
"default_value": "",
"options": [],
"localized": ["name"],
"name": [
{
"language_code": "en_us",
"string": "Index"
}
]
},
{ {
"column": "Watched_Value1", "column": "Watched_Value1",
"mapped_to_column": "cur_Name", "mapped_to_column": "cur_Name",

View File

@@ -83,25 +83,17 @@
{ {
"column": "Index", "column": "Index",
"css_classes": "col-sm-2", "css_classes": "col-sm-2",
"show": true,
"type": "none",
"default_value": "", "default_value": "",
"options": [],
"localized": ["name"], "localized": ["name"],
"name": [ "name": [
{ {
"language_code": "en_us", "language_code": "en_us",
"string": "N/A" "string": "Index"
},
{
"language_code": "es_es",
"string": "N/A"
},
{
"language_code": "de_de",
"string": "N/A"
} }
], ]
"options": [],
"show": false,
"type": "label"
}, },
{ {
"column": "Plugin", "column": "Plugin",

View File

@@ -302,23 +302,15 @@
{ {
"column": "Index", "column": "Index",
"css_classes": "col-sm-2", "css_classes": "col-sm-2",
"show": false, "show": true,
"type": "label", "type": "none",
"default_value": "", "default_value": "",
"options": [], "options": [],
"localized": ["name"], "localized": ["name"],
"name": [ "name": [
{ {
"language_code": "en_us", "language_code": "en_us",
"string": "N/A" "string": "Index"
},
{
"language_code": "es_es",
"string": "N/A"
},
{
"language_code": "de_de",
"string": "N/A"
} }
] ]
}, },

View File

@@ -57,19 +57,15 @@
{ {
"column": "Index", "column": "Index",
"css_classes": "col-sm-2", "css_classes": "col-sm-2",
"show": false, "show": true,
"type": "label", "type": "none",
"default_value": "", "default_value": "",
"options": [], "options": [],
"localized": ["name"], "localized": ["name"],
"name": [ "name": [
{ {
"language_code": "en_us", "language_code": "en_us",
"string": "N/A" "string": "Index"
},
{
"language_code": "es_es",
"string": "N/A"
} }
] ]
}, },

View File

@@ -1,44 +1,51 @@
<!-- ----------------------------------------------------------------------- -->
<!-- Datatable -->
<link rel="stylesheet" href="lib/AdminLTE/bower_components/datatables.net-bs/css/dataTables.bootstrap.min.css">
<link rel="stylesheet" href="lib/AdminLTE/bower_components/datatables.net/css/select.dataTables.min.css">
<script src="lib/AdminLTE/bower_components/datatables.net/js/jquery.dataTables.min.js"></script>
<script src="lib/AdminLTE/bower_components/datatables.net-bs/js/dataTables.bootstrap.min.js"></script>
<script src="lib/AdminLTE/bower_components/datatables.net/js/dataTables.select.min.js"></script>
<!-- Main content ---------------------------------------------------------- --> <!-- Main content ---------------------------------------------------------- -->
<section class="content"> <section class="content">
<div class="plugin-filters"> <div class="plugin-filters">
<div class="input-group col-sm-4"> <div class="input-group col-sm-12">
<label class="control-label col-sm-3"><?= lang('Plugins_Filters_Mac');?></label> <label class="col-sm-3"><?= lang('Plugins_Filters_Mac');?></label>
<input class="form-control col-sm-3" id="txtMacFilter" type="text" value="--" readonly> <input class="col-sm-3" id="txtMacFilter" type="text" value="--" readonly>
</div>
</div> </div>
<div class="nav-tabs-custom plugin-content" style="margin-bottom: 0px;"> </div>
<div class="nav-tabs-custom plugin-content" style="margin-bottom: 0px;">
<ul id="tabs-location" class="nav nav-tabs col-sm-2 "> <ul id="tabs-location" class="nav nav-tabs col-sm-2 ">
<!-- PLACEHOLDER --> <!-- PLACEHOLDER -->
</ul> </ul>
<div id="tabs-content-location" class="tab-content col-sm-10"> <div id="tabs-content-location" class="tab-content col-sm-10">
<!-- PLACEHOLDER --> <!-- PLACEHOLDER -->
</div> </div>
</section> </section>
<script defer>
<script>
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Initializes fields based on current MAC // Initializes fields based on current MAC
function initFields() { function initFields() {
var urlParams = new URLSearchParams(window.location.search); var urlParams = new URLSearchParams(window.location.search);
mac = urlParams.get ('mac'); mac = urlParams.get ('mac');
// if the current mac has changed, reinitialize the data // if the current mac has changed, reinitialize the data
if(mac != undefined && $("#txtMacFilter").val() != mac) if(mac != undefined && $("#txtMacFilter").val() != mac)
{ {
$("#txtMacFilter").val(mac); $("#txtMacFilter").val(mac);
getData(); getData();
} }
} }
@@ -46,142 +53,145 @@ function initFields() {
// Checking if current MAC has changed and triggering an updated if needed // Checking if current MAC has changed and triggering an updated if needed
function updater() { function updater() {
initFields() initFields()
// loop // loop
setTimeout(function() { setTimeout(function() {
updater(); updater();
}, 500); }, 500);
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Get form control according to the column definition from config.json > database_column_definitions // Get form control according to the column definition from config.json > database_column_definitions
function getFormControl(dbColumnDef, value, index) { function getFormControl(dbColumnDef, value, index) {
result = '' result = ''
// Check if mapped_to_column_data exists and has a value to override the supplied value which is most likely `undefined` // Check if mapped_to_column_data exists and has a value to override the supplied value which is most likely `undefined`
if (dbColumnDef.mapped_to_column_data && dbColumnDef.mapped_to_column_data.value) { if (dbColumnDef.mapped_to_column_data && dbColumnDef.mapped_to_column_data.value) {
value = dbColumnDef.mapped_to_column_data.value; value = dbColumnDef.mapped_to_column_data.value;
} }
result = processColumnValue(dbColumnDef, value, index, dbColumnDef.type) result = processColumnValue(dbColumnDef, value, index, dbColumnDef.type)
return result; return result;
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Process column value // Process column value
function processColumnValue(dbColumnDef, value, index, type) { function processColumnValue(dbColumnDef, value, index, type) {
if (type.includes('.')) { if (type.includes('.')) {
const typeParts = type.split('.'); const typeParts = type.split('.');
// recursion // recursion
for (const typePart of typeParts) { for (const typePart of typeParts) {
value = processColumnValue(dbColumnDef, value, index, typePart) value = processColumnValue(dbColumnDef, value, index, typePart)
} }
} else{ } else{
// pick form control based on the supplied type // pick form control based on the supplied type
switch(type) switch(type)
{ {
case 'label': case 'label':
value = `<span>${value}<span>`; value = `<span>${value}<span>`;
break; break;
case 'textarea_readonly': case 'none':
value = `<textarea cols="70" rows="3" wrap="off" readonly style="white-space: pre-wrap;"> value = `${value}`;
${value.replace(/^b'(.*)'$/gm, '$1').replace(/\\n/g, '\n').replace(/\\r/g, '\r')} break;
</textarea>`; case 'textarea_readonly':
break; value = `<textarea cols="70" rows="3" wrap="off" readonly style="white-space: pre-wrap;">
case 'textbox_save': ${value.replace(/^b'(.*)'$/gm, '$1').replace(/\\n/g, '\n').replace(/\\r/g, '\r')}
</textarea>`;
break;
case 'textbox_save':
value = value == 'null' ? '' : value; // hide 'null' values value = value == 'null' ? '' : value; // hide 'null' values
id = `${dbColumnDef.column}_${index}` id = `${dbColumnDef.column}_${index}`
value = `<span class="form-group"> value = `<span class="form-group">
<div class="input-group"> <div class="input-group">
<input class="form-control" type="text" value="${value}" id="${id}" data-my-column="${dbColumnDef.column}" data-my-index="${index}" name="${dbColumnDef.column}"> <input class="form-control" type="text" value="${value}" id="${id}" data-my-column="${dbColumnDef.column}" data-my-index="${index}" name="${dbColumnDef.column}">
<span class="input-group-addon"><i class="fa fa-save pointer" onclick="genericSaveData('${id}');"></i></span> <span class="input-group-addon"><i class="fa fa-save pointer" onclick="genericSaveData('${id}');"></i></span>
</div> </div>
<span>`; <span>`;
break; break;
case 'url': case 'url':
value = `<span><a href="${value}" target="_blank">${value}</a><span>`; value = `<span><a href="${value}" target="_blank">${value}</a><span>`;
break; break;
case 'url_http_https': case 'url_http_https':
value = `<span> value = `<span>
<a href="http://${value}" target="_blank"> <a href="http://${value}" target="_blank">
<i class="fa fa-lock-open "></i> <i class="fa fa-lock-open "></i>
</a> </a>
/ /
<a href="https://${value}" target="_blank"> <a href="https://${value}" target="_blank">
<i class="fa fa-lock "></i> <i class="fa fa-lock "></i>
</a> </a>
<span>`; <span>`;
break; break;
case 'device_name_mac': case 'device_name_mac':
value = createDeviceLink(value); value = createDeviceLink(value);
break; break;
case 'device_mac': case 'device_mac':
value = `<span class="anonymizeMac"><a href="/deviceDetails.php?mac=${value}" target="_blank">${value}</a><span>`; value = `<span class="anonymizeMac"><a href="/deviceDetails.php?mac=${value}" target="_blank">${value}</a><span>`;
break; break;
case 'device_ip': case 'device_ip':
value = `<span class="anonymizeIp"><a href="#" onclick="navigateToDeviceWithIp('${value}')" >${value}</a><span>`; value = `<span class="anonymizeIp"><a href="#" onclick="navigateToDeviceWithIp('${value}')" >${value}</a><span>`;
break; break;
case 'threshold': case 'threshold':
valueTmp = '' valueTmp = ''
$.each(dbColumnDef.options, function(index, obj) { $.each(dbColumnDef.options, function(index, obj) {
if(Number(value) < Number(obj.maximum) && valueTmp == '') if(Number(value) < Number(obj.maximum) && valueTmp == '')
{ {
valueTmp = `<div style="background-color:${obj.hexColor}">${value}</div>` valueTmp = `<div style="background-color:${obj.hexColor}">${value}</div>`
// return; // return;
} }
}); });
value = valueTmp; value = valueTmp;
break; break;
case 'replace': case 'replace':
$.each(dbColumnDef.options, function(index, obj) { $.each(dbColumnDef.options, function(index, obj) {
if(value == obj.equals) if(value == obj.equals)
{ {
value = `<span title="${value}">${obj.replacement}</span>` value = `<span title="${value}">${obj.replacement}</span>`
} }
}); });
break; break;
case 'regex': case 'regex':
for (const option of dbColumnDef.options) { for (const option of dbColumnDef.options) {
if (option.type === type) { if (option.type === type) {
const regexPattern = new RegExp(option.param); const regexPattern = new RegExp(option.param);
const match = value.match(regexPattern); const match = value.match(regexPattern);
if (match) { if (match) {
// Return the first match // Return the first match
value = match[0]; value = match[0];
} }
} }
} }
break; break;
case 'eval': case 'eval':
for (const option of dbColumnDef.options) { for (const option of dbColumnDef.options) {
if (option.type === type) { if (option.type === type) {
// console.log(option.param) // console.log(option.param)
value = eval(option.param); value = eval(option.param);
} }
} }
break; break;
default: default:
value = value + `<div style='text-align:center' title="${getString("Plugins_no_control")}"><i class='fa-solid fa-circle-question'></i></div>` ; value = value + `<div style='text-align:center' title="${getString("Plugins_no_control")}"><i class='fa-solid fa-circle-question'></i></div>` ;
} }
} }
// Default behavior if no match is found // Default behavior if no match is found
@@ -193,30 +203,30 @@ function processColumnValue(dbColumnDef, value, index, type) {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Update the corresponding DB column and entry // Update the corresponding DB column and entry
function genericSaveData (id) { function genericSaveData (id) {
columnName = $(`#${id}`).attr('data-my-column') columnName = $(`#${id}`).attr('data-my-column')
index = $(`#${id}`).attr('data-my-index') index = $(`#${id}`).attr('data-my-index')
columnValue = $(`#${id}`).val() columnValue = $(`#${id}`).val()
console.log(columnName) console.log(columnName)
console.log(index) console.log(index)
console.log(columnValue) console.log(columnValue)
$.get(`php/server/dbHelper.php?action=update&dbtable=Plugins_Objects&columnName=Index&id=${index}&columns=UserData&values=${columnValue}`, function(data) { $.get(`php/server/dbHelper.php?action=update&dbtable=Plugins_Objects&columnName=Index&id=${index}&columns=UserData&values=${columnValue}`, function(data) {
// var result = JSON.parse(data); // var result = JSON.parse(data);
// console.log(data) // console.log(data)
if(sanitize(data) == 'OK') if(sanitize(data) == 'OK')
{ {
showMessage('<?= lang('Gen_DataUpdatedUITakesTime');?>') showMessage('<?= lang('Gen_DataUpdatedUITakesTime');?>')
// Remove navigation prompt "Are you sure you want to leave..." // Remove navigation prompt "Are you sure you want to leave..."
window.onbeforeunload = null; window.onbeforeunload = null;
} else } else
{ {
showMessage('<?= lang('Gen_LockedDB');?>') showMessage('<?= lang('Gen_LockedDB');?>')
} }
}); });
} }
@@ -228,361 +238,287 @@ pluginHistory = []
function getData(){ function getData(){
$.get('api/plugins.json', function(res) { // Show the loading spinner while generating
showSpinner();
pluginDefinitions = res["data"]; $.get('api/plugins.json', function(res) {
$.get('api/table_plugins_events.json', function(res) { pluginDefinitions = res["data"];
pluginUnprocessedEvents = res["data"]; $.get('api/table_plugins_events.json', function(res) {
$.get('api/table_plugins_objects.json', function(res) { pluginUnprocessedEvents = res["data"];
pluginObjects = res["data"]; $.get('api/table_plugins_objects.json', function(res) {
$.get('api/table_plugins_history.json', function(res) { pluginObjects = res["data"];
pluginHistory = res["data"]; $.get('api/table_plugins_history.json', function(res) {
generateTabs() pluginHistory = res["data"];
generateTabs()
});
});
}); });
});
}); });
});
} }
// ----------------------------------------------------------------------------- function generateTabs() {
function generateTabs()
{
showSpinner()
activetab = 'active' // Reset the tabs by clearing previous headers and content
resetTabs();
// clear previous headers data // Sort pluginDefinitions by unique_prefix alphabetically
$('#tabs-location').html(""); pluginDefinitions.sort((a, b) => a.unique_prefix.localeCompare(b.unique_prefix));
// clear previous content data
$('#tabs-content-location').html("");
$.each(pluginDefinitions, function(index, pluginObj) { // Iterate over the sorted pluginDefinitions to create tab headers and content
pluginDefinitions.forEach(pluginObj => {
if (pluginObj.show_ui) {
stats = createTabContent(pluginObj); // Create the content for each tab
createTabHeader(pluginObj, stats); // Create the header for each tab
}
});
// console.log(pluginObj) hideSpinner()
if(pluginObj.show_ui) // hiding plugins where specified
{
prefix = pluginObj.unique_prefix;
$('#tabs-location').append(
`<li class=" left-nav ${activetab}">
<a class=" col-sm-12 " href="#${prefix}" data-plugin-prefix="${prefix}" id="${prefix}_id" data-toggle="tab" >
${getString(`${prefix}_icon`)} ${getString(`${prefix}_display_name`)}
</a>
</li>`
);
activetab = '' // only first tab is active
}
});
activetab = 'active'
$.each(pluginDefinitions, function(index, pluginObj) {
headersHtml = ""
colDefinitions = []
evRows = ""
obRows = ""
hiRows = ""
prefix = pluginObj.unique_prefix;
// Generate the header
$.each(pluginObj["database_column_definitions"], function(index, colDef){
if(colDef.show == true) // select only the ones to show
{
colDefinitions.push(colDef)
headersHtml += `<th class="${colDef.css_classes}" >${getString(`${prefix}_${colDef.column}_name` )}</th>`
}
});
// Generate the event rows
var eveCount = 0;
for(i=0;i<pluginUnprocessedEvents.length;i++)
{
if(pluginUnprocessedEvents[i].Plugin == prefix)
{
clm = ""
for(j=0;j<colDefinitions.length;j++)
{
clm += '<td>'+ pluginUnprocessedEvents[i][colDefinitions[j].column] +'</td>'
}
evRows += `<tr data-my-index="${pluginUnprocessedEvents[i]["Index"]}" >${clm}</tr>`
eveCount++;
}
}
// Generate the history rows
var histCount = 0
var histCountDisplayed = 0
for(i=0;i < pluginHistory.length ;i++)
{
if(pluginHistory[i].Plugin == prefix)
{
if(histCount < 50) // only display 50 entries to optimize performance
{
clm = ""
for(j=0;j<colDefinitions.length;j++)
{
clm += '<td>'+ pluginHistory[i][colDefinitions[j].column] +'</td>'
}
hiRows += `<tr data-my-index="${pluginHistory[i]["Index"]}" >${clm}</tr>`
histCountDisplayed++;
}
histCount++; // count and display the total
}
}
// Generate the object rows
var obCount = 0;
for(var i=0;i<pluginObjects.length;i++)
{
if(pluginObjects[i].Plugin == prefix)
{
if(shouldBeShown(pluginObjects[i], pluginObj)) // filter TODO
{
clm = ""
for(var j=0;j<colDefinitions.length;j++)
{
clm += '<td>'+ getFormControl(colDefinitions[j], pluginObjects[i][colDefinitions[j].column], pluginObjects[i]["Index"], colDefinitions, pluginObjects[i]) +'</td>'
}
obRows += `<tr data-my-index="${pluginObjects[i]["Index"]}" >${clm}</tr>`
obCount++;
}
}
}
// Generate the HTML
$('#tabs-content-location').append(
`
<div id="${prefix}" class="tab-pane ${activetab}">
<div class="nav-tabs-custom" style="margin-bottom: 0px">
<ul class="nav nav-tabs">
<li class="active" >
<a href="#objectsTarget_${prefix}" data-toggle="tab" >
<i class="fa fa-cube"></i> <?= lang('Plugins_Objects');?> (${obCount})
</a>
</li>
<li >
<a href="#eventsTarget_${prefix}" data-toggle="tab" >
<i class="fa fa-bolt"></i> <?= lang('Plugins_Unprocessed_Events');?> (${eveCount})
</a>
</li>
<li >
<a href="#historyTarget_${prefix}" data-toggle="tab" >
<i class="fa fa-clock"></i> <?= lang('Plugins_History');?> (${histCountDisplayed} <?= lang('Plugins_Out_of');?> ${histCount})
</a>
</li>
<ul>
</div>
<div class="tab-content">
<div id="objectsTarget_${prefix}" class="tab-pane ${activetab}">
<table class="table table-striped" data-my-dbtable="Plugins_Objects">
<tbody>
<tr>
${headersHtml}
</tr>
${obRows}
</tbody>
</table>
<div class="plugin-obj-purge">
<button class="btn btn-primary" onclick="purgeAll('${prefix}', 'Plugins_Objects' )"><?= lang('Plugins_DeleteAll');?></button>
<button class="btn btn-danger " onclick="deleteListed('${prefix}', 'Plugins_Objects' )"><?= lang('Plugins_Obj_DeleteListed');?></button>
</div>
</div>
<div id="eventsTarget_${prefix}" class="tab-pane">
<table class="table table-striped" data-my-dbtable="Plugins_Events">
<tbody>
<tr>
${headersHtml}
</tr>
${evRows}
</tbody>
</table>
<div class="plugin-obj-purge">
<button class="btn btn-primary" onclick="purgeAll('${prefix}', 'Plugins_Events' )"><?= lang('Plugins_DeleteAll');?></button>
</div>
</div>
<div id="historyTarget_${prefix}" class="tab-pane">
<table class="table table-striped" data-my-dbtable="Plugins_History">
<tbody>
<tr>
${headersHtml}
</tr>
${hiRows}
</tbody>
</table>
<div class="plugin-obj-purge">
<button class="btn btn-primary" onclick="purgeAll('${prefix}', 'Plugins_History' )"><?= lang('Plugins_DeleteAll');?></button>
</div>
</div>
</div>
<div class='plugins-description'>
${getString(prefix + '_description')}
<span>
<a href="https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/${pluginObj.code_name}" target="_blank"><?= lang('Gen_ReadDocs');?></a>
</span>
</div>
</div>
`);
activetab = '' // only first tab is active
});
initTabs()
} }
// -------------------------------------------------------- function resetTabs() {
// Handle active / selected tabs // Clear any existing tab headers and content from the DOM
// handle first tab (objectsTarget_) display $('#tabs-location').empty();
function initTabs() { $('#tabs-content-location').empty();
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
var target = $(e.target).attr("href").split('_').pop();
var pref = target.includes('_') ? target.split('_')[1] : target.split('#')[1];
var everythingHidden = true;
if ($('#objectsTarget_' + pref) && $('#historyTarget_' + pref) && $('#eventsTarget_' + pref)) {
var isObjectsInactive = !$('#objectsTarget_' + pref).hasClass('active');
var isHistoryInactive = !$('#historyTarget_' + pref).hasClass('active');
var isEventsInactive = !$('#eventsTarget_' + pref).hasClass('active');
everythingHidden = isObjectsInactive && isHistoryInactive && isEventsInactive;
}
if (target === '#' + pref && everythingHidden) {
var objectsTarget = $('#objectsTarget_' + pref);
if (objectsTarget.length && !objectsTarget.hasClass('active')) {
objectsTarget.addClass('active');
}
}
});
// hide spinning icon
hideSpinner()
} }
function createTabHeader(pluginObj, stats) {
const prefix = pluginObj.unique_prefix; // Get the unique prefix for the plugin
// Determine the active class for the first tab
const activeClass = pluginDefinitions.indexOf(pluginObj) === 0 ? 'active' : '';
// Append the tab header to the tabs location
$('#tabs-location').append(`
<li class="left-nav ${activeClass} ">
<a class="col-sm-12 textOverflow" href="#${prefix}" data-plugin-prefix="${prefix}" id="${prefix}_id" data-toggle="tab">
${getString(`${prefix}_icon`)} ${getString(`${prefix}_display_name`)}
</a>
${stats.objectDataCount > 0 ? `<div class="pluginBadgeWrap"><span title="" class="badge pluginBadge" >${stats.objectDataCount}</span></div>` : ""}
</li>
`);
}
function createTabContent(pluginObj) {
const prefix = pluginObj.unique_prefix; // Get the unique prefix for the plugin
const colDefinitions = getColumnDefinitions(pluginObj); // Get column definitions for DataTables
// Get data for events, objects, and history related to the plugin
const objectData = getObjectData(prefix, colDefinitions, pluginObj);
const eventData = getEventData(prefix, colDefinitions);
const historyData = getHistoryData(prefix, colDefinitions, pluginObj);
// Append the content structure for the plugin's tab to the content location
$('#tabs-content-location').append(`
<div id="${prefix}" class="tab-pane ${pluginDefinitions.indexOf(pluginObj) === 0 ? 'active' : ''}">
${generateTabNavigation(prefix, objectData.length, eventData.length, historyData.length)} <!-- Create tab navigation -->
<div class="tab-content">
${generateDataTable(prefix, 'Objects', objectData, colDefinitions)}
${generateDataTable(prefix, 'Events', eventData, colDefinitions)}
${generateDataTable(prefix, 'History', historyData, colDefinitions)}
</div>
<div class='plugins-description'>
${getString(`${prefix}_description`)} <!-- Display the plugin description -->
<span><a href="https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/${pluginObj.code_name}" target="_blank">${getString('Gen_ReadDocs')}</a></span> <!-- Link to documentation -->
</div>
</div>
`);
// Initialize DataTables for the respective sections
initializeDataTables(prefix, objectData, eventData, historyData, colDefinitions);
return {
"objectDataCount": objectData.length,
"eventDataCount": eventData.length,
"historyDataCount": historyData.length
}
}
function getColumnDefinitions(pluginObj) {
// Filter and return only the columns that are set to show in the UI
return pluginObj["database_column_definitions"].filter(colDef => colDef.show);
}
function getEventData(prefix, colDefinitions) {
// Extract event data specific to the plugin and format it for DataTables
return pluginUnprocessedEvents
.filter(event => event.Plugin === prefix) // Filter events for the specific plugin
.map(event => colDefinitions.map(colDef => event[colDef.column] || '')); // Map to the defined columns
}
function getObjectData(prefix, colDefinitions, pluginObj) {
// Extract object data specific to the plugin and format it for DataTables
return pluginObjects
.filter(object => object.Plugin === prefix && shouldBeShown(object, pluginObj)) // Filter objects for the specific plugin
.map(object => colDefinitions.map(colDef => getFormControl(colDef, object[colDef.column], object["Index"], colDefinitions, object))); // Map to the defined columns
}
function getHistoryData(prefix, colDefinitions, pluginObj) {
// Extract history data for the plugin, limiting to the first 50 entries for performance
return pluginHistory
.filter((history, index) => history.Plugin === prefix && index < 50) // Filter history for the specific plugin
.map(history => colDefinitions.map(colDef => history[colDef.column] || '')); // Map to the defined columns
}
function generateTabNavigation(prefix, objectCount, eventCount, historyCount) {
// Create navigation tabs for Objects, Unprocessed Events, and History
return `
<div class="nav-tabs-custom" style="margin-bottom: 0px">
<ul class="nav nav-tabs">
<li class="active">
<a href="#objectsTarget_${prefix}" data-toggle="tab"><i class="fa fa-cube"></i> ${getString('Plugins_Objects')} (${objectCount})</a>
</li>
<li>
<a href="#eventsTarget_${prefix}" data-toggle="tab"><i class="fa fa-bolt"></i> ${getString('Plugins_Unprocessed_Events')} (${eventCount})</a>
</li>
<li>
<a href="#historyTarget_${prefix}" data-toggle="tab"><i class="fa fa-clock"></i> ${getString('Plugins_History')} (${historyCount})</a>
</li>
</ul>
</div>
`;
}
function generateDataTable(prefix, tableType, data, colDefinitions) {
// Generate HTML for a DataTable and associated buttons for a given table type
const headersHtml = colDefinitions.map(colDef => `<th class="${colDef.css_classes}">${getString(`${prefix}_${colDef.column}_name`)}</th>`).join('');
return `
<div id="${tableType.toLowerCase()}Target_${prefix}" class="tab-pane ${tableType == "Objects" ? "active":""}">
<table id="${tableType.toLowerCase()}Table_${prefix}" class="display table table-striped table-stretched" data-my-dbtable="Plugins_${tableType}">
<thead><tr>${headersHtml}</tr></thead>
</table>
<div class="plugin-obj-purge">
<button class="btn btn-primary" onclick="purgeAll('${prefix}', 'Plugins_${tableType}' )"><?= lang('Plugins_DeleteAll');?></button>
${tableType !== 'Events' ? `<button class="btn btn-danger" onclick="deleteListed('${prefix}', 'Plugins_${tableType}' )"><?= lang('Plugins_Obj_DeleteListed');?></button>` : ''}
</div>
</div>
`;
}
function initializeDataTables(prefix, objectData, eventData, historyData, colDefinitions) {
// Common settings for DataTables initialization
const commonDataTableSettings = {
orderable: false, // Disable ordering
createdRow: function(row, data) {
$(row).attr('data-my-index', data[0]); // Set data attribute for indexing
}
};
// Initialize DataTable for Objects
$(`#objectsTable_${prefix}`).DataTable({
data: objectData,
columns: colDefinitions.map(colDef => ({ title: getString(`${prefix}_${colDef.column}_name`) })), // Column titles
...commonDataTableSettings // Spread common settings
});
// Initialize DataTable for Unprocessed Events
$(`#eventsTable_${prefix}`).DataTable({
data: eventData,
columns: colDefinitions.map(colDef => ({ title: getString(`${prefix}_${colDef.column}_name`) })), // Column titles
...commonDataTableSettings // Spread common settings
});
// Initialize DataTable for History
$(`#historyTable_${prefix}`).DataTable({
data: historyData,
columns: colDefinitions.map(colDef => ({ title: getString(`${prefix}_${colDef.column}_name`) })), // Column titles
...commonDataTableSettings // Spread common settings
});
}
// -------------------------------------------------------- // --------------------------------------------------------
// Filter method that determines if an entry should be shown // Filter method that determines if an entry should be shown
function shouldBeShown(entry, pluginObj) function shouldBeShown(entry, pluginObj)
{ {
if (pluginObj.hasOwnProperty('data_filters')) { if (pluginObj.hasOwnProperty('data_filters')) {
let dataFilters = pluginObj.data_filters; let dataFilters = pluginObj.data_filters;
// Loop through 'data_filters' array and appply filters on individual plugin entries // Loop through 'data_filters' array and appply filters on individual plugin entries
for (let i = 0; i < dataFilters.length; i++) { for (let i = 0; i < dataFilters.length; i++) {
compare_field_id = dataFilters[i].compare_field_id; compare_field_id = dataFilters[i].compare_field_id;
compare_column = dataFilters[i].compare_column; compare_column = dataFilters[i].compare_column;
compare_operator = dataFilters[i].compare_operator; compare_operator = dataFilters[i].compare_operator;
compare_js_template = dataFilters[i].compare_js_template; compare_js_template = dataFilters[i].compare_js_template;
compare_use_quotes = dataFilters[i].compare_use_quotes; compare_use_quotes = dataFilters[i].compare_use_quotes;
compare_field_id_value = $(`#${compare_field_id}`).val(); compare_field_id_value = $(`#${compare_field_id}`).val();
// apply filter i sthe filter field has a valid value // apply filter i sthe filter field has a valid value
if(compare_field_id_value != undefined && compare_field_id_value != '--') if(compare_field_id_value != undefined && compare_field_id_value != '--')
{ {
// valid value // valid value
// resolve the left and right part of the comparison // resolve the left and right part of the comparison
let left = compare_js_template.replace('{value}', `${compare_field_id_value}`) let left = compare_js_template.replace('{value}', `${compare_field_id_value}`)
let right = compare_js_template.replace('{value}', `${entry[compare_column]}`) let right = compare_js_template.replace('{value}', `${entry[compare_column]}`)
// include wrapper quotes if specified // include wrapper quotes if specified
compare_use_quotes ? quotes = '"' : quotes = '' compare_use_quotes ? quotes = '"' : quotes = ''
result = eval( result = eval(
quotes + `${eval(left)}` + quotes + quotes + `${eval(left)}` + quotes +
` ${compare_operator} ` + ` ${compare_operator} ` +
quotes + `${eval(right)}` + quotes quotes + `${eval(right)}` + quotes
); );
return result; return result;
} }
}
} }
return true; }
return true;
} }
// -------------------------------------------------------- // --------------------------------------------------------
// Data cleanup/purge functionality // Data cleanup/purge functionality
plugPrefix = '' plugPrefix = ''
dbTable = '' dbTable = ''
function purgeAll(callback) { function purgeAll(callback) {
plugPrefix = arguments[0]; // plugin prefix plugPrefix = arguments[0]; // plugin prefix
dbTable = arguments[1]; // DB table dbTable = arguments[1]; // DB table
// Ask // Ask
showModalWarning('<?= lang('Gen_Purge');?>' + ' ' + plugPrefix + ' ' + dbTable , '<?= lang('Gen_AreYouSure');?>', showModalWarning('<?= lang('Gen_Purge');?>' + ' ' + plugPrefix + ' ' + dbTable , '<?= lang('Gen_AreYouSure');?>',
'<?= lang('Gen_Cancel');?>', '<?= lang('Gen_Okay');?>', "purgeAllExecute"); '<?= lang('Gen_Cancel');?>', '<?= lang('Gen_Okay');?>', "purgeAllExecute");
} }
// -------------------------------------------------------- // --------------------------------------------------------
function purgeAllExecute() { function purgeAllExecute() {
$.ajax({ $.ajax({
method: "POST", method: "POST",
url: "php/server/dbHelper.php", url: "php/server/dbHelper.php",
data: { action: "delete", dbtable: dbTable, columnName: 'Plugin', id:plugPrefix }, data: { action: "delete", dbtable: dbTable, columnName: 'Plugin', id:plugPrefix },
success: function(data, textStatus) { success: function(data, textStatus) {
showModalOk ('Result', data ); showModalOk ('Result', data );
} }
}) })
} }
// -------------------------------------------------------- // --------------------------------------------------------
function deleteListed(plugPrefix, dbTable) { function deleteListed(plugPrefix, dbTable) {
idArr = $(`#${plugPrefix} table[data-my-dbtable="${dbTable}"] tr[data-my-index]`).map(function(){return $(this).attr("data-my-index");}).get(); idArr = $(`#${plugPrefix} table[data-my-dbtable="${dbTable}"] tr[data-my-index]`).map(function(){return $(this).attr("data-my-index");}).get();
console.log(idArr); console.log(idArr);
$.ajax({ $.ajax({
method: "POST", method: "POST",
url: "php/server/dbHelper.php", url: "php/server/dbHelper.php",
data: { action: "delete", dbtable: dbTable, columnName: 'Index', id:idArr.toString() }, data: { action: "delete", dbtable: dbTable, columnName: 'Index', id:idArr.toString() },
success: function(data, textStatus) { success: function(data, textStatus) {
updateApi("plugins_objects") updateApi("plugins_objects")
showModalOk ('Result', data ); showModalOk ('Result', data );
} }
}) })
} }

599
front/pluginsCoreOld.php Executable file
View File

@@ -0,0 +1,599 @@
<!-- Main content ---------------------------------------------------------- -->
<section class="content">
<div class="plugin-filters">
<div class="input-group col-sm-4">
<label class="control-label col-sm-3"><?= lang('Plugins_Filters_Mac');?></label>
<input class="form-control col-sm-3" id="txtMacFilter" type="text" value="--" readonly>
</div>
</div>
<div class="nav-tabs-custom plugin-content" style="margin-bottom: 0px;">
<ul id="tabs-location" class="nav nav-tabs col-sm-2 ">
<!-- PLACEHOLDER -->
</ul>
<div id="tabs-content-location" class="tab-content col-sm-10">
<!-- PLACEHOLDER -->
</div>
</section>
<script defer>
// -----------------------------------------------------------------------------
// Initializes fields based on current MAC
function initFields() {
var urlParams = new URLSearchParams(window.location.search);
mac = urlParams.get ('mac');
// if the current mac has changed, reinitialize the data
if(mac != undefined && $("#txtMacFilter").val() != mac)
{
$("#txtMacFilter").val(mac);
getData();
}
}
// -----------------------------------------------------------------------------
// Checking if current MAC has changed and triggering an updated if needed
function updater() {
initFields()
// loop
setTimeout(function() {
updater();
}, 500);
}
// -----------------------------------------------------------------------------
// Get form control according to the column definition from config.json > database_column_definitions
function getFormControl(dbColumnDef, value, index) {
result = ''
// Check if mapped_to_column_data exists and has a value to override the supplied value which is most likely `undefined`
if (dbColumnDef.mapped_to_column_data && dbColumnDef.mapped_to_column_data.value) {
value = dbColumnDef.mapped_to_column_data.value;
}
result = processColumnValue(dbColumnDef, value, index, dbColumnDef.type)
return result;
}
// -----------------------------------------------------------------------------
// Process column value
function processColumnValue(dbColumnDef, value, index, type) {
if (type.includes('.')) {
const typeParts = type.split('.');
// recursion
for (const typePart of typeParts) {
value = processColumnValue(dbColumnDef, value, index, typePart)
}
} else{
// pick form control based on the supplied type
switch(type)
{
case 'label':
value = `<span>${value}<span>`;
break;
case 'textarea_readonly':
value = `<textarea cols="70" rows="3" wrap="off" readonly style="white-space: pre-wrap;">
${value.replace(/^b'(.*)'$/gm, '$1').replace(/\\n/g, '\n').replace(/\\r/g, '\r')}
</textarea>`;
break;
case 'textbox_save':
value = value == 'null' ? '' : value; // hide 'null' values
id = `${dbColumnDef.column}_${index}`
value = `<span class="form-group">
<div class="input-group">
<input class="form-control" type="text" value="${value}" id="${id}" data-my-column="${dbColumnDef.column}" data-my-index="${index}" name="${dbColumnDef.column}">
<span class="input-group-addon"><i class="fa fa-save pointer" onclick="genericSaveData('${id}');"></i></span>
</div>
<span>`;
break;
case 'url':
value = `<span><a href="${value}" target="_blank">${value}</a><span>`;
break;
case 'url_http_https':
value = `<span>
<a href="http://${value}" target="_blank">
<i class="fa fa-lock-open "></i>
</a>
/
<a href="https://${value}" target="_blank">
<i class="fa fa-lock "></i>
</a>
<span>`;
break;
case 'device_name_mac':
value = createDeviceLink(value);
break;
case 'device_mac':
value = `<span class="anonymizeMac"><a href="/deviceDetails.php?mac=${value}" target="_blank">${value}</a><span>`;
break;
case 'device_ip':
value = `<span class="anonymizeIp"><a href="#" onclick="navigateToDeviceWithIp('${value}')" >${value}</a><span>`;
break;
case 'threshold':
valueTmp = ''
$.each(dbColumnDef.options, function(index, obj) {
if(Number(value) < Number(obj.maximum) && valueTmp == '')
{
valueTmp = `<div style="background-color:${obj.hexColor}">${value}</div>`
// return;
}
});
value = valueTmp;
break;
case 'replace':
$.each(dbColumnDef.options, function(index, obj) {
if(value == obj.equals)
{
value = `<span title="${value}">${obj.replacement}</span>`
}
});
break;
case 'regex':
for (const option of dbColumnDef.options) {
if (option.type === type) {
const regexPattern = new RegExp(option.param);
const match = value.match(regexPattern);
if (match) {
// Return the first match
value = match[0];
}
}
}
break;
case 'eval':
for (const option of dbColumnDef.options) {
if (option.type === type) {
// console.log(option.param)
value = eval(option.param);
}
}
break;
default:
value = value + `<div style='text-align:center' title="${getString("Plugins_no_control")}"><i class='fa-solid fa-circle-question'></i></div>` ;
}
}
// Default behavior if no match is found
return value;
}
// -----------------------------------------------------------------------------
// Update the corresponding DB column and entry
function genericSaveData (id) {
columnName = $(`#${id}`).attr('data-my-column')
index = $(`#${id}`).attr('data-my-index')
columnValue = $(`#${id}`).val()
console.log(columnName)
console.log(index)
console.log(columnValue)
$.get(`php/server/dbHelper.php?action=update&dbtable=Plugins_Objects&columnName=Index&id=${index}&columns=UserData&values=${columnValue}`, function(data) {
// var result = JSON.parse(data);
// console.log(data)
if(sanitize(data) == 'OK')
{
showMessage('<?= lang('Gen_DataUpdatedUITakesTime');?>')
// Remove navigation prompt "Are you sure you want to leave..."
window.onbeforeunload = null;
} else
{
showMessage('<?= lang('Gen_LockedDB');?>')
}
});
}
// -----------------------------------------------------------------------------
pluginDefinitions = []
pluginUnprocessedEvents = []
pluginObjects = []
pluginHistory = []
function getData(){
$.get('api/plugins.json', function(res) {
pluginDefinitions = res["data"];
$.get('api/table_plugins_events.json', function(res) {
pluginUnprocessedEvents = res["data"];
$.get('api/table_plugins_objects.json', function(res) {
pluginObjects = res["data"];
$.get('api/table_plugins_history.json', function(res) {
pluginHistory = res["data"];
generateTabs()
});
});
});
});
}
// -----------------------------------------------------------------------------
function generateTabs()
{
showSpinner()
activetab = 'active'
// clear previous headers data
$('#tabs-location').html("");
// clear previous content data
$('#tabs-content-location').html("");
$.each(pluginDefinitions, function(index, pluginObj) {
// console.log(pluginObj)
if(pluginObj.show_ui) // hiding plugins where specified
{
prefix = pluginObj.unique_prefix;
$('#tabs-location').append(
`<li class=" left-nav ${activetab}">
<a class=" col-sm-12 " href="#${prefix}" data-plugin-prefix="${prefix}" id="${prefix}_id" data-toggle="tab" >
${getString(`${prefix}_icon`)} ${getString(`${prefix}_display_name`)}
</a>
</li>`
);
activetab = '' // only first tab is active
}
});
activetab = 'active'
$.each(pluginDefinitions, function(index, pluginObj) {
headersHtml = ""
colDefinitions = []
evRows = ""
obRows = ""
hiRows = ""
prefix = pluginObj.unique_prefix;
// Generate the header
$.each(pluginObj["database_column_definitions"], function(index, colDef){
if(colDef.show == true) // select only the ones to show
{
colDefinitions.push(colDef)
headersHtml += `<th class="${colDef.css_classes}" >${getString(`${prefix}_${colDef.column}_name` )}</th>`
}
});
// Generate the event rows
var eveCount = 0;
for(i=0;i<pluginUnprocessedEvents.length;i++)
{
if(pluginUnprocessedEvents[i].Plugin == prefix)
{
clm = ""
for(j=0;j<colDefinitions.length;j++)
{
clm += '<td>'+ pluginUnprocessedEvents[i][colDefinitions[j].column] +'</td>'
}
evRows += `<tr data-my-index="${pluginUnprocessedEvents[i]["Index"]}" >${clm}</tr>`
eveCount++;
}
}
// Generate the history rows
var histCount = 0
var histCountDisplayed = 0
for(i=0;i < pluginHistory.length ;i++)
{
if(pluginHistory[i].Plugin == prefix)
{
if(histCount < 50) // only display 50 entries to optimize performance
{
clm = ""
for(j=0;j<colDefinitions.length;j++)
{
clm += '<td>'+ pluginHistory[i][colDefinitions[j].column] +'</td>'
}
hiRows += `<tr data-my-index="${pluginHistory[i]["Index"]}" >${clm}</tr>`
histCountDisplayed++;
}
histCount++; // count and display the total
}
}
// Generate the object rows
var obCount = 0;
for(var i=0;i<pluginObjects.length;i++)
{
if(pluginObjects[i].Plugin == prefix)
{
if(shouldBeShown(pluginObjects[i], pluginObj)) // filter TODO
{
clm = ""
for(var j=0;j<colDefinitions.length;j++)
{
clm += '<td>'+ getFormControl(colDefinitions[j], pluginObjects[i][colDefinitions[j].column], pluginObjects[i]["Index"], colDefinitions, pluginObjects[i]) +'</td>'
}
obRows += `<tr data-my-index="${pluginObjects[i]["Index"]}" >${clm}</tr>`
obCount++;
}
}
}
// Generate the HTML
$('#tabs-content-location').append(
`
<div id="${prefix}" class="tab-pane ${activetab}">
<div class="nav-tabs-custom" style="margin-bottom: 0px">
<ul class="nav nav-tabs">
<li class="active" >
<a href="#objectsTarget_${prefix}" data-toggle="tab" >
<i class="fa fa-cube"></i> <?= lang('Plugins_Objects');?> (${obCount})
</a>
</li>
<li >
<a href="#eventsTarget_${prefix}" data-toggle="tab" >
<i class="fa fa-bolt"></i> <?= lang('Plugins_Unprocessed_Events');?> (${eveCount})
</a>
</li>
<li >
<a href="#historyTarget_${prefix}" data-toggle="tab" >
<i class="fa fa-clock"></i> <?= lang('Plugins_History');?> (${histCountDisplayed} <?= lang('Plugins_Out_of');?> ${histCount})
</a>
</li>
<ul>
</div>
<div class="tab-content">
<div id="objectsTarget_${prefix}" class="tab-pane ${activetab}">
<table class="table table-striped" data-my-dbtable="Plugins_Objects">
<tbody>
<tr>
${headersHtml}
</tr>
${obRows}
</tbody>
</table>
<div class="plugin-obj-purge">
<button class="btn btn-primary" onclick="purgeAll('${prefix}', 'Plugins_Objects' )"><?= lang('Plugins_DeleteAll');?></button>
<button class="btn btn-danger " onclick="deleteListed('${prefix}', 'Plugins_Objects' )"><?= lang('Plugins_Obj_DeleteListed');?></button>
</div>
</div>
<div id="eventsTarget_${prefix}" class="tab-pane">
<table class="table table-striped" data-my-dbtable="Plugins_Events">
<tbody>
<tr>
${headersHtml}
</tr>
${evRows}
</tbody>
</table>
<div class="plugin-obj-purge">
<button class="btn btn-primary" onclick="purgeAll('${prefix}', 'Plugins_Events' )"><?= lang('Plugins_DeleteAll');?></button>
</div>
</div>
<div id="historyTarget_${prefix}" class="tab-pane">
<table class="table table-striped" data-my-dbtable="Plugins_History">
<tbody>
<tr>
${headersHtml}
</tr>
${hiRows}
</tbody>
</table>
<div class="plugin-obj-purge">
<button class="btn btn-primary" onclick="purgeAll('${prefix}', 'Plugins_History' )"><?= lang('Plugins_DeleteAll');?></button>
</div>
</div>
</div>
<div class='plugins-description'>
${getString(prefix + '_description')}
<span>
<a href="https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/${pluginObj.code_name}" target="_blank"><?= lang('Gen_ReadDocs');?></a>
</span>
</div>
</div>
`);
activetab = '' // only first tab is active
});
initTabs()
}
// --------------------------------------------------------
// Handle active / selected tabs
// handle first tab (objectsTarget_) display
function initTabs() {
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
var target = $(e.target).attr("href").split('_').pop();
var pref = target.includes('_') ? target.split('_')[1] : target.split('#')[1];
var everythingHidden = true;
if ($('#objectsTarget_' + pref) && $('#historyTarget_' + pref) && $('#eventsTarget_' + pref)) {
var isObjectsInactive = !$('#objectsTarget_' + pref).hasClass('active');
var isHistoryInactive = !$('#historyTarget_' + pref).hasClass('active');
var isEventsInactive = !$('#eventsTarget_' + pref).hasClass('active');
everythingHidden = isObjectsInactive && isHistoryInactive && isEventsInactive;
}
if (target === '#' + pref && everythingHidden) {
var objectsTarget = $('#objectsTarget_' + pref);
if (objectsTarget.length && !objectsTarget.hasClass('active')) {
objectsTarget.addClass('active');
}
}
});
// hide spinning icon
hideSpinner()
}
// --------------------------------------------------------
// Filter method that determines if an entry should be shown
function shouldBeShown(entry, pluginObj)
{
if (pluginObj.hasOwnProperty('data_filters')) {
let dataFilters = pluginObj.data_filters;
// Loop through 'data_filters' array and appply filters on individual plugin entries
for (let i = 0; i < dataFilters.length; i++) {
compare_field_id = dataFilters[i].compare_field_id;
compare_column = dataFilters[i].compare_column;
compare_operator = dataFilters[i].compare_operator;
compare_js_template = dataFilters[i].compare_js_template;
compare_use_quotes = dataFilters[i].compare_use_quotes;
compare_field_id_value = $(`#${compare_field_id}`).val();
// apply filter i sthe filter field has a valid value
if(compare_field_id_value != undefined && compare_field_id_value != '--')
{
// valid value
// resolve the left and right part of the comparison
let left = compare_js_template.replace('{value}', `${compare_field_id_value}`)
let right = compare_js_template.replace('{value}', `${entry[compare_column]}`)
// include wrapper quotes if specified
compare_use_quotes ? quotes = '"' : quotes = ''
result = eval(
quotes + `${eval(left)}` + quotes +
` ${compare_operator} ` +
quotes + `${eval(right)}` + quotes
);
return result;
}
}
}
return true;
}
// --------------------------------------------------------
// Data cleanup/purge functionality
plugPrefix = ''
dbTable = ''
function purgeAll(callback) {
plugPrefix = arguments[0]; // plugin prefix
dbTable = arguments[1]; // DB table
// Ask
showModalWarning('<?= lang('Gen_Purge');?>' + ' ' + plugPrefix + ' ' + dbTable , '<?= lang('Gen_AreYouSure');?>',
'<?= lang('Gen_Cancel');?>', '<?= lang('Gen_Okay');?>', "purgeAllExecute");
}
// --------------------------------------------------------
function purgeAllExecute() {
$.ajax({
method: "POST",
url: "php/server/dbHelper.php",
data: { action: "delete", dbtable: dbTable, columnName: 'Plugin', id:plugPrefix },
success: function(data, textStatus) {
showModalOk ('Result', data );
}
})
}
// --------------------------------------------------------
function deleteListed(plugPrefix, dbTable) {
idArr = $(`#${plugPrefix} table[data-my-dbtable="${dbTable}"] tr[data-my-index]`).map(function(){return $(this).attr("data-my-index");}).get();
console.log(idArr);
$.ajax({
method: "POST",
url: "php/server/dbHelper.php",
data: { action: "delete", dbtable: dbTable, columnName: 'Index', id:idArr.toString() },
success: function(data, textStatus) {
updateApi("plugins_objects")
showModalOk ('Result', data );
}
})
}
// -----------------------------------------------------------------------------
// Main sequence
// show spinning icon
showSpinner()
getData()
updater()
</script>