Notification Report page rewrite v0.1📩

This commit is contained in:
Jokob-sk
2023-10-25 22:35:07 +11:00
parent 0ed24dac0a
commit fd162ff98a
13 changed files with 245 additions and 115 deletions

View File

@@ -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 */

View File

@@ -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, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
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
// -----------------------------------------------------------------------------

View File

@@ -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;

View File

@@ -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",

View File

@@ -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",

View File

@@ -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"
],

View File

@@ -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",

View File

@@ -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",

View File

@@ -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",

View File

@@ -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>` ;

View File

@@ -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

View File

@@ -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

View File

@@ -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")