🎨Guess icons #738

This commit is contained in:
jokob-sk
2024-07-21 11:42:59 +10:00
parent 3e35f08d6c
commit 54b6b1d408
14 changed files with 170 additions and 76 deletions

View File

@@ -16,7 +16,7 @@ sys.path.extend([f"{INSTALL_PATH}/front/plugins", f"{INSTALL_PATH}/server"])
from plugin_helper import Plugin_Object, Plugin_Objects, decodeBase64 from plugin_helper import Plugin_Object, Plugin_Objects, decodeBase64
from logger import mylog, append_line_to_file from logger import mylog, append_line_to_file
from helper import timeNowTZ from helper import timeNowTZ, get_setting_value
from const import logPath, applicationPath, fullDbPath from const import logPath, applicationPath, fullDbPath
import conf import conf
from pytz import timezone from pytz import timezone

View File

@@ -19,7 +19,7 @@ sys.path.extend([f"{INSTALL_PATH}/front/plugins", f"{INSTALL_PATH}/server"])
from plugin_helper import Plugin_Object, Plugin_Objects, decodeBase64 from plugin_helper import Plugin_Object, Plugin_Objects, decodeBase64
from logger import mylog, append_line_to_file from logger import mylog, append_line_to_file
from helper import timeNowTZ, check_IP_format from helper import timeNowTZ, get_setting_value, check_IP_format
from const import logPath, applicationPath, fullDbPath from const import logPath, applicationPath, fullDbPath
import conf import conf
from pytz import timezone from pytz import timezone

View File

@@ -15,6 +15,7 @@ sys.path.extend([f"{INSTALL_PATH}/front/plugins", f"{INSTALL_PATH}/server"])
from plugin_helper import Plugin_Object, Plugin_Objects, handleEmpty, is_mac from plugin_helper import Plugin_Object, Plugin_Objects, handleEmpty, is_mac
from logger import mylog from logger import mylog
from dhcp_leases import DhcpLeases from dhcp_leases import DhcpLeases
from helper import timeNowTZ, get_setting_value
import conf import conf
from pytz import timezone from pytz import timezone

View File

@@ -12,6 +12,7 @@ sys.path.extend([f"{INSTALL_PATH}/front/plugins", f"{INSTALL_PATH}/server"])
from plugin_helper import Plugin_Objects, Plugin_Object from plugin_helper import Plugin_Objects, Plugin_Object
from logger import mylog from logger import mylog
from helper import timeNowTZ, get_setting_value
import conf import conf
from pytz import timezone from pytz import timezone

View File

@@ -13,7 +13,7 @@ sys.path.extend([f"{INSTALL_PATH}/front/plugins", f"{INSTALL_PATH}/server"])
from plugin_helper import Plugin_Objects from plugin_helper import Plugin_Objects
from logger import mylog, append_line_to_file from logger import mylog, append_line_to_file
from helper import timeNowTZ from helper import timeNowTZ, get_setting_value
import conf import conf
from pytz import timezone from pytz import timezone

View File

@@ -15,7 +15,7 @@ sys.path.extend([f"{INSTALL_PATH}/front/plugins", f"{INSTALL_PATH}/server"])
from plugin_helper import Plugin_Object, Plugin_Objects, decodeBase64 from plugin_helper import Plugin_Object, Plugin_Objects, decodeBase64
from logger import mylog, append_line_to_file from logger import mylog, append_line_to_file
from helper import timeNowTZ from helper import timeNowTZ, get_setting_value
from const import logPath, applicationPath from const import logPath, applicationPath
import conf import conf
from pytz import timezone from pytz import timezone

View File

@@ -16,7 +16,7 @@ sys.path.extend([f"{INSTALL_PATH}/front/plugins", f"{INSTALL_PATH}/server"])
from logger import mylog from logger import mylog
from plugin_helper import Plugin_Object, Plugin_Objects from plugin_helper import Plugin_Object, Plugin_Objects
from helper import timeNowTZ from helper import timeNowTZ, get_setting_value
from const import logPath, applicationPath from const import logPath, applicationPath
import conf import conf
from pytz import timezone from pytz import timezone

