mirror of
https://github.com/jokob-sk/NetAlertX.git
synced 2025-12-07 09:36:05 -08:00
Notification Report page rewrite v0.1📩
This commit is contained in:
@@ -585,8 +585,24 @@ height: 50px;
|
||||
.infobox_label {
|
||||
font-size: 16px !important;
|
||||
}
|
||||
/* --------------------------------------------------------- */
|
||||
/* report */
|
||||
/* --------------------------------------------------------- */
|
||||
|
||||
/*settings*/
|
||||
#notificationData textarea{
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#notificationData pre {outline: 1px solid #ccc; padding: 5px; margin: 5px; }
|
||||
.string { color: green; }
|
||||
.number { color: darkorange; }
|
||||
.boolean { color: blue; }
|
||||
.null { color: magenta; }
|
||||
.key { color: red; }
|
||||
|
||||
/* --------------------------------------------------------- */
|
||||
/* settings */
|
||||
/* --------------------------------------------------------- */
|
||||
|
||||
@media (max-width: 767px) {
|
||||
/* hide on mobile */
|
||||
|
||||
@@ -304,6 +304,32 @@ function showMessage (textMessage="") {
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// String utilities
|
||||
// -----------------------------------------------------------------------------
|
||||
function jsonSyntaxHighlight(json) {
|
||||
if (typeof json != 'string') {
|
||||
json = JSON.stringify(json, undefined, 2);
|
||||
}
|
||||
json = json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
||||
return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
|
||||
var cls = 'number';
|
||||
if (/^"/.test(match)) {
|
||||
if (/:$/.test(match)) {
|
||||
cls = 'key';
|
||||
} else {
|
||||
cls = 'string';
|
||||
}
|
||||
} else if (/true|false/.test(match)) {
|
||||
cls = 'boolean';
|
||||
} else if (/null/.test(match)) {
|
||||
cls = 'null';
|
||||
}
|
||||
return '<span class="' + cls + '">' + match + '</span>';
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// General utilities
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
@@ -20,21 +20,21 @@ if(array_key_exists('function', $_REQUEST) != FALSE)
|
||||
{
|
||||
$FUNCTION = $_REQUEST['function'];
|
||||
}
|
||||
if(array_key_exists('settings', $_REQUEST) != FALSE)
|
||||
{
|
||||
$SETTINGS = $_REQUEST['settings'];
|
||||
}
|
||||
|
||||
|
||||
// call functions based on requested params
|
||||
switch ($FUNCTION) {
|
||||
case 'savesettings':
|
||||
|
||||
saveSettings();
|
||||
break;
|
||||
|
||||
case 'cleanLog':
|
||||
|
||||
if(array_key_exists('settings', $_REQUEST) != FALSE)
|
||||
{
|
||||
$SETTINGS = $_REQUEST['settings'];
|
||||
}
|
||||
|
||||
cleanLog($SETTINGS);
|
||||
break;
|
||||
|
||||
|
||||
@@ -452,7 +452,7 @@
|
||||
"run_event_tooltip" : "Enable the setting and save your changes at first before you run it.",
|
||||
"run_event_icon" : "fa-play",
|
||||
"general_event_title" : "Executing an ad-hoc event",
|
||||
"general_event_description" : " The event you nove triggered might take a while until background processes finish. The execution ended once you see <code>finished</code> below. Check the <a href='/maintenance.php#tab_Logging'>error log</a> if you didn not get the expected result. <br/> <br/> Status: ",
|
||||
"general_event_description" : " The event you nove triggered might take a while until background processes finish. The execution ended once the below execution queue empties (Check the <a href='/maintenance.php#tab_Logging'>error log</a> if you envounter issues). <br/> <br/> Execution queue:",
|
||||
"Plugins_Unprocessed_Events" : "Unprocessed Events",
|
||||
"Plugins_Objects" : "Plugin Objects",
|
||||
"Plugins_DeleteAll" : "Delete all (filters are ignored)",
|
||||
@@ -603,6 +603,8 @@
|
||||
"Systeminfo_System_Uname": "Uname:",
|
||||
"Systeminfo_System_Uptime": "Uptime:",
|
||||
"Systeminfo_USB_Devices" : "USB Devices",
|
||||
"report_select_format": "Select Format:",
|
||||
"report_time": "Notification time:",
|
||||
"Donations_Title" : "Donations",
|
||||
"Donations_Text" : "Hey 👋! </br> Thanks for clicking on this menu item 😅 </br> </br> I'm trying to collect some donations to make you better software. Also, it would help me not to get burned out. Me burning out might mean end of support for this app. Any small (recurring or not) sponsorship makes me want ot put more effort into this app. I don't want to lock features (new plugins) behind paywalls 🔐. </br> Currently, I'm waking up 2h before work so I contribute to the app a bit. If I had some recurring income I could shorten my workweek and in the remaining time fully focus on PiAlert. You'd get more functionality, a more polished app and less bugs. </br> </br> Thanks for reading - I'm super grateful for any support ❤🙏 </br> </br> TL;DR: By supporting me you get: </br> </br> <ul><li>Regular updates to keep your data and family safe 🔄</li><li>Less bugs 🐛🔫</li><li>Better and more functionality➕</li><li>I don't get burned out 🔥🤯</li><li>Less rushed releases 💨</li><li>Better docs📚</li><li>Quicker and better support with issues 🆘</li><li>Less grumpy me 😄</li></ul> </br> 📧Email me to <a href='mailto:jokob@duck.com?subject=PiAlert'>jokob@duck.com</a> if you want to get in touch or if I should add other sponsorship platforms. </br>",
|
||||
"Donations_Platforms" : "Sponsor platforms",
|
||||
|
||||
@@ -127,9 +127,14 @@
|
||||
"column": "Watched_Value1",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"type": "eval",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"options": [
|
||||
{
|
||||
"type": "eval",
|
||||
"param": "`<a href='/report?guid=${value}'>${value}</a>`"
|
||||
}
|
||||
],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
|
||||
@@ -156,9 +156,14 @@
|
||||
"column": "Watched_Value1",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"type": "eval",
|
||||
"default_value":"",
|
||||
"options": [
|
||||
{
|
||||
"type": "eval",
|
||||
"param": "`<a href='/report?guid=${value}'>${value}</a>`"
|
||||
}
|
||||
],
|
||||
"localized": [
|
||||
"name"
|
||||
],
|
||||
|
||||
@@ -94,9 +94,14 @@
|
||||
"column": "Watched_Value1",
|
||||
"css_classes": "col-sm-3",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"type": "eval",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"options": [
|
||||
{
|
||||
"type": "eval",
|
||||
"param": "`<a href='/report?guid=${value}'>${value}</a>`"
|
||||
}
|
||||
],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
|
||||
@@ -94,9 +94,14 @@
|
||||
"column": "Watched_Value1",
|
||||
"css_classes": "col-sm-3",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"type": "eval",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"options": [
|
||||
{
|
||||
"type": "eval",
|
||||
"param": "`<a href='/report?guid=${value}'>${value}</a>`"
|
||||
}
|
||||
],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
|
||||
@@ -94,9 +94,14 @@
|
||||
"column": "Watched_Value1",
|
||||
"css_classes": "col-sm-3",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"type": "eval",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"options": [
|
||||
{
|
||||
"type": "eval",
|
||||
"param": "`<a href='/report?guid=${value}'>${value}</a>`"
|
||||
}
|
||||
],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
|
||||
@@ -169,6 +169,14 @@ function processColumnValue(dbColumnDef, value, index, type) {
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'eval':
|
||||
|
||||
for (const option of dbColumnDef.options) {
|
||||
if (option.type === type) {
|
||||
value = eval(value);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
value = value + `<div style='text-align:center' title="${getString("Plugins_no_control")}"><i class='fa-solid fa-circle-question'></i></div>` ;
|
||||
|
||||
151
front/report.php
151
front/report.php
@@ -30,20 +30,145 @@
|
||||
<!-- Main content ---------------------------------------------------------- -->
|
||||
<section class="content">
|
||||
|
||||
<?php
|
||||
// Check if the page exists
|
||||
if (file_exists("api/notification_text.html")) {
|
||||
// Load the page
|
||||
include("api/notification_text.html");
|
||||
} else {
|
||||
// Display an error message
|
||||
echo "<h2>Error</h2>";
|
||||
echo lang('REPORT_ERROR');
|
||||
}
|
||||
?>
|
||||
<div class="col-sm-2">
|
||||
<!-- Display data and navigation buttons -->
|
||||
<div id="notificationContainer">
|
||||
<div id="navigationButtons">
|
||||
<button class="btn btn-default text-gray50" id="prevButton">
|
||||
<i class="fa fa-chevron-left"></i>
|
||||
</button>
|
||||
<span id="notificationOutOff"></span>
|
||||
<button class="btn btn-default text-gray50" id="nextButton">
|
||||
<i class="fa fa-chevron-right"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
<!-- Select format -->
|
||||
<div class="col-sm-2 ">
|
||||
<label for="formatSelect">
|
||||
<?= lang('report_select_format') ;?>
|
||||
</label>
|
||||
<select id="formatSelect" class="pointer">
|
||||
<option value="HTML">HTML</option>
|
||||
<option value="JSON">JSON</option>
|
||||
<option value="Text">Text</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="col-sm-8">
|
||||
<label><?= lang('report_time') ;?></label>
|
||||
<span id="timestamp">Timestamp</span>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="col-sm-12" id="notificationData">
|
||||
<!-- Data will be displayed here -->
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- JavaScript to fetch and display data based on selected format -->
|
||||
<script>
|
||||
// JavaScript to fetch and display data based on selected format
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const notificationData = document.getElementById('notificationData');
|
||||
const timestamp = document.getElementById('timestamp');
|
||||
const prevButton = document.getElementById('prevButton');
|
||||
const nextButton = document.getElementById('nextButton');
|
||||
const formatSelect = document.getElementById('formatSelect');
|
||||
|
||||
let currentIndex = -1; // Current report index
|
||||
|
||||
// Function to update the displayed data and timestamp based on the selected format and index
|
||||
function updateData(format, index) {
|
||||
// Fetch data from the API endpoint
|
||||
fetch('/api/table_notifications.json')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (index < 0) {
|
||||
index = data.data.length - 1;
|
||||
} else if (index >= data.data.length) {
|
||||
index = 0;
|
||||
}
|
||||
|
||||
const notification = data.data[index];
|
||||
const formatData = notification[format];
|
||||
|
||||
// Display the selected format data and update timestamp
|
||||
switch (format) {
|
||||
case 'HTML':
|
||||
notificationData.innerHTML = formatData;
|
||||
break;
|
||||
case 'JSON':
|
||||
notificationData.innerHTML = `<pre class="logs" cols="70" rows="10" wrap="off" readonly="">
|
||||
${jsonSyntaxHighlight(JSON.stringify(JSON.parse(formatData), undefined, 4))}
|
||||
</pre>`;
|
||||
break;
|
||||
case 'Text':
|
||||
notificationData.innerHTML = `<pre class="logs" cols="70" rows="10" wrap="off" readonly">${formatData}</pre>`;
|
||||
break;
|
||||
}
|
||||
|
||||
timestamp.textContent = notification.DateTimeCreated;
|
||||
currentIndex = index;
|
||||
|
||||
$("#notificationOutOff").html(`${currentIndex + 1}/${data.data.length}`);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
});
|
||||
}
|
||||
|
||||
// Function to find the index of a notification by GUID
|
||||
function findIndexByGUID(data, guid) {
|
||||
return data.findIndex(notification => notification.GUID === guid);
|
||||
}
|
||||
|
||||
// Listen for format selection changes
|
||||
formatSelect.addEventListener('change', () => {
|
||||
updateData(formatSelect.value, currentIndex);
|
||||
});
|
||||
|
||||
// Listen for previous button click
|
||||
prevButton.addEventListener('click', () => {
|
||||
updateData(formatSelect.value, currentIndex - 1);
|
||||
});
|
||||
|
||||
// Listen for next button click
|
||||
nextButton.addEventListener('click', () => {
|
||||
updateData(formatSelect.value, currentIndex + 1);
|
||||
});
|
||||
|
||||
// Check if there is a GUID query parameter
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
if (urlParams.has('guid')) {
|
||||
const guid = urlParams.get('guid');
|
||||
fetch('/api/table_notifications.json')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
const index = findIndexByGUID(data.data, guid);
|
||||
if (index !== -1) {
|
||||
// Load the notification with the specified GUID
|
||||
updateData(formatSelect.value, index);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
});
|
||||
} else {
|
||||
|
||||
// Initial data load
|
||||
updateData('HTML', -1); // Default format to HTML and load the latest report
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<!-- /.content -->
|
||||
<?php
|
||||
|
||||
@@ -839,41 +839,6 @@ while ($row = $result -> fetchArray (SQLITE3_ASSOC)) {
|
||||
|
||||
modalEventStatusId = 'modal-message-front-event'
|
||||
|
||||
function handleEvent (element){
|
||||
|
||||
// value has to be in format event|param. e.g. run|ARPSCAN
|
||||
value = $(element).attr('data-myevent') + '|'+ $(element).attr('data-myparam-plugin')
|
||||
|
||||
setParameter ('Front_Event', value)
|
||||
|
||||
// show message
|
||||
showModalOk("<?= lang("general_event_title")?>", "<?= lang("general_event_description")?> <code id='"+modalEventStatusId+"'></code>");
|
||||
|
||||
// Periodically update state of the requested action
|
||||
getParam(modalEventStatusId,"Front_Event", true, updateModalState)
|
||||
|
||||
updateModalState()
|
||||
}
|
||||
|
||||
|
||||
// function updateModalState(){
|
||||
|
||||
// setTimeout(function(){
|
||||
// displayedEvent = $('#'+modalEventStatusId).html()
|
||||
|
||||
// // loop until finished
|
||||
// if(displayedEvent.indexOf('finished') == -1) // if the message is different from finished, check again in 2s
|
||||
// {
|
||||
|
||||
// getParam(modalEventStatusId,"Front_Event", true)
|
||||
|
||||
// updateModalState()
|
||||
|
||||
// }
|
||||
// }, 2000);
|
||||
// }
|
||||
|
||||
|
||||
// --------------------------------------------------------
|
||||
// Calls a backend function to add a front-end event (specified by the attributes 'data-myevent' and 'data-myparam-plugin' on the passed element) to an execution queue
|
||||
function addToExecutionQueue(element)
|
||||
@@ -882,34 +847,34 @@ function addToExecutionQueue(element)
|
||||
// value has to be in format event|param. e.g. run|ARPSCAN
|
||||
action = `${getGuid()}|${$(element).attr('data-myevent')}|${$(element).attr('data-myparam-plugin')}`
|
||||
|
||||
// addToExecutionQueue(action)
|
||||
|
||||
$.ajax({
|
||||
method: "POST",
|
||||
url: "php/server/util.php",
|
||||
data: { function: "addToExecutionQueue", action: action },
|
||||
success: function(data, textStatus) {
|
||||
showModalOk ('Result', data );
|
||||
// showModalOk ('Result', data );
|
||||
|
||||
// show message
|
||||
showModalOk(getString("general_event_title"), `${getString("general_event_description")} <br/> <br/> <code id='${modalEventStatusId}'></code>`);
|
||||
|
||||
updateModalState()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// TODO
|
||||
// --------------------------------------------------------
|
||||
// Updating the execution queue in in modal pop-up
|
||||
function updateModalState() {
|
||||
setTimeout(function() {
|
||||
// Fetch the content from the log file using an AJAX request
|
||||
$.ajax({
|
||||
url: '~/log/execution_queue.log',
|
||||
url: '/log/execution_queue.log',
|
||||
type: 'GET',
|
||||
success: function(data) {
|
||||
// Update the content of the HTML element (e.g., a div with id 'logContent')
|
||||
$('#logContent').html(data);
|
||||
$('#'+modalEventStatusId).html(data);
|
||||
|
||||
// Check if the displayed content contains 'finished'
|
||||
if (data.indexOf('finished') === -1) {
|
||||
// If not finished, continue to update
|
||||
updateModalState();
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
// Handle error, such as the file not being found
|
||||
@@ -919,11 +884,6 @@ function updateModalState() {
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
// Call the function to start the periodic updates
|
||||
updateModalState();
|
||||
|
||||
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// handling events on the backend initiated by the front end END
|
||||
|
||||
@@ -727,38 +727,6 @@ class plugin_object_class:
|
||||
#===============================================================================
|
||||
# Handling of user initialized front-end events
|
||||
#===============================================================================
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# def check_and_run_user_event(db, pluginsState):
|
||||
|
||||
# sql = db.sql # TO-DO
|
||||
# sql.execute(""" select * from Parameters where par_ID = "Front_Event" """)
|
||||
# rows = sql.fetchall()
|
||||
|
||||
# event, param = ['','']
|
||||
# if len(rows) > 0 and rows[0]['par_Value'] != 'finished':
|
||||
# keyValue = rows[0]['par_Value'].split('|')
|
||||
|
||||
# if len(keyValue) == 2:
|
||||
# event = keyValue[0]
|
||||
# param = keyValue[1]
|
||||
# else:
|
||||
# return pluginsState
|
||||
|
||||
# if event == 'test':
|
||||
# pluginsState = handle_test(param, db, pluginsState)
|
||||
# if event == 'run':
|
||||
# pluginsState = handle_run(param, db, pluginsState)
|
||||
|
||||
# # clear event execution flag
|
||||
# sql.execute ("UPDATE Parameters SET par_Value='finished' WHERE par_ID='Front_Event'")
|
||||
|
||||
# # commit to DB
|
||||
# db.commitDB()
|
||||
|
||||
# return pluginsState
|
||||
|
||||
|
||||
def check_and_run_user_event(db, pluginsState):
|
||||
# Check if the log file exists
|
||||
logFile = os.path.join(logPath, "execution_queue.log")
|
||||
|
||||
Reference in New Issue
Block a user