mirror of
https://github.com/jokob-sk/NetAlertX.git
synced 2026-04-15 22:51:37 -07:00
Icon selector
This commit is contained in:
@@ -1226,6 +1226,52 @@ input[readonly] {
|
|||||||
/* Devices page */
|
/* Devices page */
|
||||||
/* ----------------------------------------------------------------- */
|
/* ----------------------------------------------------------------- */
|
||||||
|
|
||||||
|
.modal-header .close
|
||||||
|
{
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-title
|
||||||
|
{
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
#iconList
|
||||||
|
{
|
||||||
|
padding: 10px;
|
||||||
|
padding-bottom:30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconPreviewSelector:hover
|
||||||
|
{
|
||||||
|
backdrop-filter: brightness(50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconPreviewSelector
|
||||||
|
{
|
||||||
|
text-align: center;
|
||||||
|
padding: 15px;
|
||||||
|
height: 80px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconList
|
||||||
|
{
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconPreviewSelector svg
|
||||||
|
{
|
||||||
|
width:40px;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconPreviewSelector i
|
||||||
|
{
|
||||||
|
font-size: 30px;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
.iconPreview {
|
.iconPreview {
|
||||||
min-width: 40px;
|
min-width: 40px;
|
||||||
}
|
}
|
||||||
|
|||||||
+56
-37
@@ -16,6 +16,7 @@
|
|||||||
require 'php/templates/header.php';
|
require 'php/templates/header.php';
|
||||||
?>
|
?>
|
||||||
|
|
||||||
|
|
||||||
<!-- Page ------------------------------------------------------------------ -->
|
<!-- Page ------------------------------------------------------------------ -->
|
||||||
<div class="content-wrapper">
|
<div class="content-wrapper">
|
||||||
|
|
||||||
@@ -214,9 +215,7 @@ switch ($UI_THEME) {
|
|||||||
?>
|
?>
|
||||||
|
|
||||||
<!-- page script ----------------------------------------------------------- -->
|
<!-- page script ----------------------------------------------------------- -->
|
||||||
<script defer>
|
<script >
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------
|
// ------------------------------------------------------------
|
||||||
|
|
||||||
@@ -238,11 +237,16 @@ switch ($UI_THEME) {
|
|||||||
var selectedTab = 'tabDetails';
|
var selectedTab = 'tabDetails';
|
||||||
var emptyArr = ['undefined', "", undefined, null];
|
var emptyArr = ['undefined', "", undefined, null];
|
||||||
|
|
||||||
main();
|
|
||||||
|
|
||||||
|
// Call renderSmallBoxes, then main
|
||||||
|
(async () => {
|
||||||
|
await renderSmallBoxes();
|
||||||
|
main();
|
||||||
|
})();
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
function main () {
|
function main () {
|
||||||
|
|
||||||
// Initialize MAC
|
// Initialize MAC
|
||||||
var urlParams = new URLSearchParams(window.location.search);
|
var urlParams = new URLSearchParams(window.location.search);
|
||||||
if (urlParams.has ('mac') == true) {
|
if (urlParams.has ('mac') == true) {
|
||||||
@@ -670,40 +674,23 @@ function initTable(tableId, mac){
|
|||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Render the small boxes on top
|
// Render the small boxes on top
|
||||||
function renderSmallBoxes(customData) {
|
async function renderSmallBoxes() {
|
||||||
$.ajax({
|
|
||||||
url: 'php/components/device_cards.php', // PHP script URL
|
|
||||||
type: 'POST', // Use POST method to send data
|
try {
|
||||||
dataType: 'html', // Expect HTML response
|
// Show loading dialog
|
||||||
data: { items: JSON.stringify(customData) }, // Send customData as JSON
|
showSpinner();
|
||||||
success: function(response) {
|
|
||||||
$('#TopSmallBoxes').html(response); // Replace container content with fetched HTML
|
// Get data from the server
|
||||||
hideSpinner()
|
const response = await fetch(`php/server/devices.php?action=getServerDeviceData&mac=${getMac()}&period=${period}`);
|
||||||
},
|
if (!response.ok) {
|
||||||
error: function(xhr, status, error) {
|
throw new Error(`Error fetching device data: ${response.statusText}`);
|
||||||
console.error('Error fetching small boxes:', error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------------
|
const deviceData = await response.json();
|
||||||
|
|
||||||
window.onload = function async()
|
|
||||||
{
|
|
||||||
initializeTabs();
|
|
||||||
|
|
||||||
|
|
||||||
// get data from server
|
|
||||||
$.get('php/server/devices.php?action=getServerDeviceData&mac='+ mac + '&period='+ period, function(data) {
|
|
||||||
|
|
||||||
// show loading dialog
|
|
||||||
showSpinner()
|
|
||||||
|
|
||||||
var deviceData = JSON.parse(data);
|
|
||||||
|
|
||||||
console.log(deviceData);
|
console.log(deviceData);
|
||||||
|
|
||||||
|
// Prepare custom data
|
||||||
const customData = [
|
const customData = [
|
||||||
{
|
{
|
||||||
"onclickEvent": "$('#tabDetails').trigger('click')",
|
"onclickEvent": "$('#tabDetails').trigger('click')",
|
||||||
@@ -733,7 +720,7 @@ window.onload = function async()
|
|||||||
"labelLang": "DevDetail_Shortcut_Presence",
|
"labelLang": "DevDetail_Shortcut_Presence",
|
||||||
"iconId": "deviceEventsIcon",
|
"iconId": "deviceEventsIcon",
|
||||||
"iconClass": "fa fa-calendar",
|
"iconClass": "fa fa-calendar",
|
||||||
"dataValue": deviceData.devPresenceHours + 'h'
|
"dataValue": `${deviceData.devPresenceHours}h`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"onclickEvent": "$('#tabEvents').trigger('click');",
|
"onclickEvent": "$('#tabEvents').trigger('click');",
|
||||||
@@ -747,11 +734,43 @@ window.onload = function async()
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
renderSmallBoxes(customData);
|
// Send data to render small boxes
|
||||||
|
const cardResponse = await fetch('php/components/device_cards.php', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ items: customData })
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (!cardResponse.ok) {
|
||||||
|
throw new Error(`Error rendering small boxes: ${cardResponse.statusText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const html = await cardResponse.text();
|
||||||
|
|
||||||
|
$('#TopSmallBoxes').html(html);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error in renderSmallBoxes:', error);
|
||||||
|
} finally {
|
||||||
|
// Hide loading dialog
|
||||||
|
hideSpinner();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
window.onload = function async()
|
||||||
|
{
|
||||||
|
initializeTabs();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -181,6 +181,15 @@
|
|||||||
</span>`;
|
</span>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// handle generate IP for new device
|
||||||
|
if (setting.setKey == "NEWDEV_devIcon") {
|
||||||
|
inlineControl += `<span class="input-group-addon pointer"
|
||||||
|
onclick="showIconSelection()"
|
||||||
|
title="${getString("Gen_Select")}">
|
||||||
|
<i class="fa-solid fa-chevron-down" ></i>
|
||||||
|
</span>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Generate the input field HTML
|
// Generate the input field HTML
|
||||||
const inputFormHtml = `<div class="form-group col-xs-12">
|
const inputFormHtml = `<div class="form-group col-xs-12">
|
||||||
@@ -413,14 +422,6 @@
|
|||||||
|
|
||||||
showMessage (msg);
|
showMessage (msg);
|
||||||
|
|
||||||
|
|
||||||
// clear session storage
|
|
||||||
setCache("#dropdownOwner","");
|
|
||||||
setCache("#dropdownDeviceType","");
|
|
||||||
setCache("#dropdownGroup","");
|
|
||||||
setCache("#dropdownLocation","");
|
|
||||||
setCache("#dropdownNetworkNodeMac","");
|
|
||||||
|
|
||||||
// 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;
|
||||||
somethingChanged = false;
|
somethingChanged = false;
|
||||||
@@ -438,15 +439,6 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to clear dropdown cache
|
|
||||||
function clearDropdownCache() {
|
|
||||||
setCache("#dropdownOwner", "");
|
|
||||||
setCache("#dropdownDeviceType", "");
|
|
||||||
setCache("#dropdownGroup", "");
|
|
||||||
setCache("#dropdownLocation", "");
|
|
||||||
setCache("#dropdownNetworkNodeMac", "");
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------------
|
||||||
// Disables or enables network configuration for the root node
|
// Disables or enables network configuration for the root node
|
||||||
function toggleNetworkConfiguration(disable) {
|
function toggleNetworkConfiguration(disable) {
|
||||||
|
|||||||
@@ -387,6 +387,89 @@ function addIconAsBase64 (el) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function showIconSelection() {
|
||||||
|
const selectElement = document.getElementById('NEWDEV_devIcon');
|
||||||
|
const modalId = 'dynamicIconModal';
|
||||||
|
|
||||||
|
// Create modal HTML dynamically
|
||||||
|
const modalHTML = `
|
||||||
|
<div id="${modalId}" class="modal fade" tabindex="-1" role="dialog">
|
||||||
|
<div class="modal-dialog" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">${getString("Gen_Select")}</h5>
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div id="iconList" class="row"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Append the modal to the body
|
||||||
|
document.body.insertAdjacentHTML('beforeend', modalHTML);
|
||||||
|
|
||||||
|
const iconList = document.getElementById('iconList');
|
||||||
|
|
||||||
|
// Populate the icon list
|
||||||
|
Array.from(selectElement.options).forEach(option => {
|
||||||
|
if (option.value != "") {
|
||||||
|
|
||||||
|
|
||||||
|
const value = option.value;
|
||||||
|
|
||||||
|
// Decode the base64 value
|
||||||
|
let decodedValue;
|
||||||
|
try {
|
||||||
|
decodedValue = atob(value);
|
||||||
|
} catch (e) {
|
||||||
|
console.warn(`Skipping invalid base64 value: ${value}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create an icon container
|
||||||
|
const iconDiv = document.createElement('div');
|
||||||
|
iconDiv.classList.add('iconPreviewSelector','col-md-2' , 'col-sm-3', 'col-xs-4');
|
||||||
|
iconDiv.style.cursor = 'pointer';
|
||||||
|
|
||||||
|
// Render the SVG or HTML content
|
||||||
|
const iconContainer = document.createElement('div');
|
||||||
|
iconContainer.innerHTML = decodedValue;
|
||||||
|
|
||||||
|
// Append the icon to the div
|
||||||
|
iconDiv.appendChild(iconContainer);
|
||||||
|
iconList.appendChild(iconDiv);
|
||||||
|
|
||||||
|
// Add click event to select icon
|
||||||
|
iconDiv.addEventListener('click', () => {
|
||||||
|
selectElement.value = value; // Update the select element value
|
||||||
|
$(`#${modalId}`).modal('hide'); // Hide the modal
|
||||||
|
updateIconPreview();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Show the modal using AJAX
|
||||||
|
$(`#${modalId}`).modal('show');
|
||||||
|
|
||||||
|
// Remove modal from DOM after it's hidden
|
||||||
|
$(`#${modalId}`).on('hidden.bs.modal', function () {
|
||||||
|
document.getElementById(modalId).remove();
|
||||||
|
});
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// initialize
|
// initialize
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
require '../server/init.php';
|
require '../server/init.php';
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// check if authenticated
|
// Check if authenticated
|
||||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/php/templates/security.php';
|
require_once $_SERVER['DOCUMENT_ROOT'] . '/php/templates/security.php';
|
||||||
|
|
||||||
function renderSmallBox($params) {
|
function renderSmallBox($params) {
|
||||||
@@ -21,7 +21,7 @@ function renderSmallBox($params) {
|
|||||||
<a href="#" onclick="javascript: ' . htmlspecialchars($onclickEvent) . '">
|
<a href="#" onclick="javascript: ' . htmlspecialchars($onclickEvent) . '">
|
||||||
<div class="small-box ' . htmlspecialchars($color) . '">
|
<div class="small-box ' . htmlspecialchars($color) . '">
|
||||||
<div class="inner">
|
<div class="inner">
|
||||||
<h3 id="' . htmlspecialchars($headerId) . '" style="' . htmlspecialchars($headerStyle) . '"> '.$dataValue.' </h3>
|
<h3 id="' . htmlspecialchars($headerId) . '" style="' . htmlspecialchars($headerStyle) . '"> ' . htmlspecialchars($dataValue) . ' </h3>
|
||||||
<p class="infobox_label">' . lang(htmlspecialchars($labelLang)) . '</p>
|
<p class="infobox_label">' . lang(htmlspecialchars($labelLang)) . '</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="icon">
|
<div class="icon">
|
||||||
@@ -36,14 +36,20 @@ function renderSmallBox($params) {
|
|||||||
$defaultDataFile = 'device_cards_defaults.json';
|
$defaultDataFile = 'device_cards_defaults.json';
|
||||||
$defaultData = file_exists($defaultDataFile) ? json_decode(file_get_contents($defaultDataFile), true) : [];
|
$defaultData = file_exists($defaultDataFile) ? json_decode(file_get_contents($defaultDataFile), true) : [];
|
||||||
|
|
||||||
// Check if 'items' parameter exists and is valid JSON
|
// Decode raw JSON input from body
|
||||||
$items = isset($_POST['items']) ? json_decode($_POST['items'], true) : [];
|
$requestBody = file_get_contents('php://input');
|
||||||
|
$data = json_decode($requestBody, true);
|
||||||
|
|
||||||
// Use default data if 'items' is not provided or cannot be decoded
|
// Debugging logs
|
||||||
if (empty($items)) {
|
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||||
$items = $defaultData;
|
error_log('JSON Decode Error: ' . json_last_error_msg());
|
||||||
|
error_log('Raw body: ' . $requestBody);
|
||||||
|
$data = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Extract 'items' or fall back to default data
|
||||||
|
$items = isset($data['items']) ? $data['items'] : $defaultData;
|
||||||
|
|
||||||
// Generate HTML
|
// Generate HTML
|
||||||
$html = '<div class="row">';
|
$html = '<div class="row">';
|
||||||
foreach ($items as $item) {
|
foreach ($items as $item) {
|
||||||
|
|||||||
@@ -309,6 +309,7 @@
|
|||||||
"Gen_Saved": "Saved",
|
"Gen_Saved": "Saved",
|
||||||
"Gen_Search": "Search",
|
"Gen_Search": "Search",
|
||||||
"Gen_SelectToPreview": "Select to preview",
|
"Gen_SelectToPreview": "Select to preview",
|
||||||
|
"Gen_Select": "Select",
|
||||||
"Gen_Selected_Devices": "Selected Devices:",
|
"Gen_Selected_Devices": "Selected Devices:",
|
||||||
"Gen_Switch": "Switch",
|
"Gen_Switch": "Switch",
|
||||||
"Gen_Upd": "Updated successfully",
|
"Gen_Upd": "Updated successfully",
|
||||||
|
|||||||
+2
-2
@@ -186,11 +186,11 @@ def main ():
|
|||||||
|
|
||||||
# Footer
|
# Footer
|
||||||
|
|
||||||
mylog('verbose', ['[MAIN] Process: Wait'])
|
mylog('verbose', ['[MAIN] Process: Idle'])
|
||||||
else:
|
else:
|
||||||
# do something
|
# do something
|
||||||
# mylog('verbose', ['[MAIN] Waiting to start next loop'])
|
# mylog('verbose', ['[MAIN] Waiting to start next loop'])
|
||||||
updateState("Process: Wait")
|
updateState("Process: Idle")
|
||||||
|
|
||||||
|
|
||||||
#loop
|
#loop
|
||||||
|
|||||||
@@ -64,4 +64,4 @@ def start_server(graphql_port, app_state):
|
|||||||
thread.start()
|
thread.start()
|
||||||
|
|
||||||
# Update the state to indicate the server has started
|
# Update the state to indicate the server has started
|
||||||
app_state = updateState("Process: Wait", None, None, None, 1)
|
app_state = updateState("Process: Idle", None, None, None, 1)
|
||||||
Reference in New Issue
Block a user