View File

@@ -13,7 +13,7 @@ sys.path.extend([f"{INSTALL_PATH}/front/plugins", f"{INSTALL_PATH}/server"])
from plugin_helper import Plugin_Object, Plugin_Objects, decodeBase64, handleEmpty, normalize_mac from plugin_helper import Plugin_Object, Plugin_Objects, decodeBase64, handleEmpty, normalize_mac
from logger import mylog from logger import mylog
from helper import timeNowTZ from helper import timeNowTZ, get_setting_value
from const import logPath, applicationPath from const import logPath, applicationPath
import conf import conf
from pytz import timezone from pytz import timezone

View File

@@ -13,7 +13,7 @@ sys.path.extend([f"{INSTALL_PATH}/front/plugins", f"{INSTALL_PATH}/server"])
from plugin_helper import Plugin_Object, Plugin_Objects, decodeBase64 from plugin_helper import Plugin_Object, Plugin_Objects, decodeBase64
from logger import mylog, append_line_to_file from logger import mylog, append_line_to_file
from helper import timeNowTZ from helper import timeNowTZ, get_setting_value
from const import logPath, applicationPath from const import logPath, applicationPath
import conf import conf
from pytz import timezone from pytz import timezone

View File

@@ -21,6 +21,7 @@ sys.path.extend([f"{INSTALL_PATH}/front/plugins", f"{INSTALL_PATH}/server"])
from plugin_helper import Plugin_Object, Plugin_Objects from plugin_helper import Plugin_Object, Plugin_Objects
from logger import mylog from logger import mylog
from helper import timeNowTZ, get_setting_value
import conf import conf
from pytz import timezone from pytz import timezone

View File

@@ -17,7 +17,7 @@ sys.path.extend([f"{INSTALL_PATH}/front/plugins", f"{INSTALL_PATH}/server"])
from plugin_helper import Plugin_Object, Plugin_Objects, decodeBase64, handleEmpty from plugin_helper import Plugin_Object, Plugin_Objects, decodeBase64, handleEmpty
from logger import mylog, append_line_to_file from logger import mylog, append_line_to_file
from helper import timeNowTZ from helper import timeNowTZ, get_setting_value
from const import logPath, applicationPath, fullDbPath from const import logPath, applicationPath, fullDbPath
from device import query_MAC_vendor from device import query_MAC_vendor
import conf import conf

View File

@@ -15,6 +15,7 @@ sys.path.extend([f"{INSTALL_PATH}/front/plugins", f"{INSTALL_PATH}/server"])
from plugin_helper import Plugin_Objects from plugin_helper import Plugin_Objects
from datetime import datetime from datetime import datetime
from const import logPath from const import logPath
from helper import timeNowTZ, get_setting_value
import conf import conf
from pytz import timezone from pytz import timezone

View File

