More icons work 🔨
This commit is contained in:
@@ -29,11 +29,11 @@ Copying the HTML code from [Font Awesome](https://fontawesome.com/search?o=r&m=f
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
3. Paste in the copied HTML or SVG code.
|
3. Paste in the copied HTML or SVG code and click "OK":
|
||||||
|
|
||||||
4. Click "OK"
|

|
||||||
|
|
||||||
5. "Save" the device
|
6. "Save" the device
|
||||||
|
|
||||||
> [!NOTE]
|
> [!NOTE]
|
||||||
> If you want to mass-apply an icon to all devices of the same device type (Field: Type), you can click the mass-copy button (next to the "+" button). A confirmation prompt is displayed. If you proceed, icons of all devices set to the same device type as the current device, will be overwritten with the current device's icon.
|
> If you want to mass-apply an icon to all devices of the same device type (Field: Type), you can click the mass-copy button (next to the "+" button). A confirmation prompt is displayed. If you proceed, icons of all devices set to the same device type as the current device, will be overwritten with the current device's icon.
|
||||||
|
|||||||
BIN
docs/img/ICONS/paste-svg.png
Executable file
BIN
docs/img/ICONS/paste-svg.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 58 KiB |
@@ -748,28 +748,13 @@ function main () {
|
|||||||
|
|
||||||
// Show device icon as it changes
|
// Show device icon as it changes
|
||||||
$('#txtIcon').on('change input', function() {
|
$('#txtIcon').on('change input', function() {
|
||||||
updateIconPreview()
|
updateIconPreview('#txtIcon')
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
function updateIconPreview () {
|
|
||||||
// update icon
|
|
||||||
iconInput = $('#txtIcon')
|
|
||||||
|
|
||||||
value = iconInput.val()
|
|
||||||
|
|
||||||
iconInput.on('change input', function() {
|
|
||||||
$('#txtIconFA').html(atob(value))
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#txtIconFA').html(atob(value))
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
function initializeTabs () {
|
function initializeTabs () {
|
||||||
// Activate panel
|
// Activate panel
|
||||||
@@ -839,12 +824,12 @@ function initializeCombos () {
|
|||||||
// nameTransformer) // callback to transform name
|
// nameTransformer) // callback to transform name
|
||||||
|
|
||||||
|
|
||||||
initSettingDropdown("NEWDEV_dev_Icon", [], "dropdownIcon_tmp", genDevDetailsList, 'txtIcon', atob )
|
initSettingDropdown("NEWDEV_dev_Icon", [], "dropdownIcon_tmp", genListWithInputSet, 'txtIcon', atob )
|
||||||
initSettingDropdown("NEWDEV_dev_DeviceType", [], "dropdownDeviceType_tmp", genDevDetailsList, 'txtDeviceType' )
|
initSettingDropdown("NEWDEV_dev_DeviceType", [], "dropdownDeviceType_tmp", genListWithInputSet, 'txtDeviceType' )
|
||||||
initSettingDropdown("NEWDEV_dev_Owner", [], "dropdownOwner_tmp", genDevDetailsList, 'txtOwner' )
|
initSettingDropdown("NEWDEV_dev_Owner", [], "dropdownOwner_tmp", genListWithInputSet, 'txtOwner' )
|
||||||
initSettingDropdown("NEWDEV_dev_Group", [], "dropdownGroup_tmp", genDevDetailsList, 'txtGroup' )
|
initSettingDropdown("NEWDEV_dev_Group", [], "dropdownGroup_tmp", genListWithInputSet, 'txtGroup' )
|
||||||
initSettingDropdown("NEWDEV_dev_Location", [], "dropdownLocation_tmp", genDevDetailsList, 'txtLocation' )
|
initSettingDropdown("NEWDEV_dev_Location", [], "dropdownLocation_tmp", genListWithInputSet, 'txtLocation' )
|
||||||
initSettingDropdown("NEWDEV_dev_Network_Node_MAC_ADDR", [], "dropdownNetworkNodeMac_tmp", genDevDetailsList, 'txtNetworkNodeMac' )
|
initSettingDropdown("NEWDEV_dev_Network_Node_MAC_ADDR", [], "dropdownNetworkNodeMac_tmp", genListWithInputSet, 'txtNetworkNodeMac' )
|
||||||
|
|
||||||
// Initialize static combos
|
// Initialize static combos
|
||||||
initializeComboSkipRepeated ();
|
initializeComboSkipRepeated ();
|
||||||
@@ -1155,7 +1140,7 @@ function initializeCalendar () {
|
|||||||
showSpinner()
|
showSpinner()
|
||||||
} else {
|
} else {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
updateIconPreview()
|
updateIconPreview('#txtIcon')
|
||||||
}, 100);
|
}, 100);
|
||||||
|
|
||||||
hideSpinner()
|
hideSpinner()
|
||||||
@@ -1673,7 +1658,7 @@ function addAsBase64 () {
|
|||||||
|
|
||||||
$('#txtIcon').val(iconHtmlBase64);
|
$('#txtIcon').val(iconHtmlBase64);
|
||||||
|
|
||||||
updateIconPreview()
|
updateIconPreview('#txtIcon')
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -186,13 +186,25 @@ function hideUIelements(settingKey) {
|
|||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// Processor to generate options for a dropdown menu
|
// Processor to generate options for a dropdown menu
|
||||||
function generateDropdownOptions(data, valuesArray) {
|
function generateDropdownOptions(data, valuesArray, targetField, nameTransformer) {
|
||||||
var optionsHtml = "";
|
var optionsHtml = "";
|
||||||
data.forEach(function(item) {
|
data.forEach(function(item) {
|
||||||
|
|
||||||
|
labelName = item.name
|
||||||
|
|
||||||
|
// console.log(nameTransformer);
|
||||||
|
// console.log(labelName);
|
||||||
|
|
||||||
|
// if(nameTransformer && nameTransformer != '' && labelName != '❌None')
|
||||||
|
// {
|
||||||
|
// console.log(labelName);
|
||||||
|
// labelName = nameTransformer(labelName)
|
||||||
|
// console.log(labelName);
|
||||||
|
// }
|
||||||
|
|
||||||
let selected = valuesArray.includes(item.id) ? 'selected' : '';
|
let selected = valuesArray.includes(item.id) ? 'selected' : '';
|
||||||
|
|
||||||
optionsHtml += `<option value="${item.id}" ${selected}>${item.name}</option>`;
|
optionsHtml += `<option value="${item.id}" ${selected}>${labelName}</option>`;
|
||||||
});
|
});
|
||||||
return `${optionsHtml}`;
|
return `${optionsHtml}`;
|
||||||
}
|
}
|
||||||
@@ -200,21 +212,28 @@ function generateDropdownOptions(data, valuesArray) {
|
|||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// Processor to generate a list
|
// Processor to generate a list
|
||||||
function generateList(data, valuesArray) {
|
function generateList(data, valuesArray, targetField, nameTransformer) {
|
||||||
var listHtml = "";
|
var listHtml = "";
|
||||||
data.forEach(function(item) {
|
data.forEach(function(item) {
|
||||||
|
|
||||||
|
labelName = item.name
|
||||||
|
|
||||||
|
if(nameTransformer && nameTransformer != '' && labelName != '❌None')
|
||||||
|
{
|
||||||
|
labelName = nameTransformer(labelName)
|
||||||
|
}
|
||||||
|
|
||||||
let selected = valuesArray.includes(item.id) ? 'selected' : '';
|
let selected = valuesArray.includes(item.id) ? 'selected' : '';
|
||||||
|
|
||||||
listHtml += `<li ${selected}>${item.name}</li>`;
|
listHtml += `<li ${selected}>${labelName}</li>`;
|
||||||
});
|
});
|
||||||
|
|
||||||
return listHtml;
|
return listHtml;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// Processor to generate a list in teh deviceDetails page
|
// Processor to generate a list in the deviceDetails page
|
||||||
function genDevDetailsList(data, valuesArray, targetField, nameTransformer) {
|
function genListWithInputSet(data, valuesArray, targetField, nameTransformer) {
|
||||||
|
|
||||||
var listHtml = "";
|
var listHtml = "";
|
||||||
|
|
||||||
@@ -227,7 +246,7 @@ function genDevDetailsList(data, valuesArray, targetField, nameTransformer) {
|
|||||||
|
|
||||||
labelName = item.name
|
labelName = item.name
|
||||||
|
|
||||||
if(nameTransformer && labelName != '❌None')
|
if(nameTransformer && nameTransformer != '' && labelName != '❌None')
|
||||||
{
|
{
|
||||||
labelName = nameTransformer(labelName)
|
labelName = nameTransformer(labelName)
|
||||||
}
|
}
|
||||||
@@ -242,7 +261,21 @@ function genDevDetailsList(data, valuesArray, targetField, nameTransformer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Updates the icon preview
|
||||||
|
function updateIconPreview (inputId) {
|
||||||
|
// update icon
|
||||||
|
iconInput = $(inputId)
|
||||||
|
|
||||||
|
value = iconInput.val()
|
||||||
|
|
||||||
|
iconInput.on('change input', function() {
|
||||||
|
$('#txtIconFA').html(atob(value))
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#txtIconFA').html(atob(value))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// initialize
|
// initialize
|
||||||
|
|||||||
@@ -107,19 +107,36 @@
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (inputType === 'text.select') {
|
if (inputType === 'text.select') {
|
||||||
|
|
||||||
targetLocation = columns[j].Code_Name + "_initSettingDropdown"
|
targetLocation = columns[j].Code_Name + "_initSettingDropdown"
|
||||||
|
|
||||||
initSettingDropdown(columns[j].Code_Name, [], targetLocation, generateDropdownOptions)
|
initSettingDropdown(columns[j].Code_Name, [], targetLocation, generateDropdownOptions)
|
||||||
|
|
||||||
|
// Handle Icons as tehy need a preview
|
||||||
|
if(columns[j].Code_Name == 'NEWDEV_dev_Icon')
|
||||||
|
{
|
||||||
|
input = `
|
||||||
|
<span class="input-group-addon" id="txtIconFA"></span>
|
||||||
|
<select class="form-control"
|
||||||
|
onChange="updateIconPreview('#NEWDEV_dev_Icon')"
|
||||||
|
id="${columns[j].Code_Name}"
|
||||||
|
data-my-column="${columns[j].Code_Name}"
|
||||||
|
data-my-targetColumns="${columns[j].Code_Name.replace('NEWDEV_','')}" >
|
||||||
|
<option id="${targetLocation}"></option>
|
||||||
|
</select>`
|
||||||
|
|
||||||
|
} else{
|
||||||
|
|
||||||
input = `<select class="form-control"
|
input = `<select class="form-control"
|
||||||
id="${columns[j].Code_Name}"
|
id="${columns[j].Code_Name}"
|
||||||
data-my-column="${columns[j].Code_Name}"
|
data-my-column="${columns[j].Code_Name}"
|
||||||
data-my-targetColumns="${columns[j].Code_Name.replace('NEWDEV_','')}" >
|
data-my-targetColumns="${columns[j].Code_Name.replace('NEWDEV_','')}" >
|
||||||
<option id="${targetLocation}"></option>
|
<option id="${targetLocation}"></option>
|
||||||
</select>`
|
</select>`
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// Add classes specifically for checkboxes
|
// Add classes specifically for checkboxes
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
<!-- © 2022 jokob-sk -->
|
<!-- © 2022 jokob-sk -->
|
||||||
<span style="display:inline-block; transform: rotate(180deg)">©</span>
|
<span style="display:inline-block; transform: rotate(180deg)">©</span>
|
||||||
2020 Puche (2022+ <a href="mailto:jokob@duck.com?subject=NetAlertX">jokob-sk</a>) | <b><?= lang('Maintenance_built_on');?>: </b>
|
Author: <a href="mailto:jokob@duck.com?subject=NetAlertX">jokob-sk</a> (Based on <a href="https://github.com/pucherot/Pi.Alert">2020 PiAlert</a>) | <b><?= lang('Maintenance_built_on');?>: </b>
|
||||||
<?php include 'php/templates/build.php'; ?> | <b> Version: </b> <?php include 'php/templates/version.php'; ?> |
|
<?php include 'php/templates/build.php'; ?> | <b> Version: </b> <?php include 'php/templates/version.php'; ?> |
|
||||||
<a href="https://github.com/jokob-sk/NetAlertX/tree/main/docs" target="_blank"><span>Docs <i class="fa fa-circle-question"></i></a>
|
<a href="https://github.com/jokob-sk/NetAlertX/tree/main/docs" target="_blank"><span>Docs <i class="fa fa-circle-question"></i></a>
|
||||||
<span>
|
<span>
|
||||||
|
|||||||
@@ -613,7 +613,9 @@
|
|||||||
"TIMEZONE_name": "Time zone",
|
"TIMEZONE_name": "Time zone",
|
||||||
"UI_DEV_SECTIONS_description": "Select which UI elements to hide in the Devices pages.",
|
"UI_DEV_SECTIONS_description": "Select which UI elements to hide in the Devices pages.",
|
||||||
"UI_DEV_SECTIONS_name": "Hide Devices Sections",
|
"UI_DEV_SECTIONS_name": "Hide Devices Sections",
|
||||||
"UI_LANG_description": "Select the preferred UI language. Help translating or suggest languages in the online portal of <a href=\"https://hosted.weblate.org/projects/pialert/core/\" target=\"_blank\">Weblate</a>.",
|
"UI_ICONS_description": "Select which UI elements to hide in the Devices pages.",
|
||||||
|
"UI_ICONS_name": "Pre-defined icons",
|
||||||
|
"UI_LANG_description": "A list of pre-defined icons. Proceed with caution, the preferred way to add icons is described in the <a href=\"https://github.com/jokob-sk/NetAlertX/blob/main/docs/ICONS.md\" target=\"_blank\">Icons documentation</a>. You can add a base64-encoded SVG HTML or Font-awesome HTML tag.",
|
||||||
"UI_LANG_name": "UI Language",
|
"UI_LANG_name": "UI Language",
|
||||||
"UI_MY_DEVICES_description": "Devices of which statuses should be shown in the default <b>My Devices</b> view. (<code>CTRL + Click</code> to select/deselect)",
|
"UI_MY_DEVICES_description": "Devices of which statuses should be shown in the default <b>My Devices</b> view. (<code>CTRL + Click</code> to select/deselect)",
|
||||||
"UI_MY_DEVICES_name": "Show in My Devices view",
|
"UI_MY_DEVICES_name": "Show in My Devices view",
|
||||||
|
|||||||
@@ -589,7 +589,7 @@
|
|||||||
{
|
{
|
||||||
"name" : "value",
|
"name" : "value",
|
||||||
"type" : "sql",
|
"type" : "sql",
|
||||||
"value" : "SELECT DISTINCT '❌None' AS name, '' AS id UNION SELECT Dev_Icon AS name, Dev_Icon AS id FROM Devices WHERE Dev_Icon <> '';"
|
"value" : "WITH RECURSIVE SettingsIcons AS (SELECT REPLACE(REPLACE(REPLACE(Value, '[', ''), ']', ''), '''', '') AS icon_list FROM Settings WHERE Code_Name = 'UI_ICONS'), SplitIcons AS (SELECT TRIM(SUBSTR(icon_list, 1, INSTR(icon_list || ',', ',') - 1)) AS icon, SUBSTR(icon_list, INSTR(icon_list || ',', ',') + 1) AS remaining_icons FROM SettingsIcons WHERE icon_list <> '' UNION ALL SELECT TRIM(SUBSTR(remaining_icons, 1, INSTR(remaining_icons || ',', ',') - 1)) AS icon, SUBSTR(remaining_icons, INSTR(remaining_icons || ',', ',') + 1) AS remaining_icons FROM SplitIcons WHERE remaining_icons <> '') SELECT DISTINCT * FROM (SELECT icon as name, icon as id FROM SplitIcons UNION SELECT '❌None' AS name, '' AS id UNION SELECT Dev_Icon AS name, Dev_Icon AS id FROM Devices WHERE Dev_Icon <> '') AS combined_results;"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"localized": ["name", "description"],
|
"localized": ["name", "description"],
|
||||||
|
|||||||
@@ -7,11 +7,9 @@ import base64
|
|||||||
from const import fullDbPath, sql_devices_stats, sql_devices_all
|
from const import fullDbPath, sql_devices_stats, sql_devices_all
|
||||||
|
|
||||||
from logger import mylog
|
from logger import mylog
|
||||||
from helper import json_obj, initOrSetParam, row_to_json, timeNowTZ, split_string #, updateState
|
from helper import json_obj, initOrSetParam, row_to_json, timeNowTZ#, split_string #, updateState
|
||||||
from appevent import AppEvent_obj
|
from appevent import AppEvent_obj
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class DB():
|
class DB():
|
||||||
"""
|
"""
|
||||||
DB Class to provide the basic database interactions.
|
DB Class to provide the basic database interactions.
|
||||||
@@ -83,12 +81,6 @@ class DB():
|
|||||||
Check the current tables in the DB and upgrade them if neccessary
|
Check the current tables in the DB and upgrade them if neccessary
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Registering UDF (User Defined Functions)
|
|
||||||
#
|
|
||||||
resultUDF = self.sql_connection.create_function("split_string", 2, split_string) # Register the UDF
|
|
||||||
mylog('none',f'[upgradeDB] resultUDF: {resultUDF}')
|
|
||||||
|
|
||||||
|
|
||||||
# indicates, if Online_History table is available
|
# indicates, if Online_History table is available
|
||||||
onlineHistoryAvailable = self.sql.execute("""
|
onlineHistoryAvailable = self.sql.execute("""
|
||||||
SELECT name FROM sqlite_master WHERE type='table'
|
SELECT name FROM sqlite_master WHERE type='table'
|
||||||
|
|||||||
@@ -597,12 +597,6 @@ def cleanDeviceName(str, match_IP):
|
|||||||
# String manipulation methods
|
# String manipulation methods
|
||||||
#-------------------------------------------------------------------------------
|
#-------------------------------------------------------------------------------
|
||||||
|
|
||||||
#-------------------------------------------------------------------------------
|
|
||||||
# Define the split_string function
|
|
||||||
def split_string(input_str, delimiter):
|
|
||||||
# remove any wrapping brackets
|
|
||||||
input_str = input_str.replace('[','').replace(']','')
|
|
||||||
return input_str.split(delimiter)
|
|
||||||
|
|
||||||
#-------------------------------------------------------------------------------
|
#-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ def importConfigs (db):
|
|||||||
conf.UI_DEV_SECTIONS = ccd('UI_DEV_SECTIONS', [] , c_d, 'Show sections', 'text.multiselect', "['Tile Cards', 'Device Presence']", 'General')
|
conf.UI_DEV_SECTIONS = ccd('UI_DEV_SECTIONS', [] , c_d, 'Show sections', 'text.multiselect', "['Tile Cards', 'Device Presence']", 'General')
|
||||||
conf.UI_MY_DEVICES = ccd('UI_MY_DEVICES', ['online', 'offline', 'archived', 'new', 'down'] , c_d, 'Include in My Devices', 'text.multiselect', "['online', 'offline', 'archived', 'new', 'down']", 'General')
|
conf.UI_MY_DEVICES = ccd('UI_MY_DEVICES', ['online', 'offline', 'archived', 'new', 'down'] , c_d, 'Include in My Devices', 'text.multiselect', "['online', 'offline', 'archived', 'new', 'down']", 'General')
|
||||||
conf.UI_NOT_RANDOM_MAC = ccd('UI_NOT_RANDOM_MAC', [] , c_d, 'Exlude from Random Prefix', 'list', "", 'General')
|
conf.UI_NOT_RANDOM_MAC = ccd('UI_NOT_RANDOM_MAC', [] , c_d, 'Exlude from Random Prefix', 'list', "", 'General')
|
||||||
conf.UI_ICONS = ccd('UI_ICONS', ['PGkgY2xhc3M9ImZhIGZhLWNvbXB1dGVyIj48L2k', 'PGkgY2xhc3M9ImZhIGZhLWV0aGVybmV0Ij48L2k', 'PGkgY2xhc3M9ImZhIGZhLWdhbWVwYWQiPjwvaT4', 'PGkgY2xhc3M9ImZhIGZhLWdsb2JlIj48L2k', 'PGkgY2xhc3M9ImZhIGZhLWxhcHRvcCI', 'PGkgY2xhc3M9ImZhIGZhLWxpZ2h0YnVsYiI', 'PGkgY2xhc3M9ImZhIGZhLXNoaWVsZCI', 'PGkgY2xhc3M9ImZhIGZhLXdpZmkiPjwvaT4'] , c_d, 'Icons', 'list', "", 'General')
|
conf.UI_ICONS = ccd('UI_ICONS', ['PGkgY2xhc3M9ImZhIGZhLWNvbXB1dGVyIj48L2k+', 'PGkgY2xhc3M9ImZhIGZhLWV0aGVybmV0Ij48L2k+', 'PGkgY2xhc3M9ImZhIGZhLWdhbWVwYWQiPjwvaT4', 'PGkgY2xhc3M9ImZhIGZhLWdsb2JlIj48L2k+', 'PGkgY2xhc3M9ImZhIGZhLWxhcHRvcCI+PC9pPg==', 'PGkgY2xhc3M9ImZhIGZhLWxpZ2h0YnVsYiI+PC9pPg==', 'PGkgY2xhc3M9ImZhIGZhLXNoaWVsZCI+PC9pPg==', 'PGkgY2xhc3M9ImZhIGZhLXdpZmkiPjwvaT4'] , c_d, 'Icons', 'list', "", 'General')
|
||||||
conf.UI_REFRESH = ccd('UI_REFRESH', 0 , c_d, 'Refresh interval', 'integer', "", 'General')
|
conf.UI_REFRESH = ccd('UI_REFRESH', 0 , c_d, 'Refresh interval', 'integer', "", 'General')
|
||||||
conf.DAYS_TO_KEEP_EVENTS = ccd('DAYS_TO_KEEP_EVENTS', 90 , c_d, 'Delete events days', 'integer', '', 'General')
|
conf.DAYS_TO_KEEP_EVENTS = ccd('DAYS_TO_KEEP_EVENTS', 90 , c_d, 'Delete events days', 'integer', '', 'General')
|
||||||
conf.HRS_TO_KEEP_NEWDEV = ccd('HRS_TO_KEEP_NEWDEV', 0 , c_d, 'Keep new devices for', 'integer', "0", 'General')
|
conf.HRS_TO_KEEP_NEWDEV = ccd('HRS_TO_KEEP_NEWDEV', 0 , c_d, 'Keep new devices for', 'integer', "0", 'General')
|
||||||
|
|||||||
Reference in New Issue
Block a user