@@ -183,8 +183,7 @@ def create_new_devices (db):
dev_Group, dev_Group,
dev_Comments, dev_Comments,
dev_LogEvents, dev_LogEvents,
dev_Location, dev_Location"""
dev_Icon"""
newDevDefaults = f"""{get_setting_value('NEWDEV_dev_AlertEvents')}, newDevDefaults = f"""{get_setting_value('NEWDEV_dev_AlertEvents')},
{get_setting_value('NEWDEV_dev_AlertDeviceDown')}, {get_setting_value('NEWDEV_dev_AlertDeviceDown')},
@@ -198,12 +197,21 @@ def create_new_devices (db):
'{get_setting_value('NEWDEV_dev_Group')}', '{get_setting_value('NEWDEV_dev_Group')}',
'{get_setting_value('NEWDEV_dev_Comments')}', '{get_setting_value('NEWDEV_dev_Comments')}',
{get_setting_value('NEWDEV_dev_LogEvents')}, {get_setting_value('NEWDEV_dev_LogEvents')},
'{get_setting_value('NEWDEV_dev_Location')}', '{get_setting_value('NEWDEV_dev_Location')}'"""
'{get_setting_value('NEWDEV_dev_Icon')}'
"""
# Bulk-inserting devices from the CurrentScan table as new devices in the table Devices ... # Fetch data from CurrentScan
# ... with new device defaults and ignoring specidfied IPs and MACs) current_scan_data = sql.execute("SELECT cur_MAC, cur_Name, cur_Vendor, cur_IP, cur_SyncHubNodeName, cur_NetworkNodeMAC, cur_PORT, cur_NetworkSite, cur_SSID, cur_Type FROM CurrentScan").fetchall()
for row in current_scan_data:
cur_MAC, cur_Name, cur_Vendor, cur_IP, cur_SyncHubNodeName, cur_NetworkNodeMAC, cur_PORT, cur_NetworkSite, cur_SSID, cur_Type = row
# Handle NoneType
cur_Name = cur_Name.strip() if cur_Name else '(unknown)'
cur_Type = cur_Type.strip() if cur_Type else get_setting_value("NEWDEV_dev_DeviceType")
cur_NetworkNodeMAC = cur_NetworkNodeMAC.strip() if cur_NetworkNodeMAC else ''
cur_NetworkNodeMAC = cur_NetworkNodeMAC if cur_NetworkNodeMAC and cur_MAC != "Internet" else (get_setting_value("NEWDEV_dev_Network_Node_MAC_ADDR") if cur_MAC != "Internet" else "null")
# Preparing the individual insert statement
sqlQuery = f"""INSERT OR IGNORE INTO Devices sqlQuery = f"""INSERT OR IGNORE INTO Devices
( (
dev_MAC, dev_MAC,
@@ -221,45 +229,29 @@ def create_new_devices (db):
dev_DeviceType, dev_DeviceType,
{newDevColumns} {newDevColumns}
) )
SELECT VALUES
cur_MAC, (
CASE '{cur_MAC}',
WHEN LENGTH(TRIM(cur_Name)) > 0 THEN cur_Name ELSE '(unknown)' '{cur_Name}',
END, '{cur_Vendor}',
cur_Vendor, '{cur_IP}',
cur_IP,
?, ?,
?, ?,
cur_SyncHubNodeName, '{cur_SyncHubNodeName}',
{sql_generateGuid}, {sql_generateGuid},
CASE '{cur_NetworkNodeMAC}',
WHEN LENGTH(TRIM(cur_NetworkNodeMAC)) > 0 '{cur_PORT}',
AND cur_MAC != 'Internet' '{cur_NetworkSite}',
THEN cur_NetworkNodeMAC '{cur_SSID}',
ELSE '{cur_Type}',
CASE
WHEN cur_MAC = 'Internet'
THEN 'null'
ELSE '{get_setting_value('NEWDEV_dev_Network_Node_MAC_ADDR')}'
END
END,
cur_PORT,
cur_NetworkSite,
cur_SSID,
CASE
WHEN LENGTH(TRIM(cur_Type)) > 0 THEN cur_Type ELSE '{get_setting_value('NEWDEV_dev_DeviceType')}'
END,
{newDevDefaults} {newDevDefaults}
FROM CurrentScan )"""
WHERE 1=1
{list_to_where('OR', 'cur_MAC', 'NOT LIKE', get_setting_value('NEWDEV_ignored_MACs'))}
{list_to_where('OR', 'cur_IP', 'NOT LIKE', get_setting_value('NEWDEV_ignored_IPs'))}
"""
mylog('debug',f'[New Devices] Create devices SQL: {sqlQuery}') mylog('trace', f'[New Devices] Create device SQL: {sqlQuery}')
sql.execute(sqlQuery, (startTime, startTime)) sql.execute(sqlQuery, (startTime, startTime))
mylog('debug','[New Devices] New Devices end') mylog('debug','[New Devices] New Devices end')
db.commitDB() db.commitDB()
@@ -410,6 +402,7 @@ def update_devices_data_from_scan (db):
AND cur_Name <> '' AND cur_Name <> ''
) """) ) """)
# Update VENDORS
recordsToUpdate = [] recordsToUpdate = []
query = """SELECT * FROM Devices query = """SELECT * FROM Devices
WHERE dev_Vendor = '(unknown)' OR dev_Vendor ='' WHERE dev_Vendor = '(unknown)' OR dev_Vendor =''
@@ -420,8 +413,24 @@ def update_devices_data_from_scan (db):
if vendor != -1 and vendor != -2 : if vendor != -1 and vendor != -2 :
recordsToUpdate.append ([vendor, device['dev_MAC']]) recordsToUpdate.append ([vendor, device['dev_MAC']])
sql.executemany ("UPDATE Devices SET dev_Vendor = ? WHERE dev_MAC = ? ", if len(recordsToUpdate) > 0:
recordsToUpdate ) sql.executemany ("UPDATE Devices SET dev_Vendor = ? WHERE dev_MAC = ? ", recordsToUpdate )
# Guess ICONS
recordsToUpdate = []
query = """SELECT * FROM Devices
WHERE dev_Icon in ('', 'null')
OR dev_Icon IS NULL"""
default_icon = get_setting_value('NEWDEV_dev_Icon')
for device in sql.execute (query) :
# Conditional logic for dev_Icon guessing
dev_Icon = guess_icon(device['dev_Vendor'], device['dev_MAC'], device['dev_LastIP'], device['dev_Name'], default_icon)
recordsToUpdate.append ([dev_Icon, device['dev_MAC']])
if len(recordsToUpdate) > 0:
sql.executemany ("UPDATE Devices SET dev_Icon = ? WHERE dev_MAC = ? ", recordsToUpdate )
mylog('debug','[Update Devices] Update devices end') mylog('debug','[Update Devices] Update devices end')
@@ -582,3 +591,84 @@ def query_MAC_vendor (pMAC):
mylog('none', [f"[Vendor Check] ⚠ ERROR: Vendors file {vendorsPath} not found."]) mylog('none', [f"[Vendor Check] ⚠ ERROR: Vendors file {vendorsPath} not found."])
return -1 return -1
#===============================================================================
# Icons
#===============================================================================
#-------------------------------------------------------------------------------
# Base64 encoded HTML string for FontAwesome icons
icons = {
"globe": "PGkgY2xhc3M9ImZhcyBmYS1nbG9iZSI+PC9pPg==", # globe icon
"phone": "PGkgY2xhc3M9ImZhcyBmYS1tb2JpbGUtYWx0Ij48L2k+",
"laptop": "PGkgY2xhc3M9ImZhIGZhLWxhcHRvcCI+PC9pPg==",
"printer": "PGkgY2xhc3M9ImZhIGZhLXByaW50ZXIiPjwvaT4=",
"router": "PGkgY2xhc3M9ImZhcyBmYS1yYW5kb20iPjwvaT4=",
"tv": "PGkgY2xhc3M9ImZhIGZhLXR2Ij48L2k+",
"desktop": "PGkgY2xhc3M9ImZhIGZhLWRlc2t0b3AiPjwvaT4=",
"tablet": "PGkgY2xhc3M9ImZhIGZhLXRhYmxldCI+PC9pPg==",
"watch": "PGkgY2xhc3M9ImZhIGZhLXdhbmNoIj48L2k+",
"camera": "PGkgY2xhc3M9ImZhIGZhLWNhbWVyYSI+PC9pPg==",
"home": "PGkgY2xhc3M9ImZhIGZhLWhvbWUiPjwvaT4=",
"apple": "PGkgY2xhc3M9ImZhYiBmYS1hcHBsZSI+PC9pPg==",
"ethernet": "PGkgY2xhc3M9ImZhcyBmYS1ldGhlcm5ldCI+PC9pPg==",
"google": "PGkgY2xhc3M9ImZhYiBmYS1nb29nbGUiPjwvaT4=",
"raspberry": "PGkgY2xhc3M9ImZhYiBmYS1yYXNwYmVycnktcGkiPjwvaT4=",
"microchip": "PGkgY2xhc3M9ImZhcyBmYS1taWNyb2NoaXAiPjwvaT4="
}
#-------------------------------------------------------------------------------
# Guess device icon
def guess_icon(vendor, mac, ip, name, default):
result = default
mac = mac.upper()
vendor = vendor.lower()
name = name.lower()
# Guess icon based on vendor
if any(brand in vendor for brand in {"samsung", "motorola"}):
result = icons.get("phone")
elif "dell" in vendor:
result = icons.get("laptop")
elif "hp" in vendor:
result = icons.get("printer")
elif "cisco" in vendor:
result = icons.get("router")
elif "lg" in vendor:
result = icons.get("tv")
elif "raspberry" in vendor:
result = icons.get("raspberry")
elif "apple" in vendor:
result = icons.get("apple")
elif "google" in vendor:
result = icons.get("google")
elif "ubiquiti" in vendor:
result = icons.get("router")
elif any(brand in vendor for brand in {"espressif"}):
result = icons.get("microchip")
# Guess icon based on MAC address patterns
elif mac == "INTERNET": # Apple
result = icons.get("globe")
elif mac.startswith("00:1A:79"): # Apple
result = icons.get("apple")
elif mac.startswith("B0:BE:83"): # Apple
result = icons.get("apple")
elif mac.startswith("00:1B:63"): # Sony
result = icons.get("tablet")
elif mac.startswith("74:AC:B9"): # Unifi
result = icons.get("ethernet")
# Guess icon based on name
elif 'google' in name:
result = icons.get("google")
elif 'desktop' in name:
result = icons.get("desktop")
# Guess icon based on IP address ranges
elif ip.startswith("192.168.1."):
result = icons.get("laptop")
return result

View File

@@ -145,7 +145,7 @@ def importConfigs (db, all_plugins):
# UI # UI
conf.UI_LANG = ccd('UI_LANG', 'English' , c_d, 'Language Interface', '{"dataType":"string", "elements": [{"elementType" : "select", "elementOptions" : [] ,"transformers": []}]}', "['English', 'French', 'German', 'Norwegian', 'Russian', 'Spanish', 'Italian (it_it)', 'Portuguese (pt_br)', 'Polish (pl_pl)', 'Turkish (tr_tr)', 'Chinese (zh_cn)' ]", 'UI') conf.UI_LANG = ccd('UI_LANG', 'English' , c_d, 'Language Interface', '{"dataType":"string", "elements": [{"elementType" : "select", "elementOptions" : [] ,"transformers": []}]}', "['English', 'French', 'German', 'Norwegian', 'Russian', 'Spanish', 'Italian (it_it)', 'Portuguese (pt_br)', 'Polish (pl_pl)', 'Turkish (tr_tr)', 'Chinese (zh_cn)' ]", 'UI')
conf.UI_NOT_RANDOM_MAC = ccd('UI_NOT_RANDOM_MAC', [] , c_d, 'Exlude from Random Prefix', '{"dataType": "array","elements": [ {"elementType": "input","elementOptions": [{ "placeholder": "Enter value" },{ "suffix": "_in" },{ "cssClasses": "col-sm-10" },{ "prefillValue": "null" }],"transformers": [] }, {"elementType": "button","elementOptions": [{ "sourceSuffixes": ["_in"] },{ "separator": "" },{ "cssClasses": "col-xs-12" },{ "onClick": "addList(this, false)" },{ "getStringKey": "Gen_Add" }],"transformers": [] }, {"elementType": "button","elementOptions": [{ "sourceSuffixes": [] },{ "separator": "" },{ "cssClasses": "col-xs-6" },{ "onClick": "removeAllOptions(this)" },{ "getStringKey": "Gen_Remove_All" }],"transformers": []},{"elementType": "button","elementOptions": [{ "sourceSuffixes": [] },{ "separator": "" },{ "cssClasses": "col-xs-6" },{ "onClick": "removeFromList(this)" },{ "getStringKey": "Gen_Remove_Last" }],"transformers": []}, {"elementType": "select","elementOptions": [{ "multiple": "true" },{ "readonly": "true" },{ "editable": "true" }],"transformers": [] }]}', "[]", 'UI') conf.UI_NOT_RANDOM_MAC = ccd('UI_NOT_RANDOM_MAC', [] , c_d, 'Exlude from Random Prefix', '{"dataType": "array","elements": [ {"elementType": "input","elementOptions": [{ "placeholder": "Enter value" },{ "suffix": "_in" },{ "cssClasses": "col-sm-10" },{ "prefillValue": "null" }],"transformers": [] }, {"elementType": "button","elementOptions": [{ "sourceSuffixes": ["_in"] },{ "separator": "" },{ "cssClasses": "col-xs-12" },{ "onClick": "addList(this, false)" },{ "getStringKey": "Gen_Add" }],"transformers": [] }, {"elementType": "button","elementOptions": [{ "sourceSuffixes": [] },{ "separator": "" },{ "cssClasses": "col-xs-6" },{ "onClick": "removeAllOptions(this)" },{ "getStringKey": "Gen_Remove_All" }],"transformers": []},{"elementType": "button","elementOptions": [{ "sourceSuffixes": [] },{ "separator": "" },{ "cssClasses": "col-xs-6" },{ "onClick": "removeFromList(this)" },{ "getStringKey": "Gen_Remove_Last" }],"transformers": []}, {"elementType": "select","elementOptions": [{ "multiple": "true" },{ "readonly": "true" },{ "editable": "true" }],"transformers": [] }]}', "[]", 'UI')
conf.UI_ICONS = ccd('UI_ICONS', ['PGkgY2xhc3M9ImZhIGZhLWNvbXB1dGVyIj48L2k+', 'PGkgY2xhc3M9ImZhIGZhLWV0aGVybmV0Ij48L2k+', 'PGkgY2xhc3M9ImZhIGZhLWdhbWVwYWQiPjwvaT4', 'PGkgY2xhc3M9ImZhIGZhLWdsb2JlIj48L2k+', 'PGkgY2xhc3M9ImZhIGZhLWxhcHRvcCI+PC9pPg==', 'PGkgY2xhc3M9ImZhIGZhLWxpZ2h0YnVsYiI+PC9pPg==', 'PGkgY2xhc3M9ImZhIGZhLXNoaWVsZCI+PC9pPg==', 'PGkgY2xhc3M9ImZhIGZhLXdpZmkiPjwvaT4'] , c_d, 'Icons', '{"dataType": "array","elements": [ {"elementType": "input","elementOptions": [{ "placeholder": "Enter value" },{ "suffix": "_in" },{ "cssClasses": "col-sm-10" },{ "prefillValue": "null" }],"transformers": [] }, {"elementType": "button","elementOptions": [{ "sourceSuffixes": ["_in"] },{ "separator": "" },{ "cssClasses": "col-xs-12" },{ "onClick": "addList(this, false)" },{ "getStringKey": "Gen_Add" }],"transformers": [] }, {"elementType": "button","elementOptions": [{ "sourceSuffixes": [] },{ "separator": "" },{ "cssClasses": "col-xs-6" },{ "onClick": "removeAllOptions(this)" },{ "getStringKey": "Gen_Remove_All" }],"transformers": []},{"elementType": "button","elementOptions": [{ "sourceSuffixes": [] },{ "separator": "" },{ "cssClasses": "col-xs-6" },{ "onClick": "removeFromList(this)" },{ "getStringKey": "Gen_Remove_Last" }],"transformers": []}, {"elementType": "select","elementOptions": [{ "multiple": "true" },{ "readonly": "true" },{ "editable": "true" }],"transformers": [] }]}', "[]", 'UI') conf.UI_ICONS = ccd('UI_ICONS', ['PGkgY2xhc3M9J2ZhIGZhLXdpZmknPjwvaT4=', 'PGkgY2xhc3M9ImZhIGZhLWNvbXB1dGVyIj48L2k+', 'PGkgY2xhc3M9ImZhIGZhLWV0aGVybmV0Ij48L2k+', 'PGkgY2xhc3M9ImZhIGZhLWdhbWVwYWQiPjwvaT4', 'PGkgY2xhc3M9ImZhIGZhLWdsb2JlIj48L2k+', 'PGkgY2xhc3M9ImZhIGZhLWxhcHRvcCI+PC9pPg==', 'PGkgY2xhc3M9ImZhIGZhLWxpZ2h0YnVsYiI+PC9pPg==', 'PGkgY2xhc3M9ImZhIGZhLXNoaWVsZCI+PC9pPg==', 'PGkgY2xhc3M9ImZhIGZhLXdpZmkiPjwvaT4', 'PGkgY2xhc3M9J2ZhIGZhLWdhbWVwYWQnPjwvaT4'] , c_d, 'Icons', '{"dataType": "array","elements": [ {"elementType": "input","elementOptions": [{ "placeholder": "Enter value" },{ "suffix": "_in" },{ "cssClasses": "col-sm-10" },{ "prefillValue": "null" }],"transformers": [] }, {"elementType": "button","elementOptions": [{ "sourceSuffixes": ["_in"] },{ "separator": "" },{ "cssClasses": "col-xs-12" },{ "onClick": "addList(this, false)" },{ "getStringKey": "Gen_Add" }],"transformers": [] }, {"elementType": "button","elementOptions": [{ "sourceSuffixes": [] },{ "separator": "" },{ "cssClasses": "col-xs-6" },{ "onClick": "removeAllOptions(this)" },{ "getStringKey": "Gen_Remove_All" }],"transformers": []},{"elementType": "button","elementOptions": [{ "sourceSuffixes": [] },{ "separator": "" },{ "cssClasses": "col-xs-6" },{ "onClick": "removeFromList(this)" },{ "getStringKey": "Gen_Remove_Last" }],"transformers": []}, {"elementType": "select","elementOptions": [{ "multiple": "true" },{ "readonly": "true" },{ "editable": "true" }],"transformers": [] }]}', "[]", 'UI')
conf.UI_REFRESH = ccd('UI_REFRESH', 0 , c_d, 'Refresh interval', '{"dataType":"integer", "elements": [{"elementType" : "input", "elementOptions" : [{"type": "number"}] ,"transformers": []}]}', "[]", 'UI') conf.UI_REFRESH = ccd('UI_REFRESH', 0 , c_d, 'Refresh interval', '{"dataType":"integer", "elements": [{"elementType" : "input", "elementOptions" : [{"type": "number"}] ,"transformers": []}]}', "[]", 'UI')
conf.UI_DEV_SECTIONS = ccd('UI_DEV_SECTIONS', [] , c_d, 'Show sections', '{"dataType":"array", "elements": [{"elementType" : "select", "elementOptions" : [{"multiple":"true"}] ,"transformers": []}]}', "['Tile Cards', 'Device Presence']", 'UI') conf.UI_DEV_SECTIONS = ccd('UI_DEV_SECTIONS', [] , c_d, 'Show sections', '{"dataType":"array", "elements": [{"elementType" : "select", "elementOptions" : [{"multiple":"true"}] ,"transformers": []}]}', "['Tile Cards', 'Device Presence']", 'UI')
conf.UI_PRESENCE = ccd('UI_PRESENCE', ['online', 'offline', 'archived'] , c_d, 'Include in presence', '{"dataType":"array", "elements": [{"elementType" : "select", "elementOptions" : [{"multiple":"true"}] ,"transformers": []}]}', "['online', 'offline', 'archived']", 'UI') conf.UI_PRESENCE = ccd('UI_PRESENCE', ['online', 'offline', 'archived'] , c_d, 'Include in presence', '{"dataType":"array", "elements": [{"elementType" : "select", "elementOptions" : [{"multiple":"true"}] ,"transformers": []}]}', "['online', 'offline', 'archived']", 'UI')