connectcore-demo-example: initial dashboard and management pages

Generated from repo https://github.com/digidotcom/digi-iot-web-apps at commit
95cb32f39f2fafd7bde7fb02c47bc966d8f75916 and directory 'connectcore'.

https://onedigi.atlassian.net/browse/DEL-7742

Signed-off-by: Tatiana Leon <Tatiana.Leon@digi.com>
This commit is contained in:
Tatiana Leon 2022-05-02 18:29:51 +02:00
parent 7681c2f100
commit 3a2d37f8e1
52 changed files with 10747 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,534 @@
<!DOCTYPE html>
<html>
<head>
<title>
Digi Demo - Management
</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<link href="https://cdn.jsdelivr.net/gh/gitbrent/bootstrap4-toggle@3.6.1/css/bootstrap4-toggle.min.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-slider/9.7.3/css/bootstrap-slider.min.css" rel="stylesheet">
<link rel="stylesheet" href="/static/css/login.css">
<link rel="stylesheet" href="/static/css/general.css">
<link rel="stylesheet" href="/static/css/toastr.css">
<link rel="stylesheet" href="/static/css/xterm.css">
<!-- JS, Popper.js, and jQuery -->
<script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js" integrity="sha384-B4gt1jrGC7Jh4AgTPSdUtOBvfO8shuf57BaghqFfPlYxofvL8/KUEfYiJOMMV+rV" crossorigin="anonymous"></script>
<script src="https://kit.fontawesome.com/1e66c78073.js" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/gh/gitbrent/bootstrap4-toggle@3.6.1/js/bootstrap4-toggle.min.js"></script>
<script src="https://www.gstatic.com/charts/loader.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-slider/9.7.3/bootstrap-slider.min.js"></script>
<script>
google.charts.load("current", {"packages":["line"]});
</script>
<script type="text/javascript" src="/static/js/common.js"></script>
<script type="text/javascript" src="/static/js/devices.js"></script>
<script type="text/javascript" src="/static/js/jquery.pjax.js"></script>
<script type="text/javascript" src="/static/js/jquery.matchHeight-min.js"></script>
<script type="text/javascript" src="/static/js/toastr.min.js"></script>
</head>
<body>
<nav id="topBar" class="navbar navbar-expand-lg navbar-light bg-white shadow-sm">
<div class="nav-container">
<a id="banner-link" class="navbar-brand align-middle" href="/">
<div class="d-flex align-items-baseline">
<img id="banner-logo" class="banner-icon" src="/static/images/Digi_logo_banner.png">
<p id="banner-text">ConnectCore Demo</p>
</div>
</a>
<div class="nav-right-container">
<div id="data_usage_panel" class="data-usage-panel" style="display: none;">
<div class="data-usage-panel-wrapper">
<div id="data_usage_loading" class="data-usage-loading">
<div class="data-usage-loading-background"></div>
<img class="data-usage-loading-icon" src="/static/images/loading.gif" alt="Loading..." />
<div class="data-usage-loading-text">Loading data...</div>
</div>
<div id="data_usage_content" class="data-usage-content">
<div class="data-usage-section">
<div class="data-usage-header">
<div class="data-usage-title">Total account data usage</div>
<div class="fas fa-sync device-card-header-button" onclick="refreshUsageData()"></div>
</div>
<div id="data_usage_total" class="data-usage-total-value">-</div>
<div class="data-usage-graphic-container">
<button id="data_usage_graphic_devices" class="fas data-usage-graphic data-usage-graphic-devices" data-toggle="tooltip" data-placement="bottom" title="Total data usage by devices"></button>
<button id="data_usage_graphic_web" class="fas data-usage-graphic data-usage-graphic-web" data-toggle="tooltip" data-placement="bottom" title="Total data usage by web APIs"></button>
</div>
<div class="data-usage-values-container">
<table>
<tr>
<td>
<div class="data-usage-legend data-usage-graphic-devices"></div>
</td>
<td>
<div class="data-usage-legend-text">Devices data usage</div>
</td>
</tr>
<tr>
<td>
<div class="data-usage-legend data-usage-graphic-web"></div>
</td>
<td>
<div class="data-usage-legend-text">Web APIs data usage</div>
</td>
</tr>
</table>
</div>
</div>
<div class="data-usage-section">
<div class="data-usage-title">Devices usage</div>
<div class="data-usage-values-container">
<table>
<tr>
<td>
<div class="data-usage-value-label-bold">Total devices usage:</div>
</td>
<td>
<div id="data_usage_devices" class="data-usage-value-bold">-</div>
</td>
</tr>
<tr>
<td>
<div class="data-usage-value-label">Current device usage:</div>
</td>
<td>
<div id="data_usage_current_device" class="data-usage-value">-</div>
</td>
</tr>
</table>
</div>
</div>
<div class="data-usage-section">
<div class="data-usage-title">Web APIs usage</div>
<div class="data-usage-values-container">
<table>
<tr>
<td>
<div class="data-usage-value-label-bold">Total web APIs usage:</div>
</td>
<td>
<div id="data_usage_web" class="data-usage-value-bold">-</div>
</td>
</tr>
<tr>
<td>
<div class="data-usage-value-label">Web services usage:</div>
</td>
<td>
<div id="data_usage_web_services" class="data-usage-value">-</div>
</td>
</tr>
<tr>
<td>
<div class="data-usage-value-label">Monitors usage:</div>
</td>
<td>
<div id="data_usage_monitors" class="data-usage-value">-</div>
</td>
</tr>
</table>
</div>
</div>
</div>
</div>
</div>
<div>
<img src="/static/images/board.png" class="device-title-img" title="Device">
</div>
<div id="device-name"></div>
<div>
<img src="/static/images/status_offline.png" id="device-connection-status" class="device-title-img" title="Offline">
</div>
<div class="vertical-separator"></div>
<div>
<button id="devices-list-button" class="btn widget-button" type="button" value="0" onclick="window.open('/','_self');">
<img src="/static/images/devices_list_gray.png" id="devices-list-icon" class="devices-list-icon" data-toggle="tooltip" data-placement="bottom" title="Open devices list">
</button>
<button id="data_usage_button" class="btn widget-button" type="button" value="0" onclick="toggleDataUsagePanel();">
<img src="/static/images/data_usage.png" id="data_usage_icon" class="devices-list-icon" data-toggle="tooltip" data-placement="bottom" title="Show data usage">
</button>
</div>
<div class="vertical-separator"></div>
<div class="dropdown digi-gray" id="profile-container">
<button class="btn dropdown-toggle" type="button" id="profileMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<img id="profile-logo" class="banner-icon" src="/static/images/profile_gray.png">
</button>
<div class="dropdown-menu shadow-sm" aria-labelledby="profileMenuButton">
<a class="dropdown-item" href="/access/logout/">Log out</a>
</div>
</div>
</div>
</div>
</nav>
<div class="bg-light" id="body-row">
<!-- Sidebar https://www.codeply.com/go/3e0RAjccRO/bootstrap-4-collapsing-sidebar-menu# -->
<div id="sidebar-container" class="sidebar-expanded d-none d-md-block">
<!-- d-* hides the Sidebar in smaller devices. Its items can be kept on the Navbar 'Menu' -->
<div id="sidebar-contents">
<!-- Bootstrap List Group -->
<ul id="sections" data-pjax class="list-group">
<li>
<a data-pjax href="/dashboard/" class="list-group-item list-group-item-action d-flex align-items-center">
<div class="d-flex w-100 justify-content-start align-items-center">
<span class="digi-menu-icon fas fa-tachometer-alt fa-fw fa-lg mr-3"></span>
<span class="menu-collapsed">Dashboard</span>
</div>
</a>
</li>
<li>
<a data-pjax href="/history/" class="list-group-item list-group-item-action d-flex align-items-center">
<div class="d-flex w-100 justify-content-start align-items-center">
<span class="digi-menu-icon fas fa-chart-area fa-fw fa-lg mr-3"></span>
<span class="menu-collapsed">Historical data</span>
</div>
</a>
</li>
<li>
<a data-pjax href="/management/" class="list-group-item list-group-item-action d-flex align-items-center">
<div class="d-flex w-100 justify-content-start align-items-center">
<span class="digi-menu-icon fas fa-cog fa-fw fa-lg mr-3"></span>
<span class="menu-collapsed">Management</span>
</div>
</a>
</li>
</ul>
<ul id="collapsator" class="list-group">
<a href="#top" data-toggle="sidebar-collapse" class="list-group-item list-group-item-action d-flex align-items-center">
<div class="d-flex w-100 justify-content-start align-items-center">
<span id="collapse-icon" class="digi-menu-icon fas fa-fw fa-lg mr-3"></span>
<span id="collapse-text" class="menu-collapsed">Collapse</span>
</div>
</a>
</ul>
</div>
</div>
<div class="container-fluid">
<div id="loading">
<img id="loading-image" src="/static/images/loading.gif" alt="Loading..." />
</div>
<div id="pjax-container">
<!-- <input type="file" id="firmware_file" style="display:none" onchange="firmwareFileChanged()" accept=".swu,.json,.txt"/>-->
<input type="file" id="firmware_file" style="display:none" onchange="firmwareFileChanged()"/>
<div class="row justify-content-lg-center">
<div class="col-lg-12 col-xl-12">
<div id="loading_popup" class="popup popup-loading shadow">
<img class="popup-item" src="/static/images/loading.gif" alt="Loading..." />
<div id="loading_popup_message" class="popup-text">Loading information...</div>
</div>
<div id="info_popup" class="popup popup-info shadow d-none">
<div id="info_popup_title" class="popup-title">Error</div>
<div id="info_popup_message" class="popup-text">-</div>
</div>
<div id="confirm_dialog" class="confirm-dialog d-none">
<div class="device-card-header">
<span class="fas fa-question-circle fa-lg mr-2"></span>
<span id="confirm_dialog_title"></span>
<div class="fas fa-window-close fa-lg device-card-header-button" onclick="showPopup(ID_LOADING_WRAPPER, ID_CONFIRM_DIALOG, false)"></div>
</div>
<div id="confirm_dialog_message" class="confirm-dialog-message"></div>
<div class="confirm-dialog-buttons-container">
<div id="confirm_dialog_no_button" class="device-card-button confirm-dialog-button">No</div>
<div id="confirm_dialog_yes_button" class="device-card-button confirm-dialog-button">Yes</div>
</div>
</div>
<div id="loading_wrapper" class="loading-wrapper element-grayed">
<div class="card shadow-sm">
<div class="card-body">
<h5 class="card-title">System monitor</h5>
<div>Configure the system monitor service parameters.</div>
<div class="system-monitor-param-container">
<span class="system-monitor-param-label">Time between samples:</span>
<input id="sample_rate" class="system-monitor-input" type="text"/>
<button class="fas fa-question-circle system-monitor-help" title="Time to wait between samples read (in seconds). Must be a positive number greater than 0." data-toggle="tooltip" data-placement="right"></button>
</div>
<div id="sample_rate_error" class="system-monitor-error"></div>
<div class="system-monitor-param-container">
<span class="system-monitor-param-label">Samples to buffer:</span>
<input id="num_samples_upload" class="system-monitor-input" type="text"/>
<button class="fas fa-question-circle system-monitor-help" title="Number of samples of each parameter to gather before uploading them to Digi Remote Manager. Must be a positive number greater than 0." data-toggle="tooltip" data-placement="right"></button>
</div>
<div id="samples_buffer_error" class="system-monitor-error"></div>
<div id="save_button" class="device-card-button system-monitor-save system-monitor-save-disabled" onclick="saveSystemMonitor()">Save</div>
</div>
</div>
<div class="card shadow-sm">
<div class="card-body">
<h5 class="card-title">Reboot device</h5>
<div>Click <b>REBOOT</b> to restart your device.</div>
<div id="reboot_button" class="device-card-button reboot-button" onclick="askReboot()">REBOOT</div>
</div>
</div>
<div class="card shadow-sm">
<div class="card-body">
<h5 class="card-title">Firmware update</h5>
<table style="margin: 15px;">
<tr>
<td style="width: 180px; vertical-align: top;">
<span class="device-card-content-text">Current DEY version:</span>
</td>
<td>
<span id="dey_version" class="device-card-content-value">-</span>
</td>
</tr>
<tr>
<td style="vertical-align: top;">
<span class="device-card-content-text">Current kernel version:</span>
</td>
<td>
<span id="kernel_version" class="device-card-content-value">-</span>
</td>
</tr>
<tr>
<td style="vertical-align: top;">
<span class="device-card-content-text">Current U-Boot version:</span>
</td>
<td>
<span id="uboot_version" class="device-card-content-value">-</span>
</td>
</tr>
</table>
<div class="firmware-tabs">
<div id="firmware_tab_upload_header" class="firmware-tab-header firmware-tab-header-active" onclick="showFirmwareTab(ID_FIRMWARE_TAB_UPLOAD)">
<span class="fas fa-upload fa-lg"></span>
<span class="firmware-tab-text">Upload file</span>
</div>
<div id="firmware_tab_fileset_header" class="firmware-tab-header" onclick="showFirmwareTab(ID_FIRMWARE_TAB_FILESET)">
<span class="fas fa-database fa-lg"></span>
<span class="firmware-tab-text">Download from storage</span>
</div>
</div>
<div class="firmware-tab-container">
<div id="firmware_tab_upload" class="firmware-tab firmware-tab-upload">
<div>Upload and install a firmware file from your computer.</div>
<div class="firmware-file-container">
<div id="select_firmware_button" class="device-card-button browse-firmware-button" onclick="openFirmwareBrowser()">Choose file...</div>
<div id="firmware_file_label" class="firmware-file-label">No file chosen</div>
</div>
</div>
<div id="firmware_tab_fileset" class="firmware-tab firmware-tab-fileset">
<div>Download and install firmware from Digi Remote Manager storage.</div>
<div class="fileset-items-header">
<div class="fileset-entry-icon"></div>
<div class="fileset-entry-name">Name</div>
<div class="fileset-entry-path">Path</div>
<div class="fileset-entry-size">Size</div>
<div class="fileset-entry-last-modified">Last modified</div>
</div>
<div id="fileset_items_container" class="fileset-items-container"></div>
<div id="refresh_fileset_button" class="device-card-button refresh-fileset-button" onclick="refreshFilesetFiles()">Refresh</div>
</div>
</div>
<div id="update_firmware_progress" class="update-firmware-progress">
<div id="update_firmware_progress_title" class="update-firmware-progress-title">Firmware update in progress...</div>
<div class="progress update-firmware-progress-bar">
<div id="update_firmware_progress_bar" class="progress-bar progress-bar-striped update-firmware-progress-bar update-firmware-progress-bar-info update-firmware-progress-bar-hover" role="progressbar" aria-valuenow="40" aria-valuemin="0" aria-valuemax="100" style="width:40%">40%</div>
</div>
<span id="update_firmware_progress_message" class="update-firmware-progress-status">Waiting for firmware update...</span>
</div>
<div>
<div id="update_firmware_button" class="device-card-button update-firmware-button management-button-disabled" onclick="askUpdateFirmware()">Update Firmware</div>
<div id="cancel_update_firmware_button" class="device-card-button cancel-firmware-update-button management-button-disabled" onclick="askCancelFirmwareUpdate()">Cancel update</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
$(document).ready(function() {
// Reset variables.
readingManagementInfo = false;
managementInfoRead = false;
deviceRebooting = false;
updatingFirmware = false;
firmwareUpdateTimer = null;
selectedFilesetEntry = null;
filesLoaded = false;
// Initialize page.
initializeManagementPage();
// Register system monitor input changed.
$("#sample_rate").on("input", function(event) {
validateSystemMonitor(event.target.value);
});
$("#num_samples_upload").on("input", function(event) {
validateSystemMonitor();
});
});
</script>
</div>
</div>
</div>
<script>
function getCookie(cName) {
if (document.cookie.length > 0) {
cStart = document.cookie.indexOf(cName + "=");
if (cStart != -1) {
cStart = cStart + cName.length + 1;
cEnd = document.cookie.indexOf(";", cStart);
if (cEnd == -1)
cEnd = document.cookie.length;
return unescape(document.cookie.substring(cStart, cEnd));
}
}
return "";
}
$.ajaxSetup({
headers: {
"X-CSRFToken": getCookie("csrftoken")
}
});
$(document).ready(function() {
$("#banner-link").on({
"mouseover" : function() {
$("#banner-logo").attr("src", "/static/images/Digi_logo_banner_gray.png");
},
"mouseout" : function() {
$("#banner-logo").attr("src", "/static/images/Digi_logo_banner.png");
}
});
});
// Enable the tooltip library.
$(function() {
$('[data-toggle="tooltip"]').tooltip();
});
</script>
<!-- Local JS files and functions -->
<script>
$( document ).ready(function() {
$("#profile-container").on({
"mouseover" : function() {
$("#profile-logo").attr("src", "/static/images/profile_green.png");
if (!$("#profile-container").hasClass("digi-green")) {
$("#profile-container").addClass("digi-green");
}
if ($("#profile-container").hasClass("digi-gray")) {
$("#profile-container").removeClass("digi-gray");
}
},
"mouseout" : function() {
$("#profile-logo").attr("src", "/static/images/profile_gray.png");
if (!$("#profile-container").hasClass("digi-gray")) {
$("#profile-container").addClass("digi-gray");
}
if ($("#profile-container").hasClass("digi-green")) {
$("#profile-container").removeClass("digi-green");
}
}
});
});
</script>
<!-- Local JS files and functions -->
<script type="text/javascript" src="/static/js/sidebar.js"></script>
<script type="text/javascript" src="/static/js/ccimx8mm-dvk.js"></script>
<script type="text/javascript" src="/static/js/ccimx8m-nano.js"></script>
<script type="text/javascript" src="/static/js/ccimx8x-sbc-pro.js"></script>
<script type="text/javascript" src="/static/js/dashboard.js"></script>
<script type="text/javascript" src="/static/js/management.js"></script>
<script type="text/javascript" src="/static/js/history.js"></script>
<script type="text/javascript" src="/static/js/xterm.js"></script>
<script type="text/javascript" src="/static/js/xterm-addon-fit.js"></script>
<script type="text/javascript" src="/static/js/console.js"></script>
<script type="text/javascript" src="/static/js/file-system.js"></script>
<script type="text/javascript" src="/static/js/data-usage.js"></script>
<script>
$(document).ready(function() {
// Don't show the loading spinner at the beginning. Initial page
// load is full, so not relying on AJAX.
$("#loading").hide();
verifyParameters();
// Set up PJAX.
if ($.support.pjax) {
$.pjax.defaults.timeout = 20000;
$.pjax.defaults.fragment = "#pjax-container";
$(document).pjax("a[data-pjax]", "#pjax-container");
$(document).on("pjax:beforeSend", function() {
// Do not load new content if there are unsaved changes.
if ($("#save-schedule").length && !$("#save-schedule").attr("disabled") && !confirm("There are unsaved changes. Do you want to exit?"))
return false;
});
$(document).on("pjax:send", function(e) {
setSelectedSection(e.currentTarget.activeElement);
$("#pjax-container").hide();
$("#loading").show();
});
$(document).on("pjax:complete", function() {
$("#loading").hide();
$("#pjax-container").show();
verifyParameters();
});
}
// Append the URL parameters to the section links.
var params = new URLSearchParams(window.location.search).toString();
if (params) {
$("#sections li").each(function(i, n) {
n.children[0].href += "?" + params;
});
}
// Set the selected section.
setSelectedSection();
// Set the name of the selected device.
$("#device-name").html("DEY device".toUpperCase());
// Change the color of the devices icon when hovering.
$("#devices-list-button").on({
"mouseover" : function() {
$("#devices-list-icon").attr("src", "/static/images/devices_list_green.png");
},
"mouseout" : function() {
$("#devices-list-icon").attr("src", "/static/images/devices_list_gray.png");
}
});
// Change the color of the data usage icon when hovering.
$("#data_usage_button").on({
"mouseover" : function() {
$("#data_usage_icon").attr("src", "/static/images/data_usage_green.png");
},
"mouseout" : function() {
$("#data_usage_icon").attr("src", "/static/images/data_usage.png");
}
});
// Check the device connection status.
checkDeviceConnectionStatus();
});
</script>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,228 @@
.toast-title {
font-weight: bold;
}
.toast-message {
-ms-word-wrap: break-word;
word-wrap: break-word;
}
.toast-message a,
.toast-message label {
color: #FFFFFF;
}
.toast-message a:hover {
color: #CCCCCC;
text-decoration: none;
}
.toast-close-button {
position: relative;
right: -0.3em;
top: -0.3em;
float: right;
font-size: 20px;
font-weight: bold;
color: #FFFFFF;
-webkit-text-shadow: 0 1px 0 #ffffff;
text-shadow: 0 1px 0 #ffffff;
opacity: 0.8;
-ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=80);
filter: alpha(opacity=80);
line-height: 1;
}
.toast-close-button:hover,
.toast-close-button:focus {
color: #000000;
text-decoration: none;
cursor: pointer;
opacity: 0.4;
-ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=40);
filter: alpha(opacity=40);
}
.rtl .toast-close-button {
left: -0.3em;
float: left;
right: 0.3em;
}
/*Additional properties for button version
iOS requires the button element instead of an anchor tag.
If you want the anchor version, it requires `href="#"`.*/
button.toast-close-button {
padding: 0;
cursor: pointer;
background: transparent;
border: 0;
-webkit-appearance: none;
}
.toast-top-center {
top: 0;
right: 0;
width: 100%;
}
.toast-bottom-center {
bottom: 0;
right: 0;
width: 100%;
}
.toast-top-full-width {
top: 0;
right: 0;
width: 100%;
}
.toast-bottom-full-width {
bottom: 0;
right: 0;
width: 100%;
}
.toast-top-left {
top: 12px;
left: 12px;
}
.toast-top-right {
top: 12px;
right: 12px;
}
.toast-bottom-right {
right: 12px;
bottom: 12px;
}
.toast-bottom-left {
bottom: 12px;
left: 12px;
}
#toast-container {
position: fixed;
z-index: 999999;
pointer-events: none;
/*overrides*/
}
#toast-container * {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
#toast-container > div {
position: relative;
pointer-events: auto;
overflow: hidden;
margin: 0 0 6px;
padding: 15px 15px 15px 50px;
width: 300px;
-moz-border-radius: 3px 3px 3px 3px;
-webkit-border-radius: 3px 3px 3px 3px;
border-radius: 3px 3px 3px 3px;
background-position: 15px center;
background-repeat: no-repeat;
-moz-box-shadow: 0 0 12px #999999;
-webkit-box-shadow: 0 0 12px #999999;
box-shadow: 0 0 12px #999999;
color: #FFFFFF;
opacity: 0.8;
-ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=80);
filter: alpha(opacity=80);
}
#toast-container > div.rtl {
direction: rtl;
padding: 15px 50px 15px 15px;
background-position: right 15px center;
}
#toast-container > div:hover {
-moz-box-shadow: 0 0 12px #000000;
-webkit-box-shadow: 0 0 12px #000000;
box-shadow: 0 0 12px #000000;
opacity: 1;
-ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=100);
filter: alpha(opacity=100);
cursor: pointer;
}
#toast-container > .toast-info {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGwSURBVEhLtZa9SgNBEMc9sUxxRcoUKSzSWIhXpFMhhYWFhaBg4yPYiWCXZxBLERsLRS3EQkEfwCKdjWJAwSKCgoKCcudv4O5YLrt7EzgXhiU3/4+b2ckmwVjJSpKkQ6wAi4gwhT+z3wRBcEz0yjSseUTrcRyfsHsXmD0AmbHOC9Ii8VImnuXBPglHpQ5wwSVM7sNnTG7Za4JwDdCjxyAiH3nyA2mtaTJufiDZ5dCaqlItILh1NHatfN5skvjx9Z38m69CgzuXmZgVrPIGE763Jx9qKsRozWYw6xOHdER+nn2KkO+Bb+UV5CBN6WC6QtBgbRVozrahAbmm6HtUsgtPC19tFdxXZYBOfkbmFJ1VaHA1VAHjd0pp70oTZzvR+EVrx2Ygfdsq6eu55BHYR8hlcki+n+kERUFG8BrA0BwjeAv2M8WLQBtcy+SD6fNsmnB3AlBLrgTtVW1c2QN4bVWLATaIS60J2Du5y1TiJgjSBvFVZgTmwCU+dAZFoPxGEEs8nyHC9Bwe2GvEJv2WXZb0vjdyFT4Cxk3e/kIqlOGoVLwwPevpYHT+00T+hWwXDf4AJAOUqWcDhbwAAAAASUVORK5CYII=") !important;
}
#toast-container > .toast-error {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHOSURBVEhLrZa/SgNBEMZzh0WKCClSCKaIYOED+AAKeQQLG8HWztLCImBrYadgIdY+gIKNYkBFSwu7CAoqCgkkoGBI/E28PdbLZmeDLgzZzcx83/zZ2SSXC1j9fr+I1Hq93g2yxH4iwM1vkoBWAdxCmpzTxfkN2RcyZNaHFIkSo10+8kgxkXIURV5HGxTmFuc75B2RfQkpxHG8aAgaAFa0tAHqYFfQ7Iwe2yhODk8+J4C7yAoRTWI3w/4klGRgR4lO7Rpn9+gvMyWp+uxFh8+H+ARlgN1nJuJuQAYvNkEnwGFck18Er4q3egEc/oO+mhLdKgRyhdNFiacC0rlOCbhNVz4H9FnAYgDBvU3QIioZlJFLJtsoHYRDfiZoUyIxqCtRpVlANq0EU4dApjrtgezPFad5S19Wgjkc0hNVnuF4HjVA6C7QrSIbylB+oZe3aHgBsqlNqKYH48jXyJKMuAbiyVJ8KzaB3eRc0pg9VwQ4niFryI68qiOi3AbjwdsfnAtk0bCjTLJKr6mrD9g8iq/S/B81hguOMlQTnVyG40wAcjnmgsCNESDrjme7wfftP4P7SP4N3CJZdvzoNyGq2c/HWOXJGsvVg+RA/k2MC/wN6I2YA2Pt8GkAAAAASUVORK5CYII=") !important;
}
#toast-container > .toast-success {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADsSURBVEhLY2AYBfQMgf///3P8+/evAIgvA/FsIF+BavYDDWMBGroaSMMBiE8VC7AZDrIFaMFnii3AZTjUgsUUWUDA8OdAH6iQbQEhw4HyGsPEcKBXBIC4ARhex4G4BsjmweU1soIFaGg/WtoFZRIZdEvIMhxkCCjXIVsATV6gFGACs4Rsw0EGgIIH3QJYJgHSARQZDrWAB+jawzgs+Q2UO49D7jnRSRGoEFRILcdmEMWGI0cm0JJ2QpYA1RDvcmzJEWhABhD/pqrL0S0CWuABKgnRki9lLseS7g2AlqwHWQSKH4oKLrILpRGhEQCw2LiRUIa4lwAAAABJRU5ErkJggg==") !important;
}
#toast-container > .toast-warning {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGYSURBVEhL5ZSvTsNQFMbXZGICMYGYmJhAQIJAICYQPAACiSDB8AiICQQJT4CqQEwgJvYASAQCiZiYmJhAIBATCARJy+9rTsldd8sKu1M0+dLb057v6/lbq/2rK0mS/TRNj9cWNAKPYIJII7gIxCcQ51cvqID+GIEX8ASG4B1bK5gIZFeQfoJdEXOfgX4QAQg7kH2A65yQ87lyxb27sggkAzAuFhbbg1K2kgCkB1bVwyIR9m2L7PRPIhDUIXgGtyKw575yz3lTNs6X4JXnjV+LKM/m3MydnTbtOKIjtz6VhCBq4vSm3ncdrD2lk0VgUXSVKjVDJXJzijW1RQdsU7F77He8u68koNZTz8Oz5yGa6J3H3lZ0xYgXBK2QymlWWA+RWnYhskLBv2vmE+hBMCtbA7KX5drWyRT/2JsqZ2IvfB9Y4bWDNMFbJRFmC9E74SoS0CqulwjkC0+5bpcV1CZ8NMej4pjy0U+doDQsGyo1hzVJttIjhQ7GnBtRFN1UarUlH8F3xict+HY07rEzoUGPlWcjRFRr4/gChZgc3ZL2d8oAAAAASUVORK5CYII=") !important;
}
#toast-container.toast-top-center > div,
#toast-container.toast-bottom-center > div {
width: 300px;
margin-left: auto;
margin-right: auto;
}
#toast-container.toast-top-full-width > div,
#toast-container.toast-bottom-full-width > div {
width: 96%;
margin-left: auto;
margin-right: auto;
}
.toast {
background-color: #030303;
}
.toast-success {
background-color: #51A351;
}
.toast-error {
background-color: #BD362F;
}
.toast-info {
background-color: #2F96B4;
}
.toast-warning {
background-color: #F89406;
}
.toast-progress {
position: absolute;
left: 0;
bottom: 0;
height: 4px;
background-color: #000000;
opacity: 0.4;
-ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=40);
filter: alpha(opacity=40);
}
/*Responsive Design*/
@media all and (max-width: 240px) {
#toast-container > div {
padding: 8px 8px 8px 50px;
width: 11em;
}
#toast-container > div.rtl {
padding: 8px 50px 8px 8px;
}
#toast-container .toast-close-button {
right: -0.2em;
top: -0.2em;
}
#toast-container .rtl .toast-close-button {
left: -0.2em;
right: 0.2em;
}
}
@media all and (min-width: 241px) and (max-width: 480px) {
#toast-container > div {
padding: 8px 8px 8px 50px;
width: 18em;
}
#toast-container > div.rtl {
padding: 8px 50px 8px 8px;
}
#toast-container .toast-close-button {
right: -0.2em;
top: -0.2em;
}
#toast-container .rtl .toast-close-button {
left: -0.2em;
right: 0.2em;
}
}
@media all and (min-width: 481px) and (max-width: 768px) {
#toast-container > div {
padding: 15px 15px 15px 50px;
width: 25em;
}
#toast-container > div.rtl {
padding: 15px 50px 15px 15px;
}
}

View File

@ -0,0 +1,187 @@
/**
* Copyright (c) 2014 The xterm.js authors. All rights reserved.
* Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
* https://github.com/chjj/term.js
* @license MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* Originally forked from (with the author's permission):
* Fabrice Bellard's javascript vt100 for jslinux:
* http://bellard.org/jslinux/
* Copyright (c) 2011 Fabrice Bellard
* The original design remains. The terminal itself
* has been extended to include xterm CSI codes, among
* other features.
*/
/**
* Default styles for xterm.js
*/
.xterm {
position: relative;
user-select: none;
-ms-user-select: none;
-webkit-user-select: none;
}
.xterm.focus,
.xterm:focus {
outline: none;
}
.xterm .xterm-helpers {
position: absolute;
top: 0;
/**
* The z-index of the helpers must be higher than the canvases in order for
* IMEs to appear on top.
*/
z-index: 5;
}
.xterm .xterm-helper-textarea {
padding: 0;
border: 0;
margin: 0;
/* Move textarea out of the screen to the far left, so that the cursor is not visible */
position: absolute;
opacity: 0;
left: -9999em;
top: 0;
width: 0;
height: 0;
z-index: -5;
/** Prevent wrapping so the IME appears against the textarea at the correct position */
white-space: nowrap;
overflow: hidden;
resize: none;
}
.xterm .composition-view {
/* TODO: Composition position got messed up somewhere */
background: #000;
color: #FFF;
display: none;
position: absolute;
white-space: nowrap;
z-index: 1;
}
.xterm .composition-view.active {
display: block;
}
.xterm .xterm-viewport {
/* On OS X this is required in order for the scroll bar to appear fully opaque */
background-color: #000;
overflow-y: scroll;
cursor: default;
position: absolute;
right: 0;
left: 0;
top: 0;
bottom: 0;
}
.xterm .xterm-screen {
position: relative;
}
.xterm .xterm-screen canvas {
position: absolute;
left: 0;
top: 0;
}
.xterm .xterm-scroll-area {
visibility: hidden;
}
.xterm-char-measure-element {
display: inline-block;
visibility: hidden;
position: absolute;
top: 0;
left: -9999em;
line-height: normal;
}
.xterm {
cursor: text;
}
.xterm.enable-mouse-events {
/* When mouse events are enabled (eg. tmux), revert to the standard pointer cursor */
cursor: default;
}
.xterm.xterm-cursor-pointer,
.xterm .xterm-cursor-pointer {
cursor: pointer;
}
.xterm.column-select.focus {
/* Column selection mode */
cursor: crosshair;
}
.xterm .xterm-accessibility,
.xterm .xterm-message {
position: absolute;
left: 0;
top: 0;
bottom: 0;
right: 0;
z-index: 10;
color: transparent;
}
.xterm .live-region {
position: absolute;
left: -9999px;
width: 1px;
height: 1px;
overflow: hidden;
}
.xterm-dim {
opacity: 0.5;
}
.xterm-underline {
text-decoration: underline;
}
.xterm-strikethrough {
text-decoration: line-through;
}
.xterm-screen .xterm-decoration-container .xterm-decoration {
z-index: 6;
position: absolute;
}
.xterm-decoration-overview-ruler {
z-index: 7;
position: absolute;
top: 0;
right: 0;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 337 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 881 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 881 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 866 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 589 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 618 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 587 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 596 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 677 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 534 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 646 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 994 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1019 B

View File

@ -0,0 +1,146 @@
/*
* Copyright 2022, Digi International Inc.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
class CCIMX8MNANO extends ConnectCoreDevice {
// Public constants.
static DEVICE_TYPE = "ccimx8mn-dvk";
static PLATFORM_NAME = "ConnectCore 8M-Nano DVK";
// Variables.
BOARD_IMAGE = "ccimx8m-nano_board.png";
BOARD_IMAGE_SCALE = 85;
CPU_COMPONENT_VISIBLE = true;
CPU_COMPONENT_HAS_PANEL = true;
CPU_COMPONENT_HAS_ARROW = true;
CPU_COMPONENT_PANEL_ALWAYS_VISIBLE = false;
CPU_COMPONENT_PANEL_ORIENTATION = VALUE_TOP;
CPU_COMPONENT_PANEL_HORIZONTAL_PERCENT = 28.5;
CPU_COMPONENT_PANEL_VERTICAL_PERCENT = 57;
CPU_COMPONENT_ARROW_PERCENT = 33.5;
CPU_COMPONENT_AREA_TOP_PERCENT = 45.7;
CPU_COMPONENT_AREA_LEFT_PERCENT = 32.4;
CPU_COMPONENT_AREA_WIDTH_PERCENT = 5.7;
CPU_COMPONENT_AREA_HEIGHT_PERCENT = 9;
MEMORY_COMPONENT_VISIBLE = true;
MEMORY_COMPONENT_HAS_PANEL = true;
MEMORY_COMPONENT_HAS_ARROW = true;
MEMORY_COMPONENT_PANEL_ALWAYS_VISIBLE = false;
MEMORY_COMPONENT_PANEL_ORIENTATION = VALUE_BOTTOM;
MEMORY_COMPONENT_PANEL_HORIZONTAL_PERCENT = 22;
MEMORY_COMPONENT_PANEL_VERTICAL_PERCENT = 65;
MEMORY_COMPONENT_ARROW_PERCENT = 33.7;
MEMORY_COMPONENT_AREA_TOP_PERCENT = 37;
MEMORY_COMPONENT_AREA_LEFT_PERCENT = 32.4;
MEMORY_COMPONENT_AREA_WIDTH_PERCENT = 6;
MEMORY_COMPONENT_AREA_HEIGHT_PERCENT = 7;
WIFI_BT_COMPONENT_VISIBLE = true;
WIFI_BT_COMPONENT_HAS_PANEL = true;
WIFI_BT_COMPONENT_HAS_ARROW = true;
WIFI_BT_COMPONENT_PANEL_ALWAYS_VISIBLE = false;
WIFI_BT_COMPONENT_PANEL_ORIENTATION = VALUE_RIGHT;
WIFI_BT_COMPONENT_PANEL_HORIZONTAL_PERCENT = 73;
WIFI_BT_COMPONENT_PANEL_VERTICAL_PERCENT = 38;
WIFI_BT_COMPONENT_ARROW_PERCENT = 46;
WIFI_BT_COMPONENT_AREA_TOP_PERCENT = 46.5;
WIFI_BT_COMPONENT_AREA_LEFT_PERCENT = 28.3;
WIFI_BT_COMPONENT_AREA_WIDTH_PERCENT = 4;
WIFI_BT_COMPONENT_AREA_HEIGHT_PERCENT = 6;
ETHERNET_COMPONENT_VISIBLE = true;
ETHERNET_COMPONENT_HAS_PANEL = true;
ETHERNET_COMPONENT_HAS_ARROW = true;
ETHERNET_COMPONENT_PANEL_ALWAYS_VISIBLE = false;
ETHERNET_COMPONENT_PANEL_ORIENTATION = VALUE_LEFT;
ETHERNET_COMPONENT_PANEL_HORIZONTAL_PERCENT = 21;
ETHERNET_COMPONENT_PANEL_VERTICAL_PERCENT = 70;
ETHERNET_COMPONENT_ARROW_PERCENT = 78;
ETHERNET_COMPONENT_AREA_TOP_PERCENT = 77;
ETHERNET_COMPONENT_AREA_LEFT_PERCENT = 11;
ETHERNET_COMPONENT_AREA_WIDTH_PERCENT = 8.5;
ETHERNET_COMPONENT_AREA_HEIGHT_PERCENT = 16;
CONSOLE_COMPONENT_VISIBLE = true;
CONSOLE_COMPONENT_HAS_PANEL = false;
CONSOLE_COMPONENT_HAS_ARROW = false;
CONSOLE_COMPONENT_PANEL_ALWAYS_VISIBLE = false;
CONSOLE_COMPONENT_AREA_TOP_PERCENT = 6.5;
CONSOLE_COMPONENT_AREA_LEFT_PERCENT = 26.5;
CONSOLE_COMPONENT_AREA_WIDTH_PERCENT = 3.4;
CONSOLE_COMPONENT_AREA_HEIGHT_PERCENT = 4.5;
VIDEO_COMPONENT_VISIBLE = true;
VIDEO_COMPONENT_HAS_PANEL = true;
VIDEO_COMPONENT_HAS_ARROW = true;
VIDEO_COMPONENT_PANEL_ALWAYS_VISIBLE = false;
VIDEO_COMPONENT_PANEL_ORIENTATION = VALUE_BOTTOM;
VIDEO_COMPONENT_PANEL_HORIZONTAL_PERCENT = 47.5;
VIDEO_COMPONENT_PANEL_VERTICAL_PERCENT = 18;
VIDEO_COMPONENT_ARROW_PERCENT = 58.5;
VIDEO_COMPONENT_AREA_TOP_PERCENT = 84;
VIDEO_COMPONENT_AREA_LEFT_PERCENT = 57;
VIDEO_COMPONENT_AREA_WIDTH_PERCENT = 6;
VIDEO_COMPONENT_AREA_HEIGHT_PERCENT = 8;
AUDIO_COMPONENT_VISIBLE = false;
AUDIO_COMPONENT_HAS_PANEL = true;
AUDIO_COMPONENT_HAS_ARROW = true;
AUDIO_COMPONENT_PANEL_ALWAYS_VISIBLE = false;
AUDIO_COMPONENT_PANEL_ORIENTATION = VALUE_TOP;
AUDIO_COMPONENT_PANEL_HORIZONTAL_PERCENT = 1;
AUDIO_COMPONENT_PANEL_VERTICAL_PERCENT = 19;
AUDIO_COMPONENT_ARROW_PERCENT = 16;
AUDIO_COMPONENT_AREA_TOP_PERCENT = 7;
AUDIO_COMPONENT_AREA_LEFT_PERCENT = 14.5;
AUDIO_COMPONENT_AREA_WIDTH_PERCENT = 5.4;
AUDIO_COMPONENT_AREA_HEIGHT_PERCENT = 11;
LED_COMPONENT_VISIBLE = true;
LED_COMPONENT_HAS_PANEL = true;
LED_COMPONENT_HAS_ARROW = false;
LED_COMPONENT_PANEL_ALWAYS_VISIBLE = true;
LED_COMPONENT_PANEL_ORIENTATION = VALUE_TOP;
LED_COMPONENT_PANEL_HORIZONTAL_PERCENT = 61;
LED_COMPONENT_PANEL_VERTICAL_PERCENT = 14;
LED_COMPONENT_AREA_TOP_PERCENT = 8.5;
LED_COMPONENT_AREA_LEFT_PERCENT = 62.6;
LED_COMPONENT_AREA_WIDTH_PERCENT = 1.5;
LED_COMPONENT_AREA_HEIGHT_PERCENT = 4;
FLASH_MEMORY_COMPONENT_VISIBLE = true;
FLASH_MEMORY_COMPONENT_HAS_PANEL = true;
FLASH_MEMORY_COMPONENT_HAS_ARROW = true;
FLASH_MEMORY_COMPONENT_PANEL_ALWAYS_VISIBLE = false;
FLASH_MEMORY_COMPONENT_PANEL_ORIENTATION = VALUE_LEFT;
FLASH_MEMORY_COMPONENT_PANEL_HORIZONTAL_PERCENT = 45;
FLASH_MEMORY_COMPONENT_PANEL_VERTICAL_PERCENT = 36;
FLASH_MEMORY_COMPONENT_ARROW_PERCENT = 38;
FLASH_MEMORY_COMPONENT_AREA_TOP_PERCENT = 36.3;
FLASH_MEMORY_COMPONENT_AREA_LEFT_PERCENT = 38.8;
FLASH_MEMORY_COMPONENT_AREA_WIDTH_PERCENT = 5.4;
FLASH_MEMORY_COMPONENT_AREA_HEIGHT_PERCENT = 8;
// Capabilities
SUPPORTS_VIDEO_BRIGHTNESS = false;
// Constructor.
constructor(deviceID, deviceData) {
super(CCIMX8MNANO.DEVICE_TYPE, CCIMX8MNANO.PLATFORM_NAME, deviceID, deviceData);
}
}

View File

@ -0,0 +1,146 @@
/*
* Copyright 2022, Digi International Inc.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
class CCIMX8MMINI extends ConnectCoreDevice {
// Public constants.
static DEVICE_TYPE = "ccimx8mm-dvk";
static PLATFORM_NAME = "ConnectCore 8M-Mini DVK";
// Variables.
BOARD_IMAGE = "ccimx8m-mini_board.png";
BOARD_IMAGE_SCALE = 85;
CPU_COMPONENT_VISIBLE = true;
CPU_COMPONENT_HAS_PANEL = true;
CPU_COMPONENT_HAS_ARROW = true;
CPU_COMPONENT_PANEL_ALWAYS_VISIBLE = false;
CPU_COMPONENT_PANEL_ORIENTATION = VALUE_TOP;
CPU_COMPONENT_PANEL_HORIZONTAL_PERCENT = 28.5;
CPU_COMPONENT_PANEL_VERTICAL_PERCENT = 57;
CPU_COMPONENT_ARROW_PERCENT = 33.5;
CPU_COMPONENT_AREA_TOP_PERCENT = 45.7;
CPU_COMPONENT_AREA_LEFT_PERCENT = 32.4;
CPU_COMPONENT_AREA_WIDTH_PERCENT = 5.7;
CPU_COMPONENT_AREA_HEIGHT_PERCENT = 9;
MEMORY_COMPONENT_VISIBLE = true;
MEMORY_COMPONENT_HAS_PANEL = true;
MEMORY_COMPONENT_HAS_ARROW = true;
MEMORY_COMPONENT_PANEL_ALWAYS_VISIBLE = false;
MEMORY_COMPONENT_PANEL_ORIENTATION = VALUE_BOTTOM;
MEMORY_COMPONENT_PANEL_HORIZONTAL_PERCENT = 22;
MEMORY_COMPONENT_PANEL_VERTICAL_PERCENT = 65;
MEMORY_COMPONENT_ARROW_PERCENT = 33.7;
MEMORY_COMPONENT_AREA_TOP_PERCENT = 37;
MEMORY_COMPONENT_AREA_LEFT_PERCENT = 32.4;
MEMORY_COMPONENT_AREA_WIDTH_PERCENT = 6;
MEMORY_COMPONENT_AREA_HEIGHT_PERCENT = 7;
WIFI_BT_COMPONENT_VISIBLE = true;
WIFI_BT_COMPONENT_HAS_PANEL = true;
WIFI_BT_COMPONENT_HAS_ARROW = true;
WIFI_BT_COMPONENT_PANEL_ALWAYS_VISIBLE = false;
WIFI_BT_COMPONENT_PANEL_ORIENTATION = VALUE_RIGHT;
WIFI_BT_COMPONENT_PANEL_HORIZONTAL_PERCENT = 73;
WIFI_BT_COMPONENT_PANEL_VERTICAL_PERCENT = 38;
WIFI_BT_COMPONENT_ARROW_PERCENT = 46;
WIFI_BT_COMPONENT_AREA_TOP_PERCENT = 46.5;
WIFI_BT_COMPONENT_AREA_LEFT_PERCENT = 28.3;
WIFI_BT_COMPONENT_AREA_WIDTH_PERCENT = 4;
WIFI_BT_COMPONENT_AREA_HEIGHT_PERCENT = 6;
ETHERNET_COMPONENT_VISIBLE = true;
ETHERNET_COMPONENT_HAS_PANEL = true;
ETHERNET_COMPONENT_HAS_ARROW = true;
ETHERNET_COMPONENT_PANEL_ALWAYS_VISIBLE = false;
ETHERNET_COMPONENT_PANEL_ORIENTATION = VALUE_LEFT;
ETHERNET_COMPONENT_PANEL_HORIZONTAL_PERCENT = 21;
ETHERNET_COMPONENT_PANEL_VERTICAL_PERCENT = 70;
ETHERNET_COMPONENT_ARROW_PERCENT = 78;
ETHERNET_COMPONENT_AREA_TOP_PERCENT = 77;
ETHERNET_COMPONENT_AREA_LEFT_PERCENT = 11;
ETHERNET_COMPONENT_AREA_WIDTH_PERCENT = 8.5;
ETHERNET_COMPONENT_AREA_HEIGHT_PERCENT = 16;
CONSOLE_COMPONENT_VISIBLE = true;
CONSOLE_COMPONENT_HAS_PANEL = false;
CONSOLE_COMPONENT_HAS_ARROW = false;
CONSOLE_COMPONENT_PANEL_ALWAYS_VISIBLE = false;
CONSOLE_COMPONENT_AREA_TOP_PERCENT = 6.5;
CONSOLE_COMPONENT_AREA_LEFT_PERCENT = 26.5;
CONSOLE_COMPONENT_AREA_WIDTH_PERCENT = 3.4;
CONSOLE_COMPONENT_AREA_HEIGHT_PERCENT = 4.5;
VIDEO_COMPONENT_VISIBLE = true;
VIDEO_COMPONENT_HAS_PANEL = true;
VIDEO_COMPONENT_HAS_ARROW = true;
VIDEO_COMPONENT_PANEL_ALWAYS_VISIBLE = false;
VIDEO_COMPONENT_PANEL_ORIENTATION = VALUE_BOTTOM;
VIDEO_COMPONENT_PANEL_HORIZONTAL_PERCENT = 47.5;
VIDEO_COMPONENT_PANEL_VERTICAL_PERCENT = 18;
VIDEO_COMPONENT_ARROW_PERCENT = 58.5;
VIDEO_COMPONENT_AREA_TOP_PERCENT = 84;
VIDEO_COMPONENT_AREA_LEFT_PERCENT = 57;
VIDEO_COMPONENT_AREA_WIDTH_PERCENT = 6;
VIDEO_COMPONENT_AREA_HEIGHT_PERCENT = 8;
AUDIO_COMPONENT_VISIBLE = false;
AUDIO_COMPONENT_HAS_PANEL = true;
AUDIO_COMPONENT_HAS_ARROW = true;
AUDIO_COMPONENT_PANEL_ALWAYS_VISIBLE = false;
AUDIO_COMPONENT_PANEL_ORIENTATION = VALUE_TOP;
AUDIO_COMPONENT_PANEL_HORIZONTAL_PERCENT = 1;
AUDIO_COMPONENT_PANEL_VERTICAL_PERCENT = 19;
AUDIO_COMPONENT_ARROW_PERCENT = 16;
AUDIO_COMPONENT_AREA_TOP_PERCENT = 7;
AUDIO_COMPONENT_AREA_LEFT_PERCENT = 14.5;
AUDIO_COMPONENT_AREA_WIDTH_PERCENT = 5.4;
AUDIO_COMPONENT_AREA_HEIGHT_PERCENT = 11;
LED_COMPONENT_VISIBLE = true;
LED_COMPONENT_HAS_PANEL = true;
LED_COMPONENT_HAS_ARROW = false;
LED_COMPONENT_PANEL_ALWAYS_VISIBLE = true;
LED_COMPONENT_PANEL_ORIENTATION = VALUE_TOP;
LED_COMPONENT_PANEL_HORIZONTAL_PERCENT = 61;
LED_COMPONENT_PANEL_VERTICAL_PERCENT = 14;
LED_COMPONENT_AREA_TOP_PERCENT = 8.5;
LED_COMPONENT_AREA_LEFT_PERCENT = 62.6;
LED_COMPONENT_AREA_WIDTH_PERCENT = 1.5;
LED_COMPONENT_AREA_HEIGHT_PERCENT = 4;
FLASH_MEMORY_COMPONENT_VISIBLE = true;
FLASH_MEMORY_COMPONENT_HAS_PANEL = true;
FLASH_MEMORY_COMPONENT_HAS_ARROW = true;
FLASH_MEMORY_COMPONENT_PANEL_ALWAYS_VISIBLE = false;
FLASH_MEMORY_COMPONENT_PANEL_ORIENTATION = VALUE_LEFT;
FLASH_MEMORY_COMPONENT_PANEL_HORIZONTAL_PERCENT = 45;
FLASH_MEMORY_COMPONENT_PANEL_VERTICAL_PERCENT = 36;
FLASH_MEMORY_COMPONENT_ARROW_PERCENT = 38;
FLASH_MEMORY_COMPONENT_AREA_TOP_PERCENT = 36.3;
FLASH_MEMORY_COMPONENT_AREA_LEFT_PERCENT = 38.8;
FLASH_MEMORY_COMPONENT_AREA_WIDTH_PERCENT = 5.4;
FLASH_MEMORY_COMPONENT_AREA_HEIGHT_PERCENT = 8;
// Capabilities
SUPPORTS_VIDEO_BRIGHTNESS = false;
// Constructor.
constructor(deviceID, deviceData) {
super(CCIMX8MMINI.DEVICE_TYPE, CCIMX8MMINI.PLATFORM_NAME, deviceID, deviceData);
}
}

View File

@ -0,0 +1,146 @@
/*
* Copyright 2022, Digi International Inc.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
class CCIMX8X extends ConnectCoreDevice {
// Public constants.
static DEVICE_TYPE = "ccimx8x-sbc-pro";
static PLATFORM_NAME = "ConnectCore 8X SBC Pro";
// Variables.
BOARD_IMAGE = "ccimx8x-sbc-pro_board.png";
BOARD_IMAGE_SCALE = 60;
CPU_COMPONENT_VISIBLE = true;
CPU_COMPONENT_HAS_PANEL = true;
CPU_COMPONENT_HAS_ARROW = true;
CPU_COMPONENT_PANEL_ALWAYS_VISIBLE = false;
CPU_COMPONENT_PANEL_ORIENTATION = VALUE_TOP;
CPU_COMPONENT_PANEL_HORIZONTAL_PERCENT = 49;
CPU_COMPONENT_PANEL_VERTICAL_PERCENT = 65;
CPU_COMPONENT_ARROW_PERCENT = 62;
CPU_COMPONENT_AREA_TOP_PERCENT = 40;
CPU_COMPONENT_AREA_LEFT_PERCENT = 54;
CPU_COMPONENT_AREA_WIDTH_PERCENT = 19.5;
CPU_COMPONENT_AREA_HEIGHT_PERCENT = 24;
MEMORY_COMPONENT_VISIBLE = true;
MEMORY_COMPONENT_HAS_PANEL = true;
MEMORY_COMPONENT_HAS_ARROW = true;
MEMORY_COMPONENT_PANEL_ALWAYS_VISIBLE = false;
MEMORY_COMPONENT_PANEL_ORIENTATION = VALUE_RIGHT;
MEMORY_COMPONENT_PANEL_HORIZONTAL_PERCENT = 43;
MEMORY_COMPONENT_PANEL_VERTICAL_PERCENT = 22.5;
MEMORY_COMPONENT_ARROW_PERCENT = 29;
MEMORY_COMPONENT_AREA_TOP_PERCENT = 22.25;
MEMORY_COMPONENT_AREA_LEFT_PERCENT = 57.75;
MEMORY_COMPONENT_AREA_WIDTH_PERCENT = 9.5;
MEMORY_COMPONENT_AREA_HEIGHT_PERCENT = 16.5;
WIFI_BT_COMPONENT_VISIBLE = true;
WIFI_BT_COMPONENT_HAS_PANEL = true;
WIFI_BT_COMPONENT_HAS_ARROW = true;
WIFI_BT_COMPONENT_PANEL_ALWAYS_VISIBLE = false;
WIFI_BT_COMPONENT_PANEL_ORIENTATION = VALUE_LEFT;
WIFI_BT_COMPONENT_PANEL_HORIZONTAL_PERCENT = 83;
WIFI_BT_COMPONENT_PANEL_VERTICAL_PERCENT = 35;
WIFI_BT_COMPONENT_ARROW_PERCENT = 41;
WIFI_BT_COMPONENT_AREA_TOP_PERCENT = 38;
WIFI_BT_COMPONENT_AREA_LEFT_PERCENT = 73.5;
WIFI_BT_COMPONENT_AREA_WIDTH_PERCENT = 8.5;
WIFI_BT_COMPONENT_AREA_HEIGHT_PERCENT = 10;
ETHERNET_COMPONENT_VISIBLE = true;
ETHERNET_COMPONENT_HAS_PANEL = true;
ETHERNET_COMPONENT_HAS_ARROW = true;
ETHERNET_COMPONENT_PANEL_ALWAYS_VISIBLE = false;
ETHERNET_COMPONENT_PANEL_ORIENTATION = VALUE_BOTTOM;
ETHERNET_COMPONENT_PANEL_HORIZONTAL_PERCENT = -7;
ETHERNET_COMPONENT_PANEL_VERTICAL_PERCENT = 34;
ETHERNET_COMPONENT_ARROW_PERCENT = 18;
ETHERNET_COMPONENT_AREA_TOP_PERCENT = 68;
ETHERNET_COMPONENT_AREA_LEFT_PERCENT = 12;
ETHERNET_COMPONENT_AREA_WIDTH_PERCENT = 17;
ETHERNET_COMPONENT_AREA_HEIGHT_PERCENT = 27;
CONSOLE_COMPONENT_VISIBLE = true;
CONSOLE_COMPONENT_HAS_PANEL = false;
CONSOLE_COMPONENT_HAS_ARROW = false;
CONSOLE_COMPONENT_PANEL_ALWAYS_VISIBLE = false;
CONSOLE_COMPONENT_AREA_TOP_PERCENT = 22.5;
CONSOLE_COMPONENT_AREA_LEFT_PERCENT = 86;
CONSOLE_COMPONENT_AREA_WIDTH_PERCENT = 7;
CONSOLE_COMPONENT_AREA_HEIGHT_PERCENT = 4.5;
VIDEO_COMPONENT_VISIBLE = true;
VIDEO_COMPONENT_HAS_PANEL = true;
VIDEO_COMPONENT_HAS_ARROW = true;
VIDEO_COMPONENT_PANEL_ALWAYS_VISIBLE = false;
VIDEO_COMPONENT_PANEL_ORIENTATION = VALUE_TOP;
VIDEO_COMPONENT_PANEL_HORIZONTAL_PERCENT = -15;
VIDEO_COMPONENT_PANEL_VERTICAL_PERCENT = 18;
VIDEO_COMPONENT_ARROW_PERCENT = 20.75;
VIDEO_COMPONENT_AREA_TOP_PERCENT = 8.5;
VIDEO_COMPONENT_AREA_LEFT_PERCENT = 8.75;
VIDEO_COMPONENT_AREA_WIDTH_PERCENT = 27.5;
VIDEO_COMPONENT_AREA_HEIGHT_PERCENT = 7.5;
AUDIO_COMPONENT_VISIBLE = false;
AUDIO_COMPONENT_HAS_PANEL = true;
AUDIO_COMPONENT_HAS_ARROW = true;
AUDIO_COMPONENT_PANEL_ALWAYS_VISIBLE = false;
AUDIO_COMPONENT_PANEL_ORIENTATION = VALUE_TOP;
AUDIO_COMPONENT_PANEL_HORIZONTAL_PERCENT = 1;
AUDIO_COMPONENT_PANEL_VERTICAL_PERCENT = 19;
AUDIO_COMPONENT_ARROW_PERCENT = 16;
AUDIO_COMPONENT_AREA_TOP_PERCENT = 7;
AUDIO_COMPONENT_AREA_LEFT_PERCENT = 14.5;
AUDIO_COMPONENT_AREA_WIDTH_PERCENT = 5.4;
AUDIO_COMPONENT_AREA_HEIGHT_PERCENT = 11;
LED_COMPONENT_VISIBLE = true;
LED_COMPONENT_HAS_PANEL = true;
LED_COMPONENT_HAS_ARROW = false;
LED_COMPONENT_PANEL_ALWAYS_VISIBLE = true;
LED_COMPONENT_PANEL_ORIENTATION = VALUE_LEFT;
LED_COMPONENT_PANEL_HORIZONTAL_PERCENT = 30;
LED_COMPONENT_PANEL_VERTICAL_PERCENT = 52;
LED_COMPONENT_AREA_TOP_PERCENT = 53.5;
LED_COMPONENT_AREA_LEFT_PERCENT = 27;
LED_COMPONENT_AREA_WIDTH_PERCENT = 2.5;
LED_COMPONENT_AREA_HEIGHT_PERCENT = 5;
FLASH_MEMORY_COMPONENT_VISIBLE = true;
FLASH_MEMORY_COMPONENT_HAS_PANEL = true;
FLASH_MEMORY_COMPONENT_HAS_ARROW = true;
FLASH_MEMORY_COMPONENT_PANEL_ALWAYS_VISIBLE = false;
FLASH_MEMORY_COMPONENT_PANEL_ORIENTATION = VALUE_BOTTOM;
FLASH_MEMORY_COMPONENT_PANEL_HORIZONTAL_PERCENT = 57.5;
FLASH_MEMORY_COMPONENT_PANEL_VERTICAL_PERCENT = 79.5;
FLASH_MEMORY_COMPONENT_ARROW_PERCENT = 71.5;
FLASH_MEMORY_COMPONENT_AREA_TOP_PERCENT = 22.25;
FLASH_MEMORY_COMPONENT_AREA_LEFT_PERCENT = 68;
FLASH_MEMORY_COMPONENT_AREA_WIDTH_PERCENT = 10.8;
FLASH_MEMORY_COMPONENT_AREA_HEIGHT_PERCENT = 15;
// Capabilities
SUPPORTS_VIDEO_BRIGHTNESS = false;
// Constructor.
constructor(deviceID, deviceData) {
super(CCIMX8X.DEVICE_TYPE, CCIMX8X.PLATFORM_NAME, deviceID, deviceData);
}
}

View File

@ -0,0 +1,455 @@
/*
* Copyright 2022, Digi International Inc.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
// Constants.
const ID_AREA = "area";
const ID_AREA_HEIGHT = "area-height";
const ID_AREA_LEFT_MARGIN = "area-left-margin";
const ID_AREA_TOP_MARGIN = "area-top-margin";
const ID_AREA_WIDTH = "area-width";
const ID_ARROW = "arrow";
const ID_ARROW_MARGIN = "arrow-margin";
const ID_AUDIO = "audio";
const ID_BLUETOOTH_MAC = "bluetooth_mac";
const ID_BOARD_ID = "board_id";
const ID_BOARD_VARIANT = "board_variant";
const ID_BT_READ_DATA = "bluetooth_received_data";
const ID_BT_SENT_DATA = "bluetooth_sent_data";
const ID_BT_STATE = "bluetooth_state";
const ID_CONSOLE = "console";
const ID_CONFIRM_DIALOG = "confirm_dialog";
const ID_CONFIRM_DIALOG_MESSAGE = "confirm_dialog_message";
const ID_CONFIRM_DIALOG_NO_BUTTON = "confirm_dialog_no_button";
const ID_CONFIRM_DIALOG_TITLE = "confirm_dialog_title";
const ID_CONFIRM_DIALOG_YES_BUTTON = "confirm_dialog_yes_button";
const ID_CPU = "cpu";
const ID_CPU_FREQUENCY = "cpu_frequency";
const ID_CPU_LOAD = "cpu_load";
const ID_CPU_TEMPERATURE = "cpu_temperature";
const ID_CPU_UPTIME = "cpu_uptime";
const ID_CURRENT_DIR = "current_dir";
const ID_DATA = "data";
const ID_DATA_USAGE_DEVICES = "data_usage_devices";
const ID_DATA_USAGE_MONITORS = "data_usage_monitors";
const ID_DATA_USAGE_TOTAL = "data_usage_total";
const ID_DATA_USAGE_WEB = "data_usage_web";
const ID_DATA_USAGE_WEB_SERVICES = "data_usage_web_services";
const ID_DEVICE_ID = "device_id";
const ID_DEVICE_NAME = "device_name";
const ID_DEVICE_TYPE = "device_type";
const ID_DEVICES = "devices";
const ID_DEY_VERSION = "dey_version";
const ID_ERROR = "error";
const ID_ERROR_GUIDE = "error_guide";
const ID_ERROR_MESSAGE = "error_msg";
const ID_ERROR_TITLE = "error_title";
const ID_ETHERNET = "ethernet";
const ID_ETHERNET_IP = "ethernet_ip";
const ID_ETHERNET_MAC = "ethernet_mac";
const ID_ETHERNET_READ_DATA = "ethernet_received_data";
const ID_ETHERNET_SENT_DATA = "ethernet_sent_data";
const ID_ETHERNET_STATE = "ethernet_state";
const ID_FILES = "files";
const ID_FLASH_MEMORY = "flash_memory";
const ID_FLASH_SIZE = "flash_size";
const ID_HAS_ARROW = "has-arrow";
const ID_HAS_PANEL = "has-panel";
const ID_ICON = "icon";
const ID_ID = "id";
const ID_INFO_POPUP = "info_popup";
const ID_INFO_POPUP_MESSAGE = "info_popup_message";
const ID_INFO_POPUP_TITLE = "info_popup_title";
const ID_KERNEL_VERSION = "kernel_version";
const ID_LAST_MODIFIED = "last_modified";
const ID_LED = "led";
const ID_LOADING_POPUP = "loading_popup";
const ID_LOADING_POPUP_MESSAGE = "loading_popup_message";
const ID_LOADING_WRAPPER = "loading_wrapper";
const ID_MCA_FW_VERSION = "mca_fw_version";
const ID_MCA_HW_VERSION = "mca_hw_version";
const ID_MEMORY = "memory";
const ID_MEMORY_FREE = "memory_free";
const ID_MEMORY_TOTAL = "memory_total";
const ID_MEMORY_USED = "memory_used";
const ID_MESSAGE = "message";
const ID_MODULE_VARIANT = "module_variant";
const ID_NAME = "name";
const ID_NUM_SAMPLES_UPLOAD = "num_samples_upload";
const ID_ONLINE = "online";
const ID_PANEL = "panel";
const ID_PANEL_ALWAYS_VISIBLE = "panel-always-visible";
const ID_PANEL_HORIZONTAL_MARGIN = "panel-horizontal-margin";
const ID_PANEL_ORIENTATION = "panel-orientation";
const ID_PANEL_VERTICAL_MARGIN = "panel-vertical-margin";
const ID_PATH = "path";
const ID_PROGRESS = "progress";
const ID_SAMPLE_RATE = "sample_rate";
const ID_SERIAL_NUMBER = "serial_number";
const ID_SESSION_ID = "session_id";
const ID_SIZE = "size";
const ID_STATUS = "status";
const ID_STREAM = "stream";
const ID_TIMESTAMP = "timestamp";
const ID_TYPE = "type";
const ID_UBOOT_VERSION = "uboot_version";
const ID_USAGE = "usage";
const ID_VALUE = "value";
const ID_VIDEO = "video";
const ID_VIDEO_RESOLUTION = "video_resolution";
const ID_VISIBLE = "visible";
const ID_WIFI_BT = "wifi-bt";
const ID_WIFI_IP = "wifi_ip";
const ID_WIFI_MAC = "wifi_mac";
const ID_WIFI_READ_DATA = "wifi_received_data";
const ID_WIFI_SENT_DATA = "wifi_sent_data";
const ID_WIFI_STATE = "wifi_state";
const VALUE_ACTIVE = "active";
const VALUE_ABORT = "abort";
const VALUE_BOTTOM = "bottom";
const VALUE_CANCELED = "canceled";
const VALUE_FAILED = "failed";
const VALUE_LEFT = "left";
const VALUE_OFF = "Off";
const VALUE_OFFLINE = "Offline";
const VALUE_ON = "On";
const VALUE_ONLINE = "Online";
const VALUE_RIGHT = "right";
const VALUE_SUCCESSFUL = "successful";
const VALUE_TOP = "top";
const VALUE_UNKNOWN = "unknown";
const CLASS_D_NONE = "d-none";
const CLASS_DISABLED_DIV = "disabled-div";
const CLASS_ELEMENT_GRAYED = "element-grayed";
const CLASS_SELECTED = "selected";
const ERROR_ABORTED = "Operation aborted";
const ERROR_URL_NOT_FOUND = "Requested URL not found";
const ERROR_SERVER_ERROR = "Internal server error";
const ERROR_TITLE = "Error";
const ERROR_UNKNOWN_ERROR = "Unknown error";
const IMAGE_OFFLINE = "status_offline.png";
const IMAGE_ONLINE = "status_online.png";
const PATH_IMAGES = "../static/images/";
String.prototype.format = function() {
var formatted = this;
for (var arg in arguments)
formatted = formatted.replace("{" + arg + "}", arguments[arg]);
return formatted;
};
// Shows/hides a front popup over the given background element.
function showPopup(backElementID, frontElementID, visible) {
// Initialize variables.
var backElement = document.getElementById(backElementID);
var frontElement = document.getElementById(frontElementID);
// Sanity checks.
if (backElement == null || frontElement == null)
return;
// Show/Hide the popup.
if (visible) {
if (!backElement.classList.contains(CLASS_ELEMENT_GRAYED))
backElement.classList.add(CLASS_ELEMENT_GRAYED);
if (frontElement.classList.contains(CLASS_D_NONE))
frontElement.classList.remove(CLASS_D_NONE);
} else {
if (backElement.classList.contains(CLASS_ELEMENT_GRAYED))
backElement.classList.remove(CLASS_ELEMENT_GRAYED);
if (!frontElement.classList.contains(CLASS_D_NONE))
frontElement.classList.add(CLASS_D_NONE);
}
}
// Redirects to the login page.
function redirectToLogin() {
var url = "/access/login?dest=" + window.location.pathname.replaceAll("/", "");
var params = new URLSearchParams(window.location.search);
for (let param of params)
url += "&" + param[0] + "=" + param[1];
window.location.href = url;
}
// Processes the error response of the AJAX request.
function processAjaxErrorResponse(response) {
// Check common error codes.
if (response.status == 401)
redirectToLogin();
var errorMessage = "";
if (response.statusText == VALUE_ABORT)
errorMessage = ERROR_ABORTED;
else if (response.status == 400) {
errorMessage = response.responseJSON[ID_ERROR];
// Show the error message (if any).
if (errorMessage == null)
errorMessage = ERROR_UNKNOWN_ERROR;
} else if (response.status == 404)
errorMessage = ERROR_URL_NOT_FOUND;
else if (response.status == 500)
errorMessage = ERROR_SERVER_ERROR;
else
errorMessage = ERROR_UNKNOWN_ERROR;
// Show toast with the error message.
toastr.error(errorMessage);
// Return the error message.
return errorMessage;
}
// Check if there is any error in the response.
function checkErrorResponse(response, showErrorDialog) {
if (response[ID_ERROR_MESSAGE] != null || response[ID_ERROR] != null) {
// Process error.
var errorTitle = ERROR_TITLE;
var errorMessage = getErrorFromResponse(response);
if (response[ID_ERROR_TITLE] != null)
errorTitle = response[ID_ERROR_TITLE];
// Show toast error.
if (errorMessage != null && errorMessage != "")
toastr.error(errorMessage);
// Hide the loading panel.
showLoadingPopup(false);
// Show error dialog.
if (showErrorDialog)
showInfoPopup(true, errorTitle, errorMessage);
// There was an error, return true.
return true;
}
// No error found.
return false;
}
// Returns the error message from the response.
function getErrorFromResponse(response) {
var error = "";
if (response[ID_ERROR_MESSAGE] != null || response[ID_ERROR] != null) {
if (response[ID_ERROR_MESSAGE] != null) {
error = response[ID_ERROR_MESSAGE];
if (response[ID_ERROR_GUIDE] != null)
error += response[ID_ERROR_GUIDE];
} else
error = response[ID_ERROR];
}
return error;
}
// Shows/hides the loading popup panel.
function showLoadingPopup(visible, message=null) {
// Set loading message only if it is not null and the popup will be visible.
if (visible && message != null)
document.getElementById(ID_LOADING_POPUP_MESSAGE).innerHTML = message;
// Show/Hide the popup.
showPopup(ID_LOADING_WRAPPER, ID_LOADING_POPUP, visible);
}
// Shows/hides the info popup panel.
function showInfoPopup(visible, tittle=null, message=null) {
// Set title and message.
if (visible && tittle != null && message != null) {
// Initialize vars.
var infoPopupTittleElement = document.getElementById(ID_INFO_POPUP_TITLE);
var infoPopupMessageElement = document.getElementById(ID_INFO_POPUP_MESSAGE);
// Set the info title.
if (infoPopupTittleElement != null)
infoPopupTittleElement.innerHTML = tittle;
// Set the info message.
if (infoPopupMessageElement != null)
infoPopupMessageElement.innerHTML = message;
}
// Show/Hide the popup.
showPopup(ID_LOADING_WRAPPER, ID_INFO_POPUP, visible);
}
// Shows the confirm dialog.
function showConfirmDialog(title, message, yesCallback, noCallback) {
// Initialize variables.
var confirmDialogTitleElement = document.getElementById(ID_CONFIRM_DIALOG_TITLE);
var confirmDialogMessageElement = document.getElementById(ID_CONFIRM_DIALOG_MESSAGE);
var confirmDialogYesButtonElement = document.getElementById(ID_CONFIRM_DIALOG_YES_BUTTON);
var confirmDialogNoButtonElement = document.getElementById(ID_CONFIRM_DIALOG_NO_BUTTON);
// Check if the elements are valid.
if (confirmDialogTitleElement != null && confirmDialogMessageElement != null &&
confirmDialogYesButtonElement != null && confirmDialogNoButtonElement != null) {
// Set the dialog title.
confirmDialogTitleElement.innerHTML = title;
// Set the dialog message.
confirmDialogMessageElement.innerHTML = message;
// Show the dialog.
showPopup(ID_LOADING_WRAPPER, ID_CONFIRM_DIALOG, true);
// Set the yes button callback.
confirmDialogYesButtonElement.onclick = function() {
// Hide the dialog.
showPopup(ID_LOADING_WRAPPER, ID_CONFIRM_DIALOG, false);
// Call the callback.
if (yesCallback != null)
yesCallback();
};
// Set the no button callback.
confirmDialogNoButtonElement.onclick = function() {
// Hide the dialog.
showPopup(ID_LOADING_WRAPPER, ID_CONFIRM_DIALOG, false);
// Call the callback.
if (noCallback != null)
noCallback();
};
}
}
// Transforms the given ISO8601 date to human readable date.
function transformDate(iso8601Date) {
// Initialize variables.
var date = new Date(iso8601Date);
var humanReadableDate = "";
// Check if the date is valid.
if (date != null) {
// Transform the date to human readable date.
humanReadableDate = date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate() + " " +
date.getHours().toString().padStart(2, '0') + ":" + date.getMinutes().toString().padStart(2, '0');
}
// Return the human readable date.
return humanReadableDate;
}
// Transforms the given kilo-bytes to mega-bytes
function kiloBytesToMegaBytes(kiloBytes) {
return (kiloBytes / 1024).toFixed(2);
}
// Format bytes as human-readable text.
function sizeToHumanRead(bytes, si=true, dp=2) {
// Initialize variables.
var threshold = si ? 1000 : 1024;
var units = si
? ['kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
: ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'];
var unit = -1;
// Check if minimum threshold is reached.
if (Math.abs(bytes) < threshold)
return bytes + ' Bytes';
const r = 10**dp;
do {
bytes /= threshold;
++unit;
} while (Math.round(Math.abs(bytes) * r) / r >= threshold && unit < units.length - 1);
return bytes.toFixed(dp) + ' ' + units[unit];
}
// Rounds the given number to two decimals.
function roundToTwoDecimals(number) {
return Math.round(number * 100) / 100;
}
// Returns human readable time from the given seconds.
function secondsToTime(numSeconds) {
// Initialize variables.
var days = 0;
var hours = 0;
var minutes = 0;
var seconds = 0;
// Calculate the time values.
if (numSeconds < 60)
seconds = numSeconds;
else if (numSeconds < (60 * 60)) {
minutes = Math.floor(numSeconds / 60);
seconds = numSeconds % 60;
} else if (numSeconds < (60 * 60 * 24)) {
hours = Math.floor(numSeconds / (60 * 60));
minutes = Math.floor((numSeconds % (60 * 60)) / 60);
seconds = numSeconds % 60;
} else {
days = Math.floor(numSeconds / (60 * 60 * 24));
hours = Math.floor((numSeconds % (60 * 60 * 24)) / (60 * 60));
minutes = Math.floor((numSeconds % (60 * 60)) / 60);
seconds = numSeconds % 60;
}
// Build time string.
var time = "";
var numFields = 0;
if (days > 0) {
time += days + " day";
if (days > 1)
time += "s";
time += " ";
numFields += 1;
}
if (hours > 0) {
time += hours + " hour";
if (hours > 1)
time += "s";
time += " ";
numFields += 1;
}
if (minutes > 0 && numFields < 2) {
time += minutes + " minute";
if (minutes > 1)
time += "s";
time += " ";
numFields += 1;
}
if ((seconds > 0 && numFields < 2) || time == "") {
time += seconds + " second";
if (seconds > 1)
time += "s";
}
// Return the time string.
return time;
}
// Returns on/off status from the given integer.
function onOffStatus(status) {
return status == 1 ? VALUE_ON : VALUE_OFF;
}
// Updates the given field ID with the given value.
function updateFieldValue(fieldID, value) {
var fieldElement = document.getElementById(fieldID);
if (fieldElement != null && fieldElement != "undefined")
fieldElement.innerText = value;
}
// Rounds the given amount of kilo-bytes to giga bytes.
function roundToGigaBytes(kiloBytes) {
return (kiloBytes / (1024 * 1024)).toFixed(2);
}
// Returns whether the dashboard page is showing or not.
function isDashboardShowing() {
return window.location.pathname.indexOf("dashboard") > -1;
}
// Returns whether the management page is showing or not.
function isManagementShowing() {
return window.location.pathname.indexOf("management") > -1;
}
// Returns whether the history page is showing or not.
function isHistoryShowing() {
return window.location.pathname.indexOf("history") > -1;
}
// Returns the device ID.
function getDeviceID() {
return new URLSearchParams(window.location.search).get(ID_DEVICE_ID);
}
// Returns the device name.
function getDeviceName() {
return new URLSearchParams(window.location.search).get(ID_DEVICE_NAME);
}

View File

@ -0,0 +1,392 @@
/*
* Copyright 2022, Digi International Inc.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
// Constants.
const CONSOLE_CURSOR_BLINK = true;
const CONSOLE_NUM_ROWS = 30;
const CONSOLE_SCROLLBACK = 1000;
const CONSOLE_TAB_STOP_WIDTH = 8;
const CONSOLE_MAX_SEND_COMMANDS = 5;
const CONSOLE_SEND_COMMANDS_DELAY = 150;
const ID_CONSOLE_CLOSE_BUTTON = "console_close_button";
const ID_CONSOLE_CONTAINER = "console_container";
const ID_CONSOLE_ERROR_RECONNECT = "console_error_reconnect";
const ID_CONSOLE_ERROR_TEXT = "console_error_text";
const ID_CONSOLE_HEADER = "console_header";
const ID_CONSOLE_HOVER_BACKGROUND = "console_hover_background";
const ID_CONSOLE_LOADING = "console_loading";
const ID_CONSOLE_PANEL = "console_panel";
const ID_CONSOLE_RECONNECT_BUTTON = "console_reconnect_button";
const ID_CONSOLE_VIEWPORT = "xterm-viewport";
const CLI_MESSAGE_TYPE_DATA = "data";
const CLI_MESSAGE_TYPE_ERROR = "error";
const CLI_MESSAGE_TYPE_START = "start";
const CLI_MESSAGE_TYPE_TERMINATE = "terminate";
const ERROR_SESSION_CLOSED_REMOTELY = "Session closed from the remote end";
const ERROR_SESSION_CLOSING = "Previous console session is closing, please wait a moment...";
// Variables.
var term;
var cliSessionID;
var cliSocket;
var cliSessionTerminating = false;
var fitAddon;
var commandsToSend = [];
var cliTerminateFlagTimer = null;
var consoleResizeObserver = null;
// Opens the console.
function openConsole() {
// Check if console is showing.
if (isConsoleShowing())
return;
// Check if previous session is terminating.
if (cliSessionTerminating) {
toastr.info(ERROR_SESSION_CLOSING);
return;
}
// Initialize variables.
var consoleDiv = document.getElementById(ID_CONSOLE);
// Remove any residual terminals.
while (consoleDiv.firstChild)
consoleDiv.removeChild(consoleDiv.lastChild);
// Create the terminal instance.
term = new Terminal({
cursorBlink: CONSOLE_CURSOR_BLINK,
scrollback: CONSOLE_SCROLLBACK,
tabStopWidth: CONSOLE_TAB_STOP_WIDTH,
rows: CONSOLE_NUM_ROWS
});
// Configure terminal input data event.
term.onData( (data) => {
sendCLIData(data);
});
// Load Fit addon.
fitAddon = new FitAddon.FitAddon();
term.loadAddon(fitAddon);
// Attach the terminal to the div.
term.open(consoleDiv);
// Setup resize observer.
if (consoleResizeObserver == null || consoleResizeObserver == "undefined") {
consoleResizeObserver = new ResizeObserver((entries) => {
adjustConsoleSize();
})
consoleResizeObserver.observe(document.getElementById(ID_CONSOLE_CONTAINER));
}
// Show the console.
var consolePanel = document.getElementById(ID_CONSOLE_PANEL);
consolePanel.style.visibility = "visible";
consolePanel.style.display = "flex";
// Adjust console size after some time to give time to the terminal to load.
window.setTimeout(function () {
adjustConsoleSize();
}, 100);
adjustConsoleSize();
// Initialize the CLI session.
initCLISession();
}
// Adjusts the console size.
function adjustConsoleSize() {
// Sanity checks.
if (!isConsoleShowing())
return;
// Initialize variables.
var consoleContainer = document.getElementById(ID_CONSOLE_CONTAINER);
var consoleViewPort = document.getElementsByClassName(ID_CONSOLE_VIEWPORT)[0];
var consoleHeader = document.getElementById(ID_CONSOLE_HEADER);
var consoleHoverBackground = document.getElementById(ID_CONSOLE_HOVER_BACKGROUND);
// Adjust terminal size.
if (fitAddon != null && fitAddon != "undefined")
fitAddon.fit();
// Obtain dimensions.
var consoleHeight = consoleViewPort.clientHeight;
var headerHeight = consoleHeader.clientHeight;
// Set size values.
consoleContainer.style.height = (consoleHeight + headerHeight).toString() + "px";
consoleHoverBackground.style.height = (consoleContainer.clientHeight - headerHeight).toString() + "px";
consoleViewPort.style.width = "initial";
}
// Returns whether the console window is open or not.
function isConsoleShowing() {
// Sanity checks.
if (!isDashboardShowing())
return false;
// Initialize variables.
var consolePanel = document.getElementById(ID_CONSOLE_PANEL);
// Return whether the console is showing or not.
return consolePanel.style.visibility == "visible";
}
// Shows/hides the console loading panel.
function showConsoleLoading(visible) {
// Initialize variables.
var consoleHoverBackground = document.getElementById(ID_CONSOLE_HOVER_BACKGROUND);
var consoleLoading = document.getElementById(ID_CONSOLE_LOADING);
// Show/hide the loading panel.
if (visible && isConsoleShowing()) {
consoleHoverBackground.style.visibility = "visible";
consoleLoading.style.visibility = "visible";
} else {
consoleHoverBackground.style.visibility = "hidden";
consoleLoading.style.visibility = "hidden";
}
}
// Shows/hides the console error with reconnect panel.
function showConsoleErrorReconnect(visible, error) {
// Initialize variables.
var consoleHoverBackground = document.getElementById(ID_CONSOLE_HOVER_BACKGROUND);
var consoleErrorReconnect = document.getElementById(ID_CONSOLE_ERROR_RECONNECT);
var consoleErrorText = document.getElementById(ID_CONSOLE_ERROR_TEXT);
var reconnectButton = document.getElementById(ID_CONSOLE_RECONNECT_BUTTON);
var closeButton = document.getElementById(ID_CONSOLE_CLOSE_BUTTON);
// Show/hide the error panel.
if (visible && isConsoleShowing()) {
consoleHoverBackground.style.visibility = "visible";
consoleErrorReconnect.style.visibility = "visible";
reconnectButton.style.visibility = "visible";
closeButton.style.visibility = "visible";
if (error == null)
error = ERROR_UNKNOWN_ERROR;
consoleErrorText.innerText = error;
} else {
consoleHoverBackground.style.visibility = "hidden";
consoleErrorReconnect.style.visibility = "hidden";
reconnectButton.style.visibility = "hidden";
closeButton.style.visibility = "hidden";
}
}
// Initializes a CLI session.
function initCLISession() {
// Hide error with reconnect panel.
showConsoleErrorReconnect(false);
// Clear the terminal.
term.clear();
// Show loading panel.
showConsoleLoading(true);
$.post(
"../ajax/cli_init_session",
JSON.stringify({
"device_id": getDeviceID()
}),
function(data) {
// Process only if the console is showing.
if (!isConsoleShowing())
return;
// Process answer.
processInitCLISessionResponse(data);
}
).fail(function(response) {
// Process only if the console is showing.
if (!isConsoleShowing())
return;
// Process error.
var error = processAjaxErrorResponse(response);
// Hide the loading status.
showConsoleLoading(false);
// Show error with reconnect panel.
showConsoleErrorReconnect(true, error);
});
}
// Processes the init CLI session response.
function processInitCLISessionResponse(response) {
// Check if there was any error in the request.
if (checkErrorResponse(response, false)) {
// Hide the loading status.
showConsoleLoading(false);
// Show error with reconnect panel.
showConsoleErrorReconnect(true, error);
} else {
// Store session ID.
cliSessionID = response[ID_SESSION_ID];
// Register the TCP monitor.
subscribeCLISession(cliSessionID);
}
}
// Sends the given CLI data.
function sendCLIData(data) {
// Check if CLI session exists.
if (cliSessionID == null)
return;
// Add the command to the buffer.
commandsToSend.push(data);
// If the send timer is scheduled and there is enough data to send,
// return to let the timer to complete.
if (sendTimerScheduled && commandsToSend.length > CONSOLE_MAX_SEND_COMMANDS)
return;
if (sendTimer != null && sendTimer != "undefined") {
clearTimeout(sendTimer);
sendTimer = null;
}
// Schedule the timer.
sendTimer = setTimeout(function() {
// Clear timer flag.
sendTimerScheduled = false;
// Build data.
var dataToSend = btoa(commandsToSend.join(""));
commandsToSend = [];
$.post(
"../ajax/cli_data",
JSON.stringify({
"device_id": getDeviceID(),
"session_id": cliSessionID,
"data": dataToSend
}),
function(data) {
// Process only if the console is showing.
if (!isConsoleShowing())
return;
// Process answer.
processCLISendDataResponse(data);
}
).fail(function(response) {
// Process only if the console is showing.
if (!isConsoleShowing())
return;
// Process error.
processAjaxErrorResponse(response);
});
}, CONSOLE_SEND_COMMANDS_DELAY);
// Set timer flag.
sendTimerScheduled = true;
}
// Processes the send CLI data response.
function processCLISendDataResponse(response) {
// Check if there was any error in the request.
checkErrorResponse(response, false);
}
// Closes the console.
function closeConsole() {
// Check if console is showing.
if (!isConsoleShowing())
return;
// Hide the loading panel.
showConsoleLoading(false);
// Hide the error reconnect panel.
showConsoleErrorReconnect(false);
// Terminate the CLI session.
terminateCLIsession();
// Hide the console.
var consolePanel = document.getElementById(ID_CONSOLE_PANEL);
consolePanel.style.visibility = "collapse";
consolePanel.style.display = "none";
}
// Terminates the CLI session.
function terminateCLIsession() {
// Check if CLI session exists.
if (cliSessionID == null)
return;
// Flag session terminating.
cliSessionTerminating = true;
cliTerminateFlagTimer = window.setTimeout(function () {
cliSessionTerminating = false;
}, 30000); // In the case the terminate request hangs, set a timeout to manually remove the flag.
// Send request to terminate CLI session.
$.post(
"../ajax/cli_terminate_session",
JSON.stringify({
"device_id": getDeviceID(),
"session_id": cliSessionID
}),
function(data) {
// Process only if the console is showing.
if (!isConsoleShowing())
return;
// Process answer.
processTerminateCLISessionResponse(data);
}
).fail(function(response) {
// Un-flag session terminating.
cliSessionTerminating = false;
window.clearTimeout(cliTerminateFlagTimer);
// Process only if the console is showing.
if (!isConsoleShowing())
return;
// Process error.
processAjaxErrorResponse(response);
});
// Clear CLI session ID.
cliSessionID = null;
}
// Processes the terminate CLI session response.
function processTerminateCLISessionResponse(response) {
// Check if there was any error in the request.
if (checkErrorResponse(response, false)) {
// Un-flag session terminating.
cliSessionTerminating = false;
window.clearTimeout(cliTerminateFlagTimer);
}
}
// Subscribes to any CLI session change.
function subscribeCLISession(sessionID) {
// Create the web socket.
var socketPrefix = window.location.protocol == "https:" ? "wss" : "ws";
cliSocket = new WebSocket(socketPrefix + "://" + window.location.host + "/ws/cli/" + device.getDeviceID() + "/" + sessionID);
// Define the callback to be notified when data is received in the web socket.
cliSocket.onmessage = function(e) {
if (isDashboardShowing() && term != null && term != "undefined") {
var event = JSON.parse(e.data);
var type = event[ID_TYPE];
switch (type) {
case CLI_MESSAGE_TYPE_DATA:
var data = event[ID_DATA];
var decodedData = atob(data);
if (isConsoleShowing())
term.write(decodedData);
break;
case CLI_MESSAGE_TYPE_TERMINATE:
case CLI_MESSAGE_TYPE_ERROR:
cliSessionID = null;
if (cliSocket != null && cliSocket != "undefined")
cliSocket.close();
// Hide the loading status.
showConsoleLoading(false);
// Check specific type.
var error = null;
if (type == CLI_MESSAGE_TYPE_TERMINATE && isConsoleShowing())
error = ERROR_SESSION_CLOSED_REMOTELY;
else if (type == CLI_MESSAGE_TYPE_ERROR)
error = event[ID_ERROR];
if (isConsoleShowing())
showConsoleErrorReconnect(true, error);
if (error != null && (type == CLI_MESSAGE_TYPE_ERROR ||
(type == CLI_MESSAGE_TYPE_TERMINATE && isConsoleShowing())))
toastr.error(error);
// Un-flag session terminating.
cliSessionTerminating = false;
window.clearTimeout(cliTerminateFlagTimer);
break;
case CLI_MESSAGE_TYPE_START:
// Hide the loading status.
showConsoleLoading(false);
break;
}
}
};
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,202 @@
/*
* Copyright 2022, Digi International Inc.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
// Constants.
const ID_DATA_USAGE_BUTTON = "data_usage_button";
const ID_DATA_USAGE_CURRENT_DEVICE = "data_usage_current_device";
const ID_DATA_USAGE_GRAPHIC_WEB = "data_usage_graphic_web";
const ID_DATA_USAGE_GRAPHIC_DEVICES = "data_usage_graphic_devices";
const ID_DATA_USAGE_ICON = "data_usage_icon";
const ID_DATA_USAGE_LOADING = "data_usage_loading";
const ID_DATA_USAGE_PANEL = "data_usage_panel";
// Returns whether the data usage panel is open or not.
function isDataUsageShowing() {
// Initialize variables.
var dataUsagePanel = document.getElementById(ID_DATA_USAGE_PANEL);
// Return visibility.
return dataUsagePanel.style.display != "none";
}
// Toggles the data usage panel visibility.
function toggleDataUsagePanel() {
// Initialize variables.
var dataUsageIcon = document.getElementById(ID_DATA_USAGE_ICON);
var dataUsageButton = document.getElementById(ID_DATA_USAGE_BUTTON);
// Avoid double clicks.
dataUsageButton.style.pointerEvents = "none";
// Check data usage panel visibility.
if (isDataUsageShowing()) {
$("#" + ID_DATA_USAGE_PANEL).slideUp("fast", function() {
dataUsageIcon.src = "../static/images/data_usage.png";
// Enable hover effect.
$("#" + ID_DATA_USAGE_BUTTON).on({
"mouseover" : function() {
dataUsageIcon.src = "../static/images/data_usage_green.png";
},
"mouseout" : function() {
dataUsageIcon.src = "../static/images/data_usage.png";
}
});
// React to mouse events again.
dataUsageButton.style.pointerEvents = "auto";
// Reset fields.
clearDataUsageFields();
});
} else {
$("#" + ID_DATA_USAGE_PANEL).slideDown("fast", function() {
dataUsageIcon.src = "../static/images/data_usage_green.png";
// Disable hover effect.
$("#" + ID_DATA_USAGE_BUTTON).on({
"mouseover" : function() {
dataUsageIcon.src = "../static/images/data_usage_green.png";
},
"mouseout" : function() {
dataUsageIcon.src = "../static/images/data_usage_green.png";
}
});
// React to mouse events again.
dataUsageButton.style.pointerEvents = "auto";
// Read data usage.
readDataUsage();
});
}
}
// Reads the DRM account data usage.
function readDataUsage() {
// Sanity checks.
if (!isDataUsageShowing())
return;
// Show the data usage loading panel.
showDataUsageLoading(true);
// Send request to change the LED status.
$.post(
"../ajax/get_data_usage",
function(data) {
// Process only if the panel is showing.
if (!isDataUsageShowing())
return;
// Process answer.
processReadDataUsageResponse(data);
}
).fail(function(response) {
// Process only if the panel is showing.
if (!isDataUsageShowing())
return;
// Process error.
error = processAjaxErrorResponse(response);
// Hide the data usage loading panel.
showDataUsageLoading(true);
});
}
// Processes the read data usage response.
function processReadDataUsageResponse(response) {
// Hide the data usage loading panel.
showDataUsageLoading(false);
// Check if there was any error in the request.
if (!checkErrorResponse(response, false)) {
// Update the data usage values.
updateDataUsageValues(response);
}
}
// Updates the data usage values.
function updateDataUsageValues(response) {
// Sanity checks.
if (!isDataUsageShowing())
return;
// Initialize variables.
var dataUsageTotal = response[ID_DATA_USAGE_TOTAL];
var dataUsageWeb = response[ID_DATA_USAGE_WEB];
var dataUsageDevices = response[ID_DATA_USAGE_DEVICES];
var dataUsageDevicesPercent = 0;
var dataUsageWebPercent = 0;
var dataUsageCurrentDevice = 0;
var graphicDevicesElement = document.getElementById(ID_DATA_USAGE_GRAPHIC_DEVICES);
var graphicWebElement = document.getElementById(ID_DATA_USAGE_GRAPHIC_WEB);
// Calculate percent for data devices.
if (dataUsageTotal > 0) {
dataUsageDevicesPercent = Math.round(dataUsageDevices * 100 / dataUsageTotal);
dataUsageWebPercent = Math.round(dataUsageWeb * 100 / dataUsageTotal);
}
// Calculate values for totals.
dataUsageDevices = sizeToHumanRead(dataUsageDevices * 1000 * 1000); // This usage is given in MB.
dataUsageWeb = sizeToHumanRead(dataUsageWeb * 1000 * 1000); // This usage is given in MB.
// Retrieve the data usage for the current device.
for (var device in response[ID_DEVICES]) {
if (response[ID_DEVICES][device][ID_DEVICE_ID].toLowerCase() == getDeviceID().toLowerCase()) {
dataUsageCurrentDevice = response[ID_DEVICES][device][ID_USAGE];
break;
}
}
// Set percentage size of graphics.
graphicDevicesElement.style.width = dataUsageDevicesPercent + "%";
graphicWebElement.style.width = dataUsageWebPercent + "%";
// Set graphics tooltips.
graphicDevicesElement.setAttribute("data-original-title", "Total data usage by devices: " + dataUsageDevices + " (" + dataUsageDevicesPercent + "%)");
graphicWebElement.setAttribute("data-original-title", "Total data usage by web APIs: " + dataUsageWeb + " (" + dataUsageWebPercent + "%)");
// Update the data usage values.
updateFieldValue(ID_DATA_USAGE_TOTAL, sizeToHumanRead(dataUsageTotal * 1000 * 1000)); // This usage is given in MB.
updateFieldValue(ID_DATA_USAGE_DEVICES, dataUsageDevices);
updateFieldValue(ID_DATA_USAGE_CURRENT_DEVICE, sizeToHumanRead(dataUsageCurrentDevice * 1000)); // This usage is given in KB.
updateFieldValue(ID_DATA_USAGE_WEB, dataUsageWeb);
updateFieldValue(ID_DATA_USAGE_WEB_SERVICES, sizeToHumanRead(response[ID_DATA_USAGE_WEB_SERVICES] * 1000)); // This usage is given in KB.
updateFieldValue(ID_DATA_USAGE_MONITORS, sizeToHumanRead(response[ID_DATA_USAGE_MONITORS] * 1000)); // This usage is given in KB.
}
// Shows/hides the data usage loading panel.
function showDataUsageLoading(visible) {
// Sanity checks.
if (!isDataUsageShowing())
return;
// Initialize variables.
var dataUsageLoading = document.getElementById(ID_DATA_USAGE_LOADING);
// Show the data usage loading panel.
if (visible)
dataUsageLoading.style.display = "block";
else
dataUsageLoading.style.display = "none";
}
// Clears all data usage fields.
function clearDataUsageFields() {
// Initialize variables.
var graphicDevicesElement = document.getElementById(ID_DATA_USAGE_GRAPHIC_DEVICES);
var graphicWebElement = document.getElementById(ID_DATA_USAGE_GRAPHIC_WEB);
// Clear all data usage fields.
updateFieldValue(ID_DATA_USAGE_TOTAL, "");
updateFieldValue(ID_DATA_USAGE_DEVICES, "");
updateFieldValue(ID_DATA_USAGE_CURRENT_DEVICE, "");
updateFieldValue(ID_DATA_USAGE_WEB, "");
updateFieldValue(ID_DATA_USAGE_WEB_SERVICES, "");
updateFieldValue(ID_DATA_USAGE_MONITORS, "");
// Reset graphic sizes.
graphicDevicesElement.style.width = "0%";
graphicWebElement.style.width = "0%";
}
// Refreshes the usage data.
function refreshUsageData() {
// Sanity checks.
if (!isDataUsageShowing())
return;
// Clear all data usage fields.
clearDataUsageFields();
// Read data usage.
readDataUsage();
}

View File

@ -0,0 +1,805 @@
/*
* Copyright 2022, Digi International Inc.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
// Constants.
const CLASS_ADD_DEVICE_DIALOG_BUTTON_DISABLED = "add-device-button-disabled";
const CLASS_ADD_DEVICE_DIALOG_INPUT_ERROR = "add-device-input-error";
const CLASS_DEVICE_SELECTED = "devices-list-entry-selected";
const ERROR_DEVICE_ID_EMPTY = "A Device ID or MAC Address must be provided.";
const ERROR_DEVICE_ID_INVALID = "A device id format is 00000000-00000000-00000000-00000000, while a mac address format is 00:00:00:00:00:00 (optional colon separators)";
const ERROR_INVALID_PROVISION_VALUE = "Provided provision value was not valid.";
const ID_ADD_DEVICE_DIALOG = "add_device_dialog";
const ID_ADD_DEVICE_DIALOG_BUTTON = "add_device_button";
const ID_ADD_DEVICE_DIALOG_ERROR = "add_device_error";
const ID_ADD_DEVICE_DIALOG_INPUT = "add_device_input";
const ID_CONTINUE_BUTTON = "continue-button";
const ID_DEVICES_LIST = "devices-list";
const ID_REFRESH_BUTTON = "refresh-button";
const MESSAGE_LOADING_DEVICES = "Loading devices..."
const MESSAGE_REGISTERING_DEVICE = "Registering device..."
const PROVISION_TYPE_ID = "id";
const PROVISION_TYPE_MAC = "mac";
const PROVISION_TYPE_IMEI = "imei";
const REGEX_DEVICE_ID = "^(?:[a-fA-F0-9]{8}-){3}[a-fA-F0-9]{8}$";
const REGEX_DEVICE_MAC = "^(?:[a-fA-F0-9]{2}:?){5}[a-fA-F0-9]{2}$";
const REGEX_DEVICE_IMEI = "^[0-9]{15}$";
const TEMPLATE_COMPONENT_DATA = "" +
"{" +
" \"" + ID_VISIBLE + "\" : {0}," +
" \"" + ID_HAS_PANEL + "\" : {1}," +
" \"" + ID_HAS_ARROW + "\" : {2}," +
" \"" + ID_PANEL_ALWAYS_VISIBLE + "\" : {3}," +
" \"" + ID_PANEL_ORIENTATION + "\" : \"{4}\"," +
" \"" + ID_PANEL_HORIZONTAL_MARGIN + "\" : {5}," +
" \"" + ID_PANEL_VERTICAL_MARGIN + "\" : {6}," +
" \"" + ID_ARROW_MARGIN + "\" : {7}," +
" \"" + ID_AREA_TOP_MARGIN + "\" : {8}," +
" \"" + ID_AREA_LEFT_MARGIN + "\" : {9}," +
" \"" + ID_AREA_WIDTH + "\" : {10}," +
" \"" + ID_AREA_HEIGHT + "\" : {11}" +
"}"
const TEMPLATE_DEVICE_LIST_ENTRY = "" +
"<div id='@@ID@@' onclick='selectDevice(\"@@ID@@\")' class='devices-list-entry'>" +
" <table>" +
" <thead>" +
" <tr>" +
" <td rowspan='2'><img class='device-list-entry-status' src='/static/images/@@STATUS_IMAGE@@'></td>" +
" <td><span class='device-list-entry-name'>@@TYPE@@</span></td>" +
" </tr>" +
" <tr>" +
" <td><span class='device-list-entry-id'>@@ID@@</span></td>" +
" <tr>" +
" </thead>" +
" </table>" +
"</div>";
// Variables.
var devices = [];
// Lists DRM devices.
function listDevices() {
// Disable the refresh button.
document.getElementById(ID_REFRESH_BUTTON).disabled = true;
// Disable the continue button.
document.getElementById(ID_CONTINUE_BUTTON).disabled = true;
// Clear the devices list
clearDevices();
// Hide info dialog.
showInfoPopup(false);
// Show loading dialog.
showLoadingPopup(true, MESSAGE_LOADING_DEVICES);
// Send the request.
$.post(
"../ajax/get_devices",
function(data) {
// Hide the loading panel.
showLoadingPopup(false);
// Process answer.
processListDevicesAnswer(data);
// Enable the refresh button.
document.getElementById(ID_REFRESH_BUTTON).disabled = false;
// Update continue button.
updateContinueButton();
}
).fail(function(response) {
// Hide the loading panel.
showLoadingPopup(false);
// Process error.
processAjaxErrorResponse(response);
// Enable the refresh button.
document.getElementById(ID_REFRESH_BUTTON).disabled = false;
});
}
// Processes the answer of the list devices request.
function processListDevicesAnswer(response) {
// Check if there was any error in the request.
if (checkErrorResponse(response, false)) {
// Do not continue.
return;
}
// Get the devices from the JSON response.
let readDevices = response[ID_DEVICES];
// Check if the list of devices contains any device.
if (readDevices == null || readDevices.length == 0)
return;
// Process devices.
for (let device of readDevices) {
// Add a new device entry to the list of devices.
devices.push(device);
let deviceDivContent = TEMPLATE_DEVICE_LIST_ENTRY;
deviceDivContent = deviceDivContent.replace(/@@ID@@/g, device[ID_ID]);
deviceDivContent = deviceDivContent.replace(/@@TYPE@@/g, device[ID_TYPE]);
if (device[ID_ONLINE] == true)
deviceDivContent = deviceDivContent.replace(/@@STATUS_IMAGE@@/g, IMAGE_ONLINE);
else
deviceDivContent = deviceDivContent.replace(/@@STATUS_IMAGE@@/g, IMAGE_OFFLINE);
let deviceDiv = document.createElement("div");
deviceDiv.innerHTML = deviceDivContent;
$("#" + ID_DEVICES_LIST).append(deviceDiv);
}
}
// Clears the list of devices.
function clearDevices() {
unselectDevices();
devices = [];
$("#" + ID_DEVICES_LIST).html("");
}
// Selects the given device
function selectDevice(deviceID) {
// Unselect all devices.
unselectDevices();
// Set selected style to the selected device div.
if (document.getElementById(deviceID) != null)
document.getElementById(deviceID).classList.add(CLASS_DEVICE_SELECTED);
// Save selected device.
for (i = 0; i < devices.length; i++) {
device = devices[i];
if (device[ID_ID] == deviceID)
selectedDevice = device;
}
// Configure continue button.
updateContinueButton();
}
// Unselects all the devices.
function unselectDevices() {
// Clear selected style from all device divs.
for (i = 0; i < devices.length; i++) {
device = devices[i];
if (document.getElementById(device[ID_ID]) != null)
document.getElementById(device[ID_ID]).classList.remove(CLASS_DEVICE_SELECTED);
}
// Remove selected device.
selectedDevice = null;
// Configure continue button.
updateContinueButton();
}
// Updates the continue button state.
function updateContinueButton() {
// Initialize variables.
var continueButton = document.getElementById(ID_CONTINUE_BUTTON);
// Check if there is any selected device.
if (selectedDevice != null) {
continueButton.disabled = false;
continueButton.onclick = function() {openSelectedDevice();};
} else {
continueButton.disabled = true;
continueButton.onclick = function() { };
}
}
// Opens the selected device
function openSelectedDevice() {
// Avoid double click.
document.getElementById(ID_CONTINUE_BUTTON).disabled = true;
// Show loading dialog.
showLoadingPopup(true);
// Navigate to device dashboard page.
window.open("../dashboard/?device_id=" + selectedDevice[ID_ID] + "&device_name=" + selectedDevice[ID_TYPE], "_self");
}
// Opens the "Add device" dialog.
function openAddDeviceDialog() {
// Initialize variables.
var addDeviceInputElement = document.getElementById(ID_ADD_DEVICE_DIALOG_INPUT);
var addDeviceButtonElement = document.getElementById(ID_ADD_DEVICE_DIALOG_BUTTON);
var addDeviceErrorElement = document.getElementById(ID_ADD_DEVICE_DIALOG_ERROR);
// Reset dialog state.
addDeviceInputElement.value = "";
addDeviceErrorElement.innerHTML = "&nbsp;";
addDeviceErrorElement.style.visibility = "hidden";
if (!addDeviceButtonElement.classList.contains(CLASS_ADD_DEVICE_DIALOG_BUTTON_DISABLED))
addDeviceButtonElement.classList.add(CLASS_ADD_DEVICE_DIALOG_BUTTON_DISABLED);
if (addDeviceInputElement.classList.contains(CLASS_ADD_DEVICE_DIALOG_INPUT_ERROR))
addDeviceInputElement.classList.remove(CLASS_ADD_DEVICE_DIALOG_INPUT_ERROR);
// Show panel.
showAddDeviceDialog(true);
}
// Closes the "Add device" dialog.
function closeAddDeviceDialog() {
showAddDeviceDialog(false);
}
// Shows/hides the "Add device" dialog.
function showAddDeviceDialog(visible) {
// Initialize variables.
var addDeviceDialogElement = document.getElementById(ID_ADD_DEVICE_DIALOG);
var addDeviceErrorElement = document.getElementById(ID_ADD_DEVICE_DIALOG_ERROR);
// Apply visible state.
if (visible)
addDeviceDialogElement.style.visibility = "visible";
else {
addDeviceDialogElement.style.visibility = "hidden";
addDeviceErrorElement.style.visibility = "hidden";
}
}
// Validates the device ID.
function validateDeviceID(deviceID) {
// Initialize variables.
var addDeviceInputElement = document.getElementById(ID_ADD_DEVICE_DIALOG_INPUT);
var addDeviceButtonElement = document.getElementById(ID_ADD_DEVICE_DIALOG_BUTTON);
var addDeviceErrorElement = document.getElementById(ID_ADD_DEVICE_DIALOG_ERROR);
var isValid = true;
var error = ERROR_DEVICE_ID_INVALID;
// Check if the device ID is valid.
if (deviceID == null || deviceID == "") {
isValid = false;
error = ERROR_DEVICE_ID_EMPTY;
} else
isValid = deviceID.match(REGEX_DEVICE_ID) || deviceID.match(REGEX_DEVICE_MAC) || deviceID.match(REGEX_DEVICE_IMEI);
// Update controls.
if (isValid) {
if (addDeviceButtonElement.classList.contains(CLASS_ADD_DEVICE_DIALOG_BUTTON_DISABLED))
addDeviceButtonElement.classList.remove(CLASS_ADD_DEVICE_DIALOG_BUTTON_DISABLED);
if (addDeviceInputElement.classList.contains(CLASS_ADD_DEVICE_DIALOG_INPUT_ERROR))
addDeviceInputElement.classList.remove(CLASS_ADD_DEVICE_DIALOG_INPUT_ERROR);
addDeviceErrorElement.innerHTML = "&nbsp;";
addDeviceErrorElement.style.visibility = "hidden";
} else {
if (!addDeviceButtonElement.classList.contains(CLASS_ADD_DEVICE_DIALOG_BUTTON_DISABLED))
addDeviceButtonElement.classList.add(CLASS_ADD_DEVICE_DIALOG_BUTTON_DISABLED);
if (!addDeviceInputElement.classList.contains(CLASS_ADD_DEVICE_DIALOG_INPUT_ERROR))
addDeviceInputElement.classList.add(CLASS_ADD_DEVICE_DIALOG_INPUT_ERROR);
addDeviceErrorElement.innerHTML = error;
addDeviceErrorElement.style.visibility = "visible";
}
}
// Handles what happens when the "Register device" button is pressed.
function onRegisterDevice() {
// Initialize variables.
var addDeviceInputElement = document.getElementById(ID_ADD_DEVICE_DIALOG_INPUT);
var provisionValue = addDeviceInputElement.value;
var provisionType = "";
// Determine provision type.
if (provisionValue.match(REGEX_DEVICE_ID))
provisionType = PROVISION_TYPE_ID;
else if (provisionValue.match(REGEX_DEVICE_MAC))
provisionType = PROVISION_TYPE_MAC;
else if (provisionValue.match(REGEX_DEVICE_IMEI))
provisionType = PROVISION_TYPE_IMEI;
else {
toastr.error(ERROR_INVALID_PROVISION_VALUE);
return;
}
// Register the device.
registerDevice(provisionValue, provisionType);
}
// Registers the given device ID.
function registerDevice(provisionValue, provisionType) {
// Disable the refresh button.
document.getElementById(ID_REFRESH_BUTTON).disabled = true;
// Disable the continue button.
document.getElementById(ID_CONTINUE_BUTTON).disabled = true;
// Close the add device dialog.
closeAddDeviceDialog();
// Hide info dialog.
showInfoPopup(false);
// Show loading dialog.
showLoadingPopup(true, MESSAGE_REGISTERING_DEVICE);
// Send the request.
$.post(
"../ajax/register_device",
JSON.stringify({
"provision_value": provisionValue,
"provision_type": provisionType
}),
function(data) {
// Hide the loading panel.
showLoadingPopup(false);
// Process answer.
processRegisterDeviceAnswer(data);
}
).fail(function(response) {
// Hide the loading panel.
showLoadingPopup(false);
// Process error.
processAjaxErrorResponse(response);
// Enable the refresh button.
document.getElementById(ID_REFRESH_BUTTON).disabled = false;
// Refresh the continue button.
updateContinueButton();
});
}
// Processes the answer of the register device request.
function processRegisterDeviceAnswer(answer) {
// Check if there was any error in the request.
if (checkErrorResponse(answer, false)) {
// Enable the refresh button.
document.getElementById(ID_REFRESH_BUTTON).disabled = false;
// Refresh the continue button.
updateContinueButton();
} else {
// Update the device list.
listDevices();
}
}
// Class that represents a ConnectCore device.
class ConnectCoreDevice {
// Variables
// Board image.
BOARD_IMAGE;
BOARD_IMAGE_SCALE;
// CPU panel.
CPU_COMPONENT_VISIBLE = false;
CPU_COMPONENT_HAS_PANEL = false;
CPU_COMPONENT_HAS_ARROW = false;
CPU_COMPONENT_PANEL_ALWAYS_VISIBLE = false;
CPU_COMPONENT_PANEL_ORIENTATION = VALUE_TOP;
CPU_COMPONENT_PANEL_HORIZONTAL_PERCENT = 0;
CPU_COMPONENT_PANEL_VERTICAL_PERCENT = 0;
CPU_COMPONENT_ARROW_PERCENT = 0;
CPU_COMPONENT_AREA_TOP_PERCENT = 0;
CPU_COMPONENT_AREA_LEFT_PERCENT = 0;
CPU_COMPONENT_AREA_WIDTH_PERCENT = 0;
CPU_COMPONENT_AREA_HEIGHT_PERCENT = 0;
// Memory panel.
MEMORY_COMPONENT_VISIBLE = false;
MEMORY_COMPONENT_HAS_PANEL = false;
MEMORY_COMPONENT_HAS_ARROW = false;
MEMORY_COMPONENT_PANEL_ALWAYS_VISIBLE = false;
MEMORY_COMPONENT_PANEL_ORIENTATION = VALUE_TOP;
MEMORY_COMPONENT_PANEL_HORIZONTAL_PERCENT = 0;
MEMORY_COMPONENT_PANEL_VERTICAL_PERCENT = 0;
MEMORY_COMPONENT_ARROW_PERCENT = 0;
MEMORY_COMPONENT_AREA_TOP_PERCENT = 0;
MEMORY_COMPONENT_AREA_LEFT_PERCENT = 0;
MEMORY_COMPONENT_AREA_WIDTH_PERCENT = 0;
MEMORY_COMPONENT_AREA_HEIGHT_PERCENT = 0;
// WiFi/BT panel.
WIFI_BT_COMPONENT_VISIBLE = false;
WIFI_BT_COMPONENT_HAS_PANEL = false;
WIFI_BT_COMPONENT_HAS_ARROW = false;
WIFI_BT_COMPONENT_PANEL_ALWAYS_VISIBLE = false;
WIFI_BT_COMPONENT_PANEL_ORIENTATION = VALUE_TOP;
WIFI_BT_COMPONENT_PANEL_HORIZONTAL_PERCENT = 0;
WIFI_BT_COMPONENT_PANEL_VERTICAL_PERCENT = 0;
WIFI_BT_COMPONENT_ARROW_PERCENT = 0;
WIFI_BT_COMPONENT_AREA_TOP_PERCENT = 0;
WIFI_BT_COMPONENT_AREA_LEFT_PERCENT = 0;
WIFI_BT_COMPONENT_AREA_WIDTH_PERCENT = 0;
WIFI_BT_COMPONENT_AREA_HEIGHT_PERCENT = 0;
// Ethernet panel.
ETHERNET_COMPONENT_VISIBLE = false;
ETHERNET_COMPONENT_HAS_PANEL = false;
ETHERNET_COMPONENT_HAS_ARROW = false;
ETHERNET_COMPONENT_PANEL_ALWAYS_VISIBLE = false;
ETHERNET_COMPONENT_PANEL_ORIENTATION = VALUE_TOP;
ETHERNET_COMPONENT_PANEL_HORIZONTAL_PERCENT = 0;
ETHERNET_COMPONENT_PANEL_VERTICAL_PERCENT = 0;
ETHERNET_COMPONENT_ARROW_PERCENT = 0;
ETHERNET_COMPONENT_AREA_TOP_PERCENT = 0;
ETHERNET_COMPONENT_AREA_LEFT_PERCENT = 0;
ETHERNET_COMPONENT_AREA_WIDTH_PERCENT = 0;
ETHERNET_COMPONENT_AREA_HEIGHT_PERCENT = 0;
// Console.
CONSOLE_COMPONENT_VISIBLE = false;
CONSOLE_COMPONENT_HAS_PANEL = false;
CONSOLE_COMPONENT_HAS_ARROW = false;
CONSOLE_COMPONENT_PANEL_ALWAYS_VISIBLE = false;
CONSOLE_COMPONENT_PANEL_ORIENTATION = VALUE_TOP;
CONSOLE_COMPONENT_PANEL_HORIZONTAL_PERCENT = 0;
CONSOLE_COMPONENT_PANEL_VERTICAL_PERCENT = 0;
CONSOLE_COMPONENT_ARROW_PERCENT = 0;
CONSOLE_COMPONENT_AREA_TOP_PERCENT = 0;
CONSOLE_COMPONENT_AREA_LEFT_PERCENT = 0;
CONSOLE_COMPONENT_AREA_WIDTH_PERCENT = 0;
CONSOLE_COMPONENT_AREA_HEIGHT_PERCENT = 0;
// Video panel.
VIDEO_COMPONENT_VISIBLE = false;
VIDEO_COMPONENT_HAS_PANEL = false;
VIDEO_COMPONENT_HAS_ARROW = false;
VIDEO_COMPONENT_PANEL_ALWAYS_VISIBLE = false;
VIDEO_COMPONENT_PANEL_ORIENTATION = VALUE_TOP;
VIDEO_COMPONENT_PANEL_HORIZONTAL_PERCENT = 0;
VIDEO_COMPONENT_PANEL_VERTICAL_PERCENT = 0;
VIDEO_COMPONENT_ARROW_PERCENT = 0;
VIDEO_COMPONENT_AREA_TOP_PERCENT = 0;
VIDEO_COMPONENT_AREA_LEFT_PERCENT = 0;
VIDEO_COMPONENT_AREA_WIDTH_PERCENT = 0;
VIDEO_COMPONENT_AREA_HEIGHT_PERCENT = 0;
// Audio panel.
AUDIO_COMPONENT_VISIBLE = false;
AUDIO_COMPONENT_HAS_PANEL = false;
AUDIO_COMPONENT_HAS_ARROW = false;
AUDIO_COMPONENT_PANEL_ALWAYS_VISIBLE = false;
AUDIO_COMPONENT_PANEL_ORIENTATION = VALUE_TOP;
AUDIO_COMPONENT_PANEL_HORIZONTAL_PERCENT = 0;
AUDIO_COMPONENT_PANEL_VERTICAL_PERCENT = 0;
AUDIO_COMPONENT_ARROW_PERCENT = 0;
AUDIO_COMPONENT_AREA_TOP_PERCENT = 0;
AUDIO_COMPONENT_AREA_LEFT_PERCENT = 0;
AUDIO_COMPONENT_AREA_WIDTH_PERCENT = 0;
AUDIO_COMPONENT_AREA_HEIGHT_PERCENT = 0;
// LED panel.
LED_COMPONENT_VISIBLE = false;
LED_COMPONENT_HAS_PANEL = false;
LED_COMPONENT_HAS_ARROW = false;
LED_COMPONENT_PANEL_ALWAYS_VISIBLE = false;
LED_COMPONENT_PANEL_ORIENTATION = VALUE_TOP;
LED_COMPONENT_PANEL_HORIZONTAL_PERCENT = 0;
LED_COMPONENT_PANEL_VERTICAL_PERCENT = 0;
LED_COMPONENT_ARROW_PERCENT = 0;
LED_COMPONENT_AREA_TOP_PERCENT = 0;
LED_COMPONENT_AREA_LEFT_PERCENT = 0;
LED_COMPONENT_AREA_WIDTH_PERCENT = 0;
LED_COMPONENT_AREA_HEIGHT_PERCENT = 0;
// Flash memory panel.
FLASH_MEMORY_COMPONENT_VISIBLE = false;
FLASH_MEMORY_COMPONENT_HAS_PANEL = false;
FLASH_MEMORY_COMPONENT_HAS_ARROW = false;
FLASH_MEMORY_COMPONENT_PANEL_ALWAYS_VISIBLE = false;
FLASH_MEMORY_COMPONENT_PANEL_ORIENTATION = VALUE_TOP;
FLASH_MEMORY_COMPONENT_PANEL_HORIZONTAL_PERCENT = 0;
FLASH_MEMORY_COMPONENT_PANEL_VERTICAL_PERCENT = 0;
FLASH_MEMORY_COMPONENT_ARROW_PERCENT = 0;
FLASH_MEMORY_COMPONENT_AREA_TOP_PERCENT = 0;
FLASH_MEMORY_COMPONENT_AREA_LEFT_PERCENT = 0;
FLASH_MEMORY_COMPONENT_AREA_WIDTH_PERCENT = 0;
FLASH_MEMORY_COMPONENT_AREA_HEIGHT_PERCENT = 0;
// Capabilities
SUPPORTS_VIDEO_BRIGHTNESS;
// Device information.
#deviceType;
#platformName;
#deviceID;
#serialNumber;
#ubootVersion;
#kernelVersion;
#deyVersion;
#moduleVariant;
#boardVariant;
#boardID;
#mcaHWVersion;
#mcaFWVersion;
#ethernetMAC;
#ethernetIP;
#wifiMAC;
#wifiIP;
#bluetoothMAC;
#memoryTotal;
#flashSize;
#videoResolution;
#sampleRate;
#numSamplesUpload;
// Class constructor.
constructor(deviceType, platformName, deviceID, deviceData) {
this.#deviceType = deviceType;
this.#platformName = platformName;
this.#deviceID = deviceID;
this.#initDevice(deviceData);
}
// Initializes the device with the provided data.
#initDevice(deviceData) {
this.#ubootVersion = deviceData[ID_UBOOT_VERSION];
this.#serialNumber = deviceData[ID_SERIAL_NUMBER];
this.#kernelVersion = deviceData[ID_KERNEL_VERSION];
this.#deyVersion = deviceData[ID_DEY_VERSION];
this.#moduleVariant = deviceData[ID_MODULE_VARIANT];
this.#boardVariant = deviceData[ID_BOARD_VARIANT];
this.#boardID = deviceData[ID_BOARD_ID];
this.#mcaHWVersion = deviceData[ID_MCA_HW_VERSION];
this.#mcaFWVersion = deviceData[ID_MCA_FW_VERSION];
this.#ethernetMAC = deviceData[ID_ETHERNET_MAC];
this.#ethernetIP = deviceData[ID_ETHERNET_IP];
this.#wifiMAC = deviceData[ID_WIFI_MAC];
this.#wifiIP = deviceData[ID_WIFI_IP];
this.#bluetoothMAC = deviceData[ID_BLUETOOTH_MAC];
this.#memoryTotal = deviceData[ID_MEMORY_TOTAL];
this.#flashSize = deviceData[ID_FLASH_SIZE];
this.#videoResolution = deviceData[ID_VIDEO_RESOLUTION];
this.#sampleRate = deviceData[ID_SAMPLE_RATE];
this.#numSamplesUpload = deviceData[ID_NUM_SAMPLES_UPLOAD];
}
// Returns the device type.
getDeviceType() {
return this.#deviceType;
}
// Returns the platform name.
getPlatformName() {
return this.#platformName;
}
// Returns the device serial number.
getSerialNumber() {
return this.#serialNumber;
}
// Returns the device ID.
getDeviceID() {
return this.#deviceID;
}
// Returns the board image file name.
getBoardImage() {
return this.BOARD_IMAGE;
}
// Returns the board image scale.
getBoardImageScale() {
return this.BOARD_IMAGE_SCALE;
}
// Returns the device U-Boot version.
getUbootVersion() {
return this.#ubootVersion;
}
// Returns the device Kernel version.
getKernelVersion() {
return this.#kernelVersion;
}
// Returns the device DEY version.
getDEYVersion() {
return this.#deyVersion;
}
// Returns the device module variant.
getModuleVariant() {
return this.#moduleVariant;
}
// Returns the device board variant.
getBoardVariant() {
return this.#boardVariant;
}
// Returns the device board ID.
getBoardID() {
return this.#boardID;
}
// Returns the device MCA hardware version.
getMCAHWVersion() {
return this.#mcaHWVersion;
}
// Returns the device MCA firmware version.
getMCAFWVersion() {
return this.#mcaFWVersion;
}
// Returns the device Ethernet MAC address.
getEthernetMAC() {
return this.#ethernetMAC;
}
// Returns the device Ethernet IP address.
getEthernetIP() {
return this.#ethernetIP;
}
// Returns the device WiFi MAC address.
getWifiMAC() {
return this.#wifiMAC;
}
// Returns the device WiFi IP address.
getWifiIP() {
return this.#wifiIP;
}
// Returns the device Bluetooth MAC address.
getBluetoothMAC() {
return this.#bluetoothMAC;
}
// Returns the device total memory.
getMemoryTotal() {
return this.#memoryTotal;
}
// Returns the device flash size.
getFlashSize() {
return this.#flashSize;
}
// Returns the video resolution.
getVideoResolution() {
return this.#videoResolution;
}
// Returns the sample rate.
getSampleRate() {
return this.#sampleRate;
}
// Returns the number of samples to upload each batch.
getNumSamplesUpload() {
return this.#numSamplesUpload;
}
// Returns the CPU panel data.
getCPUComponentData() {
return JSON.parse(TEMPLATE_COMPONENT_DATA.format(this.CPU_COMPONENT_VISIBLE,
this.CPU_COMPONENT_HAS_PANEL,
this.CPU_COMPONENT_HAS_ARROW,
this.CPU_COMPONENT_PANEL_ALWAYS_VISIBLE,
this.CPU_COMPONENT_PANEL_ORIENTATION,
this.CPU_COMPONENT_PANEL_HORIZONTAL_PERCENT,
this.CPU_COMPONENT_PANEL_VERTICAL_PERCENT,
this.CPU_COMPONENT_ARROW_PERCENT,
this.CPU_COMPONENT_AREA_TOP_PERCENT,
this.CPU_COMPONENT_AREA_LEFT_PERCENT,
this.CPU_COMPONENT_AREA_WIDTH_PERCENT,
this.CPU_COMPONENT_AREA_HEIGHT_PERCENT));
}
// Returns the Memory panel data.
getMemoryComponentData() {
return JSON.parse(TEMPLATE_COMPONENT_DATA.format(this.MEMORY_COMPONENT_VISIBLE,
this.MEMORY_COMPONENT_HAS_PANEL,
this.MEMORY_COMPONENT_HAS_ARROW,
this.MEMORY_COMPONENT_PANEL_ALWAYS_VISIBLE,
this.MEMORY_COMPONENT_PANEL_ORIENTATION,
this.MEMORY_COMPONENT_PANEL_HORIZONTAL_PERCENT,
this.MEMORY_COMPONENT_PANEL_VERTICAL_PERCENT,
this.MEMORY_COMPONENT_ARROW_PERCENT,
this.MEMORY_COMPONENT_AREA_TOP_PERCENT,
this.MEMORY_COMPONENT_AREA_LEFT_PERCENT,
this.MEMORY_COMPONENT_AREA_WIDTH_PERCENT,
this.MEMORY_COMPONENT_AREA_HEIGHT_PERCENT));
}
// Returns the WiFi panel data.
getWifiBtComponentData() {
return JSON.parse(TEMPLATE_COMPONENT_DATA.format(this.WIFI_BT_COMPONENT_VISIBLE,
this.WIFI_BT_COMPONENT_HAS_PANEL,
this.WIFI_BT_COMPONENT_HAS_ARROW,
this.WIFI_BT_COMPONENT_PANEL_ALWAYS_VISIBLE,
this.WIFI_BT_COMPONENT_PANEL_ORIENTATION,
this.WIFI_BT_COMPONENT_PANEL_HORIZONTAL_PERCENT,
this.WIFI_BT_COMPONENT_PANEL_VERTICAL_PERCENT,
this.WIFI_BT_COMPONENT_ARROW_PERCENT,
this.WIFI_BT_COMPONENT_AREA_TOP_PERCENT,
this.WIFI_BT_COMPONENT_AREA_LEFT_PERCENT,
this.WIFI_BT_COMPONENT_AREA_WIDTH_PERCENT,
this.WIFI_BT_COMPONENT_AREA_HEIGHT_PERCENT));
}
// Returns the Ethernet panel data.
getEthernetComponentData() {
return JSON.parse(TEMPLATE_COMPONENT_DATA.format(this.ETHERNET_COMPONENT_VISIBLE,
this.ETHERNET_COMPONENT_HAS_PANEL,
this.ETHERNET_COMPONENT_HAS_ARROW,
this.ETHERNET_COMPONENT_PANEL_ALWAYS_VISIBLE,
this.ETHERNET_COMPONENT_PANEL_ORIENTATION,
this.ETHERNET_COMPONENT_PANEL_HORIZONTAL_PERCENT,
this.ETHERNET_COMPONENT_PANEL_VERTICAL_PERCENT,
this.ETHERNET_COMPONENT_ARROW_PERCENT,
this.ETHERNET_COMPONENT_AREA_TOP_PERCENT,
this.ETHERNET_COMPONENT_AREA_LEFT_PERCENT,
this.ETHERNET_COMPONENT_AREA_WIDTH_PERCENT,
this.ETHERNET_COMPONENT_AREA_HEIGHT_PERCENT));
}
// Returns the Console panel data.
getConsoleComponentData() {
return JSON.parse(TEMPLATE_COMPONENT_DATA.format(this.CONSOLE_COMPONENT_VISIBLE,
this.CONSOLE_COMPONENT_HAS_PANEL,
this.CONSOLE_COMPONENT_HAS_ARROW,
this.CONSOLE_COMPONENT_PANEL_ALWAYS_VISIBLE,
this.CONSOLE_COMPONENT_PANEL_ORIENTATION,
this.CONSOLE_COMPONENT_PANEL_HORIZONTAL_PERCENT,
this.CONSOLE_COMPONENT_PANEL_VERTICAL_PERCENT,
this.CONSOLE_COMPONENT_ARROW_PERCENT,
this.CONSOLE_COMPONENT_AREA_TOP_PERCENT,
this.CONSOLE_COMPONENT_AREA_LEFT_PERCENT,
this.CONSOLE_COMPONENT_AREA_WIDTH_PERCENT,
this.CONSOLE_COMPONENT_AREA_HEIGHT_PERCENT));
}
// Returns the Video panel data.
getVideoComponentData() {
return JSON.parse(TEMPLATE_COMPONENT_DATA.format(this.VIDEO_COMPONENT_VISIBLE,
this.VIDEO_COMPONENT_HAS_PANEL,
this.VIDEO_COMPONENT_HAS_ARROW,
this.VIDEO_COMPONENT_PANEL_ALWAYS_VISIBLE,
this.VIDEO_COMPONENT_PANEL_ORIENTATION,
this.VIDEO_COMPONENT_PANEL_HORIZONTAL_PERCENT,
this.VIDEO_COMPONENT_PANEL_VERTICAL_PERCENT,
this.VIDEO_COMPONENT_ARROW_PERCENT,
this.VIDEO_COMPONENT_AREA_TOP_PERCENT,
this.VIDEO_COMPONENT_AREA_LEFT_PERCENT,
this.VIDEO_COMPONENT_AREA_WIDTH_PERCENT,
this.VIDEO_COMPONENT_AREA_HEIGHT_PERCENT));
}
// Returns the Audio panel data.
getAudioComponentData() {
return JSON.parse(TEMPLATE_COMPONENT_DATA.format(this.AUDIO_COMPONENT_VISIBLE,
this.AUDIO_COMPONENT_HAS_PANEL,
this.AUDIO_COMPONENT_HAS_ARROW,
this.AUDIO_COMPONENT_PANEL_ALWAYS_VISIBLE,
this.AUDIO_COMPONENT_PANEL_ORIENTATION,
this.AUDIO_COMPONENT_PANEL_HORIZONTAL_PERCENT,
this.AUDIO_COMPONENT_PANEL_VERTICAL_PERCENT,
this.AUDIO_COMPONENT_ARROW_PERCENT,
this.AUDIO_COMPONENT_AREA_TOP_PERCENT,
this.AUDIO_COMPONENT_AREA_LEFT_PERCENT,
this.AUDIO_COMPONENT_AREA_WIDTH_PERCENT,
this.AUDIO_COMPONENT_AREA_HEIGHT_PERCENT));
}
// Returns the LED panel data.
getLEDComponentData() {
return JSON.parse(TEMPLATE_COMPONENT_DATA.format(this.LED_COMPONENT_VISIBLE,
this.LED_COMPONENT_HAS_PANEL,
this.LED_COMPONENT_HAS_ARROW,
this.LED_COMPONENT_PANEL_ALWAYS_VISIBLE,
this.LED_COMPONENT_PANEL_ORIENTATION,
this.LED_COMPONENT_PANEL_HORIZONTAL_PERCENT,
this.LED_COMPONENT_PANEL_VERTICAL_PERCENT,
this.LED_COMPONENT_ARROW_PERCENT,
this.LED_COMPONENT_AREA_TOP_PERCENT,
this.LED_COMPONENT_AREA_LEFT_PERCENT,
this.LED_COMPONENT_AREA_WIDTH_PERCENT,
this.LED_COMPONENT_AREA_HEIGHT_PERCENT));
}
// Returns the flash memory panel data.
getFlashMemoryComponentData() {
return JSON.parse(TEMPLATE_COMPONENT_DATA.format(this.FLASH_MEMORY_COMPONENT_VISIBLE,
this.FLASH_MEMORY_COMPONENT_HAS_PANEL,
this.FLASH_MEMORY_COMPONENT_HAS_ARROW,
this.FLASH_MEMORY_COMPONENT_PANEL_ALWAYS_VISIBLE,
this.FLASH_MEMORY_COMPONENT_PANEL_ORIENTATION,
this.FLASH_MEMORY_COMPONENT_PANEL_HORIZONTAL_PERCENT,
this.FLASH_MEMORY_COMPONENT_PANEL_VERTICAL_PERCENT,
this.FLASH_MEMORY_COMPONENT_ARROW_PERCENT,
this.FLASH_MEMORY_COMPONENT_AREA_TOP_PERCENT,
this.FLASH_MEMORY_COMPONENT_AREA_LEFT_PERCENT,
this.FLASH_MEMORY_COMPONENT_AREA_WIDTH_PERCENT,
this.FLASH_MEMORY_COMPONENT_AREA_HEIGHT_PERCENT));
}
// Returns whether the device supports video brightness or not.
supportsVideoBrightness() {
return this.SUPPORTS_VIDEO_BRIGHTNESS;
}
}

View File

@ -0,0 +1,653 @@
/*
* Copyright 2022, Digi International Inc.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
// Constants.
const ID_CURRENT_DIRECTORY = "current_directory";
const ID_FILE_SYSTEM_CONTAINER = "filesystem_container";
const ID_FILE_SYSTEM_DIR_NAME = "filesystem_directory_name";
const ID_FILE_SYSTEM_DIR_NAME_BUTTON = "filesystem_directory_name_button";
const ID_FILE_SYSTEM_DIR_NAME_ERROR = "filesystem_directory_name_error";
const ID_FILE_SYSTEM_DIR_NAME_PANEL = "filesystem_dir_name_panel";
const ID_FILE_SYSTEM_DOWNLOAD_FILE_BUTTON = "filesystem_download_file_button";
const ID_FILE_SYSTEM_HEADER = "filesystem_header";
const ID_FILE_SYSTEM_HOVER_BACKGROUND = "filesystem_hover_background";
const ID_FILE_SYSTEM_ITEMS_CONTAINER = "filesystem_items_container";
const ID_FILE_SYSTEM_ITEMS_HEADER = "filesystem_items_header";
const ID_FILE_SYSTEM_LOADING = "filesystem_loading";
const ID_FILE_SYSTEM_PANEL = "filesystem_panel";
const ID_FILE_SYSTEM_REMOVE_FILE_BUTTON = "filesystem_remove_file_button";
const ID_FILE_SYSTEM_TOOLBAR = "filesystem_toolbar";
const ID_FILE_TO_UPLOAD = "file_to_upload";
const CLASS_FA_FILE = "fa-file";
const CLASS_FILE_SYSTEM_BUTTON_DISABLED = "filesystem-button-disabled";
const CLASS_FILE_SYSTEM_DIR_NAME_BUTTON_DISABLED = "filesystem-dir-name-button-disabled";
const CLASS_FILE_SYSTEM_DIR_NAME_INPUT_ERROR = "filesystem-dir-name-input-error";
const CLASS_FILE_SYSTEM_ENTRY_SELECTED = "filesystem-entry-selected";
const FS_TYPE_FILE = "file";
const FS_TYPE_DIRECTORY = "dir";
const TITLE_CONFIRM_REMOVE = "Confirm Remove";
const MESSAGE_CONFIRM_REMOVE = "Are you sure you want to remove the selected file?";
const PREFIX_FS = "fs_";
const REGEX_DIRECTORY_NAME = '^[^\\s^\x00-\x1f\\?*:"";<>|\\/.][^\x00-\x1f\\?*:"";<>|\\/]*[^\\s^\x00-\x1f\\?*:"";<>|\\/.]+$';
const TEMPLATE_DIRECTORY = "" +
"<div id='fs_{0}' class='filesystem-entry' title='{1}' onclick='listDirectory(\"{2}\")'>" +
" <div class='fas fa-folder fa-lg filesystem-entry-icon'></div>" +
" <div class='filesystem-entry-name'>{3}</div>" +
" <div class='filesystem-entry-size'></div>" +
" <div class='filesystem-entry-last-modified'>{4}</div>" +
"</div>";
const TEMPLATE_FILE = "" +
"<div id='fs_{0}' class='filesystem-entry' title='{1}' onclick='selectFileSystemEntry(\"fs_{2}\")' ondblclick='downloadFile(\"{3}\")'>" +
" <div class='fas fa-file fa-lg filesystem-entry-icon'></div>" +
" <div class='filesystem-entry-name'>{4}</div>" +
" <div class='filesystem-entry-size'>{5}</div>" +
" <div class='filesystem-entry-last-modified'>{6}</div>" +
"</div>";
const ERROR_DIR_NAME_EMPTY = "Directory name cannot be empty.";
const ERROR_DIR_NAME_INVALID = "The entered name is not valid.";
const ROOT_DIRECTORY = "/";
// Variables.
var currentDirectory = null;
var selectedFileSystemEntry = null;
var filesystemResizeObserver = null;
// Opens the file system panel.
function openFileSystem() {
// Check if the file system is showing.
if (isFileSystemShowing())
return;
// Reset current directory.
currentDirectory = null;
$("#" + ID_CURRENT_DIRECTORY).text("");
// Unselect all entries.
unselectFileSystemEntries();
// Clear all the file system entries.
clearFileSystemEntries();
// Setup resize observer.
if (filesystemResizeObserver == null || filesystemResizeObserver == "undefined") {
filesystemResizeObserver = new ResizeObserver((entries) => {
resizeFileSystemElements();
})
filesystemResizeObserver.observe(document.getElementById(ID_FILE_SYSTEM_CONTAINER));
}
// Resize filesystem elements.
resizeFileSystemElements();
// Show the file system.
var fileSystemContainer = document.getElementById(ID_FILE_SYSTEM_PANEL);
fileSystemContainer.style.visibility = "visible";
// List root directory.
listDirectory(ROOT_DIRECTORY);
}
// Returns whether the file system window is open or not.
function isFileSystemShowing() {
// Sanity checks.
if (!isDashboardShowing())
return false;
// Initialize variables.
var fileSystemContainer = document.getElementById(ID_FILE_SYSTEM_PANEL);
// Return visibility.
return fileSystemContainer.style.visibility == "visible";
}
// Closes the file system panel.
function closeFileSystem() {
// Check if the file system is showing.
if (!isFileSystemShowing())
return;
// Hide the loading panel.
showFileSystemLoading(false);
// Hide the file system panel.
var fileSystemContainer = document.getElementById(ID_FILE_SYSTEM_PANEL);
fileSystemContainer.style.visibility = "collapse";
}
// Resizes the file system elements.
function resizeFileSystemElements() {
// If file system is not showing just return.
if (!isFileSystemShowing())
return;
// Initialize variables.
var filesystemContainer = document.getElementById(ID_FILE_SYSTEM_CONTAINER);
var filesystemHeader = document.getElementById(ID_FILE_SYSTEM_HEADER);
var filesystemToolbar = document.getElementById(ID_FILE_SYSTEM_TOOLBAR);
var filesystemHoverBackground = document.getElementById(ID_FILE_SYSTEM_HOVER_BACKGROUND);
var filesystemItemsHeader = document.getElementById(ID_FILE_SYSTEM_ITEMS_HEADER);
var filesystemItemsContainer = document.getElementById(ID_FILE_SYSTEM_ITEMS_CONTAINER);
var containerHeight = filesystemContainer.clientHeight;
var headerHeight = filesystemHeader.clientHeight;
var toolbarHeight = filesystemToolbar.clientHeight;
var itemsHeaderHeight = filesystemItemsHeader.clientHeight;
// Set correct heights.
filesystemHoverBackground.style.height = (containerHeight - headerHeight).toString() + "px";
filesystemItemsContainer.style.height = (containerHeight - headerHeight - toolbarHeight - itemsHeaderHeight).toString() + "px";
}
// Shows/hides the file system loading panel.
function showFileSystemLoading(visible) {
// Initialize variables.
var fileSystemHoverBackground = document.getElementById(ID_FILE_SYSTEM_HOVER_BACKGROUND);
var fileSystemLoading = document.getElementById(ID_FILE_SYSTEM_LOADING);
// Apply visibility.
if (visible && isFileSystemShowing()) {
fileSystemHoverBackground.style.visibility = "visible";
fileSystemLoading.style.visibility = "visible";
} else {
fileSystemHoverBackground.style.visibility = "hidden";
fileSystemLoading.style.visibility = "hidden";
}
}
// Clears all the file system entries.
function clearFileSystemEntries() {
// Initialize variables.
var fileSystemEntriesDiv = document.getElementById(ID_FILE_SYSTEM_ITEMS_CONTAINER);
// Clear all file system HTML entries.
while (fileSystemEntriesDiv.firstChild)
fileSystemEntriesDiv.removeChild(fileSystemEntriesDiv.lastChild);
}
// Enables/disabled the file system buttons.
function enableFileSystemButtons(enable) {
// Initialize variables.
var downloadButton = document.getElementById(ID_FILE_SYSTEM_DOWNLOAD_FILE_BUTTON);
var removeButton = document.getElementById(ID_FILE_SYSTEM_REMOVE_FILE_BUTTON);
// Apply enable state.
if (!enable) {
downloadButton.disabled = true;
removeButton.disabled = true;
downloadButton.classList.add(CLASS_FILE_SYSTEM_BUTTON_DISABLED)
removeButton.classList.add(CLASS_FILE_SYSTEM_BUTTON_DISABLED)
} else {
downloadButton.disabled = false;
removeButton.disabled = false;
downloadButton.classList.remove(CLASS_FILE_SYSTEM_BUTTON_DISABLED)
removeButton.classList.remove(CLASS_FILE_SYSTEM_BUTTON_DISABLED)
}
}
// Selects the given file system entry.
function selectFileSystemEntry(entryID) {
// Unselect all entries.
unselectFileSystemEntries();
// Set selected style to the selected device div.
var entryElement = document.getElementById(entryID)
if (entryElement != null)
entryElement.classList.add(CLASS_FILE_SYSTEM_ENTRY_SELECTED);
// Save selected entry.
selectedFileSystemEntry = entryID;
// Enable buttons.
enableFileSystemButtons(true);
}
// Unselects all the file system entries.
function unselectFileSystemEntries() {
// Initialize variables.
var fileSystemEntriesDiv = document.getElementById(ID_FILE_SYSTEM_ITEMS_CONTAINER);
var children = fileSystemEntriesDiv.children;
// Remove selected class from all entries.
for (var i = 0; i < children.length; i++) {
var entry = children[i].children[0];
entry.classList.remove(CLASS_FILE_SYSTEM_ENTRY_SELECTED);
}
// Reset selected entry.
selectedFileSystemEntry = null;
// Disable buttons.
enableFileSystemButtons(false);
}
// Lists the contents of the given directory.
function listDirectory(directory) {
// Build path.
var path = currentDirectory;
if (path == null || currentDirectory == directory)
path = directory;
else {
if (directory.endsWith("..")) {
// Check if last slash must be removed.
if (path.endsWith("/") && path.length > ROOT_DIRECTORY.length)
path = path.substring(0, path.lastIndexOf("/"));
// Move one directory up.
path = path.substring(0, path.lastIndexOf("/"));
if (path == "")
path = ROOT_DIRECTORY;
} else {
if (!path.endsWith("/"))
path = path + "/"
path = path + directory;
}
}
// Show loading panel.
showFileSystemLoading(true);
// Send request.
$.post(
"../ajax/fs_list_directory",
JSON.stringify({
"device_id": getDeviceID(),
"directory": path
}),
function(data) {
// Process only if the file system window is showing.
if (!isFileSystemShowing())
return;
// Process answer.
processListDirectoryResponse(data);
}
).fail(function(response) {
// Process only if the file system window is showing.
if (!isFileSystemShowing())
return;
// Process error.
processAjaxErrorResponse(response);
// Hide the loading status.
showFileSystemLoading(false);
});
}
// Processes the list directory response.
function processListDirectoryResponse(response) {
// Check if there was any error in the request.
if (checkErrorResponse(response, false)) {
// Hide the loading status.
showFileSystemLoading(false);
// Do not continue.
return;
}
// Unselect all entries.
unselectFileSystemEntries();
// Clear all file system entries.
clearFileSystemEntries();
// Set current directory.
currentDirectory = response[ID_CURRENT_DIR];
if (!currentDirectory.endsWith("/"))
currentDirectory = currentDirectory + "/";
$("#" + ID_CURRENT_DIRECTORY).text(currentDirectory);
// Iterate over all the file system received entries.
if (response[ID_FILES] != null && response[ID_FILES] != "undefined") {
var fileSystemEntriesDiv = document.getElementById(ID_FILE_SYSTEM_ITEMS_CONTAINER);
// Process response entries and create HTML elements.
for (var entry of response[ID_FILES]) {
var name = entry[ID_NAME].substring(currentDirectory.length);
var lastModified = entry[ID_LAST_MODIFIED];
if (lastModified == null || lastModified == "undefined" || lastModified == 0 || name == "..") {
lastModified = "";
} else {
var date = new Date(0); // The 0 there is the key, which sets the date to the epoch
date.setUTCSeconds(lastModified);
lastModified = date.toLocaleString("en-US", { hour12:false });
}
var entryDiv = document.createElement("div");
if (entry[ID_TYPE] == FS_TYPE_FILE)
entryDiv.innerHTML = TEMPLATE_FILE.format(name, name, name, name, name,
sizeToHumanRead(entry[ID_SIZE]), lastModified);
else if (entry[ID_TYPE] == FS_TYPE_DIRECTORY)
entryDiv.innerHTML = TEMPLATE_DIRECTORY.format(name, name, name, name, lastModified);
if (entryDiv.innerHTML != null && entryDiv.innerHTML != "")
fileSystemEntriesDiv.appendChild(entryDiv);
}
}
// Hide the loading status.
showFileSystemLoading(false);
}
// Downloads the selected file.
function downloadSelectedFile() {
// Build file path.
var filePath = selectedFileSystemEntry.substring(PREFIX_FS.length);
// Execute the download action.
downloadFile(filePath);
}
// Attempts to download the given file name.
function downloadFile(fileName) {
// Build file path.
var path = currentDirectory + fileName;
// Show loading panel.
showFileSystemLoading(true);
// Prepare data.
var data = JSON.stringify({
"device_id": getDeviceID(),
"path": path
});
// Send request
$.ajax({
type: 'POST',
url: "../ajax/fs_download_file",
data: data,
cache: false,
async: true,
xhr: function() {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState == 2) {
if (xhr.status == 200)
xhr.responseType = "blob";
else
xhr.responseType = "text";
}
};
return xhr;
},
success: function(response) {
// Process only if the file system window is showing.
if (!isFileSystemShowing())
return;
// Process answer.
processDownloadFileResponse(response);
},
error: function(response) {
// Process only if the file system window is showing.
if (!isFileSystemShowing())
return;
// Process error.
processAjaxErrorResponse(response);
// Hide the loading status.
showFileSystemLoading(false);
}
});
}
// Processes the download file response.
function processDownloadFileResponse(response) {
// Check if there was any error in the request.
if (checkErrorResponse(response, false)) {
// Hide the loading status.
showFileSystemLoading(false);
// Do not continue.
return;
}
// Obtain file name.
var fileName = selectedFileSystemEntry.substring(PREFIX_FS.length)
// Convert the Byte Data to BLOB object.
var blob = new Blob([response], { type: "application/octetstream" });
// Check the Browser type and download the File.
var isIE = false || !!document.documentMode;
if (isIE) {
window.navigator.msSaveBlob(blob, fileName);
} else {
var url = window.URL || window.webkitURL;
link = url.createObjectURL(blob);
var a = $("<a />");
a.attr("download", fileName);
a.attr("href", link);
$("body").append(a);
a[0].click();
$("body").remove(a);
}
// Hide the loading status.
showFileSystemLoading(false);
}
// Asks user to confirm file removal.
function askRemoveFile() {
showConfirmDialog(TITLE_CONFIRM_REMOVE, MESSAGE_CONFIRM_REMOVE,
function() {
// Remove the file.
removeSelectedFile();
},
function() {
// Do nothing.
}
);
}
// Removes the selected file.
function removeSelectedFile() {
// Sanity checks.
if (selectedFileSystemEntry == null)
return;
// Initialize variables.
var isFile = false;
var entryElement = document.getElementById(selectedFileSystemEntry);
var iconElement = entryElement.children[0];
// Check if it is a file.
if (iconElement.classList.contains(CLASS_FA_FILE))
isFile = true;
// Execute action.
removeFile(selectedFileSystemEntry.substring(PREFIX_FS.length), isFile);
}
// Attempts to remove the given file name.
function removeFile(fileName, isFile) {
// Build file path.
var path = currentDirectory + fileName;
// Show loading panel.
showFileSystemLoading(true);
// Send request.
$.post(
"../ajax/fs_remove_file",
JSON.stringify({
"device_id": getDeviceID(),
"path": path,
"is_file": isFile
}),
function(data) {
// Process only if the file system window is showing.
if (!isFileSystemShowing())
return;
// Process answer.
processRemoveFileResponse(data);
}
).fail(function(response) {
// Process only if the file system window is showing.
if (!isFileSystemShowing())
return;
// Process error.
processAjaxErrorResponse(response);
// Hide the loading status.
showFileSystemLoading(false);
});
}
// Processes the remove file response.
function processRemoveFileResponse(response) {
// Check if there was any error in the request.
if (checkErrorResponse(response, false)) {
// Hide the loading status.
showFileSystemLoading(false);
} else {
// List directory contents again.
listDirectory(currentDirectory);
}
}
// Opens the file browser.
function openFileBrowser() {
document.getElementById(ID_FILE_TO_UPLOAD).click();
}
// Attempts to upload the given file.
function uploadFile(file) {
// Build file path.
var path = currentDirectory + file.name;
// Show loading panel.
showFileSystemLoading(true);
// Prepare data.
var formData = new FormData();
formData.append("device_id", getDeviceID());
formData.append("path", path);
formData.append("file", file);
// Send request.
$.ajax({
type: 'POST',
url: "../ajax/fs_upload_file",
data: formData,
cache: false,
async: true,
processData: false,
contentType: false,
enctype: 'multipart/form-data',
success: function(response) {
// Process only if the file system window is showing.
if (!isFileSystemShowing())
return;
// Process answer.
processUploadFileResponse(response);
},
error: function(response) {
// Process only if the file system window is showing.
if (!isFileSystemShowing())
return;
// Process error.
processAjaxErrorResponse(response);
// Hide the loading status.
showFileSystemLoading(false);
}
});
}
// Processes the upload file response.
function processUploadFileResponse(response) {
// Check if there was any error in the request.
if (checkErrorResponse(response, false)) {
// Hide the loading status.
showFileSystemLoading(false);
} else {
// List directory contents again.
listDirectory(currentDirectory);
}
}
// Opens the directory name panel.
function openDirectoryNamePanel() {
// Initialize variables.
var fileSystemDirName = document.getElementById(ID_FILE_SYSTEM_DIR_NAME);
var fileSystemDirNameButton = document.getElementById(ID_FILE_SYSTEM_DIR_NAME_BUTTON);
var fileSystemDirNameError = document.getElementById(ID_FILE_SYSTEM_DIR_NAME_ERROR);
// Reset panel state.
fileSystemDirName.value = "";
fileSystemDirNameError.innerHTML = "&nbsp;";
fileSystemDirNameError.style.visibility = "hidden";
if (!fileSystemDirNameButton.classList.contains(CLASS_FILE_SYSTEM_DIR_NAME_BUTTON_DISABLED))
fileSystemDirNameButton.classList.add(CLASS_FILE_SYSTEM_DIR_NAME_BUTTON_DISABLED);
if (fileSystemDirName.classList.contains(CLASS_FILE_SYSTEM_DIR_NAME_INPUT_ERROR))
fileSystemDirName.classList.remove(CLASS_FILE_SYSTEM_DIR_NAME_INPUT_ERROR);
// Show panel.
showDirectoryNamePanel(true);
}
// Closes the directory name panel.
function closeDirectoryNamePanel() {
showDirectoryNamePanel(false);
}
// Opens the directory name panel.
function showDirectoryNamePanel(visible) {
// Initialize variables.
var fileSystemDirNamePanel = document.getElementById(ID_FILE_SYSTEM_DIR_NAME_PANEL);
var fileSystemDirNameError = document.getElementById(ID_FILE_SYSTEM_DIR_NAME_ERROR);
// Apply visible state.
if (visible && isFileSystemShowing())
fileSystemDirNamePanel.style.visibility = "visible";
else {
fileSystemDirNamePanel.style.visibility = "hidden";
fileSystemDirNameError.style.visibility = "hidden";
}
}
// Handles what happens when the "Create directory" button is pressed.
function onCreateDirectory() {
var fileSystemDirName = document.getElementById(ID_FILE_SYSTEM_DIR_NAME);
var dirName = fileSystemDirName.value;
createDirectory(dirName);
}
// Validates the directory name.
function validateDirectoryName(dirName) {
// Initialize variables.
var fileSystemDirName = document.getElementById(ID_FILE_SYSTEM_DIR_NAME);
var fileSystemDirNameButton = document.getElementById(ID_FILE_SYSTEM_DIR_NAME_BUTTON);
var fileSystemDirNameError = document.getElementById(ID_FILE_SYSTEM_DIR_NAME_ERROR);
var isValid = true;
var error = ERROR_DIR_NAME_INVALID;
// Check if the directory name is valid.
if (dirName == null || dirName == "") {
isValid = false;
error = ERROR_DIR_NAME_EMPTY;
} else
isValid = dirName.match(REGEX_DIRECTORY_NAME);
// Update controls.
if (isValid) {
if (fileSystemDirNameButton.classList.contains(CLASS_FILE_SYSTEM_DIR_NAME_BUTTON_DISABLED))
fileSystemDirNameButton.classList.remove(CLASS_FILE_SYSTEM_DIR_NAME_BUTTON_DISABLED);
if (fileSystemDirName.classList.contains(CLASS_FILE_SYSTEM_DIR_NAME_INPUT_ERROR))
fileSystemDirName.classList.remove(CLASS_FILE_SYSTEM_DIR_NAME_INPUT_ERROR);
fileSystemDirNameError.innerHTML = "&nbsp;";
fileSystemDirNameError.style.visibility = "hidden";
} else {
if (!fileSystemDirNameButton.classList.contains(CLASS_FILE_SYSTEM_DIR_NAME_BUTTON_DISABLED))
fileSystemDirNameButton.classList.add(CLASS_FILE_SYSTEM_DIR_NAME_BUTTON_DISABLED);
if (!fileSystemDirName.classList.contains(CLASS_FILE_SYSTEM_DIR_NAME_INPUT_ERROR))
fileSystemDirName.classList.add(CLASS_FILE_SYSTEM_DIR_NAME_INPUT_ERROR);
fileSystemDirNameError.innerHTML = error;
fileSystemDirNameError.style.visibility = "visible";
}
}
// Attempts to create the given directory.
function createDirectory(directoryName) {
// Build file path.
var path = currentDirectory + directoryName;
// Close the directory name panel.
closeDirectoryNamePanel();
// Show loading panel.
showFileSystemLoading(true);
// Send request.
$.post(
"../ajax/fs_create_dir",
JSON.stringify({
"device_id": getDeviceID(),
"path": path
}),
function(data) {
// Process only if the file system window is showing.
if (!isFileSystemShowing())
return;
// Process answer.
processCreateDirectoryResponse(data);
}
).fail(function(response) {
// Process only if the file system window is showing.
if (!isFileSystemShowing())
return;
// Process error.
processAjaxErrorResponse(response);
// Hide the loading status.
showFileSystemLoading(false);
});
}
// Processes the create directory response.
function processCreateDirectoryResponse(response) {
// Check if there was any error in the request.
if (checkErrorResponse(response, false)) {
// Hide the loading status.
showFileSystemLoading(false);
} else {
// List directory contents again.
listDirectory(currentDirectory);
}
}

View File

@ -0,0 +1,228 @@
/*
* Copyright 2022, Digi International Inc.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
// Constants.
const ID_CPU_CHART = "cpu-chart";
const ID_CPU_CHART_LOADING = "cpu-chart-loading";
const ID_MEMORY_CHART = "memory-chart";
const ID_MEMORY_CHART_LOADING = "memory-chart-loading";
const ID_TEMPERATURE_CHART = "temperature-chart";
const ID_TEMPERATURE_CHART_LOADING = "temperature-chart-loading";
const COLOR_CPU_CHART = "#3399FF";
const COLOR_MEMORY_CHART = "#FFD500";
const COLOR_TEMPERATURE_CHART = "#4F4F4F";
const TITLE_CPU_CHART = "CPU Usage";
const TITLE_MEMORY_CHART = "Memory Usage";
const TITLE_TEMPERATURE_CHART = "Temperature";
const UNITS_CPU_CHART = "%";
const UNITS_MEMORY_CHART = "MB";
const UNITS_TEMPERATURE_CHART = "°C";
// Variables.
var temperatureData = null;
var cpuData = null;
var memoryData = null;
var temperatureInterval = null;
var cpuInterval = null;
var memoryInterval = null;
// Initializes the charts.
function initCharts() {
// Reset the variables.
temperatureData = null;
cpuData = null;
memoryData = null;
temperatureInterval = null;
cpuInterval = null;
memoryInterval = null;
// Draw all the charts.
drawAllCharts(true, true);
}
// Draws all the charts.
function drawAllCharts(refresh=false, showProgress=true) {
// Sanity checks.
if (!isHistoryShowing())
return;
// Draw the charts.
drawTemperatureChart(refresh, showProgress);
drawCPUChart(refresh, showProgress);
drawMemoryChart(refresh, showProgress);
}
// Draws the temperature chart.
function drawTemperatureChart(refresh=false, showProgress=false) {
if (refresh) {
if (showProgress)
$("#" + ID_TEMPERATURE_CHART_LOADING).show();
$.post(
"/ajax/history_temperature",
JSON.stringify({
"device_id": getDeviceID(),
"interval": temperatureInterval
}),
function(response) {
// Process only if histograms page is showing.
if (!isHistoryShowing())
return;
// Check for errors.
if (!checkErrorResponse(response, false)) {
temperatureData = response.data;
drawTemperatureChart();
$("#" + ID_TEMPERATURE_CHART_LOADING).hide();
}
}
).fail(function(response) {
// Process only if histograms page is showing.
if (!isHistoryShowing())
return;
// Process error.
processAjaxErrorResponse(response);
});
} else {
drawChart(ID_TEMPERATURE_CHART, temperatureData, TITLE_TEMPERATURE_CHART, UNITS_TEMPERATURE_CHART, COLOR_TEMPERATURE_CHART);
}
}
// Draws the CPU chart.
function drawCPUChart(refresh=false, showProgress=false) {
if (refresh) {
if (showProgress)
$("#" + ID_CPU_CHART_LOADING).show();
$.post(
"/ajax/history_cpu",
JSON.stringify({
"device_id": getDeviceID(),
"interval": cpuInterval
}),
function(response) {
// Process only if histograms page is showing.
if (!isHistoryShowing())
return;
// Check for errors.
if (!checkErrorResponse(response, false)) {
cpuData = response.data;
drawCPUChart();
$("#" + ID_CPU_CHART_LOADING).hide();
}
}
).fail(function(response) {
// Process only if histograms page is showing.
if (!isHistoryShowing())
return;
// Process error.
processAjaxErrorResponse(response);
});
} else {
drawChart(ID_CPU_CHART, cpuData, TITLE_CPU_CHART, UNITS_CPU_CHART, COLOR_CPU_CHART);
}
}
// Draws the memory chart.
function drawMemoryChart(refresh=false, showProgress=false) {
if (refresh) {
if (showProgress)
$("#" + ID_MEMORY_CHART_LOADING).show();
$.post(
"/ajax/history_memory",
JSON.stringify({
"device_id": getDeviceID(),
"interval": memoryInterval
}),
function(response) {
// Process only if histograms page is showing.
if (!isHistoryShowing())
return;
// Check for errors.
if (!checkErrorResponse(response, false)) {
memoryData = response.data;
drawMemoryChart();
$("#" + ID_MEMORY_CHART_LOADING).hide();
}
}
).fail(function(response) {
// Process only if histograms page is showing.
if (!isHistoryShowing())
return;
// Process error.
processAjaxErrorResponse(response);
});
} else {
drawChart(ID_MEMORY_CHART, memoryData, TITLE_MEMORY_CHART, UNITS_MEMORY_CHART, COLOR_MEMORY_CHART);
}
}
// Draws the chart with the given data.
function drawChart(id, data, title, units, color=null) {
// Sanity checks.
if (!isHistoryShowing())
return;
// Create the chart table.
var dataTable = new google.visualization.DataTable();
dataTable.addColumn("date", "");
dataTable.addColumn("number", "");
// Check if any data was given.
if (data.length == 0) {
$("#" + id).empty();
$("#" + id).append("<span class='no-data-label'>Not enough data</span>");
return;
}
// Add the data rows.
dataTable.addRows(data.length);
// Fill each row with the given data.
$.each(data, function(k, v) {
dataTable.setCell(k, 0, new Date(v[ID_TIMESTAMP]));
dataTable.setCell(k, 1, v[ID_DATA]);
});
// Build chart options.
var options = {
backgroundColor: "transparent",
series: {
0: {
axis: "Data",
color: color,
visibleInLegend: false
}
},
axes: {
y: {
Data: {
label: units
}
}
},
legend: {
position: "none"
},
vAxis: {
viewWindow: {
min: 0
}
}
};
// Create the chart.
var chart = new google.charts.Line(document.getElementById(id));
// Draw the chart.
chart.draw(dataTable, google.charts.Line.convertOptions(options));
}
// Returns the device ID.
function getDeviceID() {
return new URLSearchParams(window.location.search).get(ID_DEVICE_ID);
}

View File

@ -0,0 +1,12 @@
/*
* jquery-match-height 0.7.2 by @liabru
* http://brm.io/jquery-match-height/
* License MIT
*/
!function(t){"use strict";"function"==typeof define&&define.amd?define(["jquery"],t):"undefined"!=typeof module&&module.exports?module.exports=t(require("jquery")):t(jQuery)}(function(t){var e=-1,o=-1,n=function(t){return parseFloat(t)||0},a=function(e){var o=1,a=t(e),i=null,r=[];return a.each(function(){var e=t(this),a=e.offset().top-n(e.css("margin-top")),s=r.length>0?r[r.length-1]:null;null===s?r.push(e):Math.floor(Math.abs(i-a))<=o?r[r.length-1]=s.add(e):r.push(e),i=a}),r},i=function(e){var o={
byRow:!0,property:"height",target:null,remove:!1};return"object"==typeof e?t.extend(o,e):("boolean"==typeof e?o.byRow=e:"remove"===e&&(o.remove=!0),o)},r=t.fn.matchHeight=function(e){var o=i(e);if(o.remove){var n=this;return this.css(o.property,""),t.each(r._groups,function(t,e){e.elements=e.elements.not(n)}),this}return this.length<=1&&!o.target?this:(r._groups.push({elements:this,options:o}),r._apply(this,o),this)};r.version="0.7.2",r._groups=[],r._throttle=80,r._maintainScroll=!1,r._beforeUpdate=null,
r._afterUpdate=null,r._rows=a,r._parse=n,r._parseOptions=i,r._apply=function(e,o){var s=i(o),h=t(e),l=[h],c=t(window).scrollTop(),p=t("html").outerHeight(!0),u=h.parents().filter(":hidden");return u.each(function(){var e=t(this);e.data("style-cache",e.attr("style"))}),u.css("display","block"),s.byRow&&!s.target&&(h.each(function(){var e=t(this),o=e.css("display");"inline-block"!==o&&"flex"!==o&&"inline-flex"!==o&&(o="block"),e.data("style-cache",e.attr("style")),e.css({display:o,"padding-top":"0",
"padding-bottom":"0","margin-top":"0","margin-bottom":"0","border-top-width":"0","border-bottom-width":"0",height:"100px",overflow:"hidden"})}),l=a(h),h.each(function(){var e=t(this);e.attr("style",e.data("style-cache")||"")})),t.each(l,function(e,o){var a=t(o),i=0;if(s.target)i=s.target.outerHeight(!1);else{if(s.byRow&&a.length<=1)return void a.css(s.property,"");a.each(function(){var e=t(this),o=e.attr("style"),n=e.css("display");"inline-block"!==n&&"flex"!==n&&"inline-flex"!==n&&(n="block");var a={
display:n};a[s.property]="",e.css(a),e.outerHeight(!1)>i&&(i=e.outerHeight(!1)),o?e.attr("style",o):e.css("display","")})}a.each(function(){var e=t(this),o=0;s.target&&e.is(s.target)||("border-box"!==e.css("box-sizing")&&(o+=n(e.css("border-top-width"))+n(e.css("border-bottom-width")),o+=n(e.css("padding-top"))+n(e.css("padding-bottom"))),e.css(s.property,i-o+"px"))})}),u.each(function(){var e=t(this);e.attr("style",e.data("style-cache")||null)}),r._maintainScroll&&t(window).scrollTop(c/p*t("html").outerHeight(!0)),
this},r._applyDataApi=function(){var e={};t("[data-match-height], [data-mh]").each(function(){var o=t(this),n=o.attr("data-mh")||o.attr("data-match-height");n in e?e[n]=e[n].add(o):e[n]=o}),t.each(e,function(){this.matchHeight(!0)})};var s=function(e){r._beforeUpdate&&r._beforeUpdate(e,r._groups),t.each(r._groups,function(){r._apply(this.elements,this.options)}),r._afterUpdate&&r._afterUpdate(e,r._groups)};r._update=function(n,a){if(a&&"resize"===a.type){var i=t(window).width();if(i===e)return;e=i;
}n?o===-1&&(o=setTimeout(function(){s(a),o=-1},r._throttle)):s(a)},t(r._applyDataApi);var h=t.fn.on?"on":"bind";t(window)[h]("load",function(t){r._update(!1,t)}),t(window)[h]("resize orientationchange",function(t){r._update(!0,t)})});

View File

@ -0,0 +1,903 @@
/*!
* Copyright 2012, Chris Wanstrath
* Released under the MIT License
* https://github.com/defunkt/jquery-pjax
*/
(function($){
// When called on a container with a selector, fetches the href with
// ajax into the container or with the data-pjax attribute on the link
// itself.
//
// Tries to make sure the back button and ctrl+click work the way
// you'd expect.
//
// Exported as $.fn.pjax
//
// Accepts a jQuery ajax options object that may include these
// pjax specific options:
//
//
// container - String selector for the element where to place the response body.
// push - Whether to pushState the URL. Defaults to true (of course).
// replace - Want to use replaceState instead? That's cool.
//
// For convenience the second parameter can be either the container or
// the options object.
//
// Returns the jQuery object
function fnPjax(selector, container, options) {
options = optionsFor(container, options)
return this.on('click.pjax', selector, function(event) {
var opts = options
if (!opts.container) {
opts = $.extend({}, options)
opts.container = $(this).attr('data-pjax')
}
handleClick(event, opts)
})
}
// Public: pjax on click handler
//
// Exported as $.pjax.click.
//
// event - "click" jQuery.Event
// options - pjax options
//
// Examples
//
// $(document).on('click', 'a', $.pjax.click)
// // is the same as
// $(document).pjax('a')
//
// Returns nothing.
function handleClick(event, container, options) {
options = optionsFor(container, options)
var link = event.currentTarget
var $link = $(link)
if (link.tagName.toUpperCase() !== 'A')
throw "$.fn.pjax or $.pjax.click requires an anchor element"
// Middle click, cmd click, and ctrl click should open
// links in a new tab as normal.
if ( event.which > 1 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey )
return
// Ignore cross origin links
if ( location.protocol !== link.protocol || location.hostname !== link.hostname )
return
// Ignore case when a hash is being tacked on the current URL
if ( link.href.indexOf('#') > -1 && stripHash(link) == stripHash(location) )
return
// Ignore event with default prevented
if (event.isDefaultPrevented())
return
var defaults = {
url: link.href,
container: $link.attr('data-pjax'),
target: link
}
var opts = $.extend({}, defaults, options)
var clickEvent = $.Event('pjax:click')
$link.trigger(clickEvent, [opts])
if (!clickEvent.isDefaultPrevented()) {
pjax(opts)
event.preventDefault()
$link.trigger('pjax:clicked', [opts])
}
}
// Public: pjax on form submit handler
//
// Exported as $.pjax.submit
//
// event - "click" jQuery.Event
// options - pjax options
//
// Examples
//
// $(document).on('submit', 'form', function(event) {
// $.pjax.submit(event, '[data-pjax-container]')
// })
//
// Returns nothing.
function handleSubmit(event, container, options) {
options = optionsFor(container, options)
var form = event.currentTarget
var $form = $(form)
if (form.tagName.toUpperCase() !== 'FORM')
throw "$.pjax.submit requires a form element"
var defaults = {
type: ($form.attr('method') || 'GET').toUpperCase(),
url: $form.attr('action'),
container: $form.attr('data-pjax'),
target: form
}
if (defaults.type !== 'GET' && window.FormData !== undefined) {
defaults.data = new FormData(form)
defaults.processData = false
defaults.contentType = false
} else {
// Can't handle file uploads, exit
if ($form.find(':file').length) {
return
}
// Fallback to manually serializing the fields
defaults.data = $form.serializeArray()
}
pjax($.extend({}, defaults, options))
event.preventDefault()
}
// Loads a URL with ajax, puts the response body inside a container,
// then pushState()'s the loaded URL.
//
// Works just like $.ajax in that it accepts a jQuery ajax
// settings object (with keys like url, type, data, etc).
//
// Accepts these extra keys:
//
// container - String selector for where to stick the response body.
// push - Whether to pushState the URL. Defaults to true (of course).
// replace - Want to use replaceState instead? That's cool.
//
// Use it just like $.ajax:
//
// var xhr = $.pjax({ url: this.href, container: '#main' })
// console.log( xhr.readyState )
//
// Returns whatever $.ajax returns.
function pjax(options) {
options = $.extend(true, {}, $.ajaxSettings, pjax.defaults, options)
if ($.isFunction(options.url)) {
options.url = options.url()
}
var hash = parseURL(options.url).hash
var containerType = $.type(options.container)
if (containerType !== 'string') {
throw "expected string value for 'container' option; got " + containerType
}
var context = options.context = $(options.container)
if (!context.length) {
throw "the container selector '" + options.container + "' did not match anything"
}
// We want the browser to maintain two separate internal caches: one
// for pjax'd partial page loads and one for normal page loads.
// Without adding this secret parameter, some browsers will often
// confuse the two.
if (!options.data) options.data = {}
if ($.isArray(options.data)) {
options.data.push({name: '_pjax', value: options.container})
} else {
options.data._pjax = options.container
}
function fire(type, args, props) {
if (!props) props = {}
props.relatedTarget = options.target
var event = $.Event(type, props)
context.trigger(event, args)
return !event.isDefaultPrevented()
}
var timeoutTimer
options.beforeSend = function(xhr, settings) {
// No timeout for non-GET requests
// Its not safe to request the resource again with a fallback method.
if (settings.type !== 'GET') {
settings.timeout = 0
}
xhr.setRequestHeader('X-PJAX', 'true')
xhr.setRequestHeader('X-PJAX-Container', options.container)
if (!fire('pjax:beforeSend', [xhr, settings]))
return false
if (settings.timeout > 0) {
timeoutTimer = setTimeout(function() {
if (fire('pjax:timeout', [xhr, options]))
xhr.abort('timeout')
}, settings.timeout)
// Clear timeout setting so jquerys internal timeout isn't invoked
settings.timeout = 0
}
var url = parseURL(settings.url)
if (hash) url.hash = hash
options.requestUrl = stripInternalParams(url)
}
options.complete = function(xhr, textStatus) {
if (timeoutTimer)
clearTimeout(timeoutTimer)
fire('pjax:complete', [xhr, textStatus, options])
fire('pjax:end', [xhr, options])
}
options.error = function(xhr, textStatus, errorThrown) {
var container = extractContainer("", xhr, options)
var allowed = fire('pjax:error', [xhr, textStatus, errorThrown, options])
if (options.type == 'GET' && textStatus !== 'abort' && allowed) {
locationReplace(container.url)
}
}
options.success = function(data, status, xhr) {
var previousState = pjax.state
// If $.pjax.defaults.version is a function, invoke it first.
// Otherwise it can be a static string.
var currentVersion = typeof $.pjax.defaults.version === 'function' ?
$.pjax.defaults.version() :
$.pjax.defaults.version
var latestVersion = xhr.getResponseHeader('X-PJAX-Version')
var container = extractContainer(data, xhr, options)
var url = parseURL(container.url)
if (hash) {
url.hash = hash
container.url = url.href
}
// If there is a layout version mismatch, hard load the new url
if (currentVersion && latestVersion && currentVersion !== latestVersion) {
locationReplace(container.url)
return
}
// If the new response is missing a body, hard load the page
if (!container.contents) {
locationReplace(container.url)
return
}
pjax.state = {
id: options.id || uniqueId(),
url: container.url,
title: container.title,
container: options.container,
fragment: options.fragment,
timeout: options.timeout
}
if (options.push || options.replace) {
window.history.replaceState(pjax.state, container.title, container.url)
}
// Only blur the focus if the focused element is within the container.
var blurFocus = $.contains(context, document.activeElement)
// Clear out any focused controls before inserting new page contents.
if (blurFocus) {
try {
document.activeElement.blur()
} catch (e) { /* ignore */ }
}
if (container.title) document.title = container.title
fire('pjax:beforeReplace', [container.contents, options], {
state: pjax.state,
previousState: previousState
})
context.html(container.contents)
// FF bug: Won't autofocus fields that are inserted via JS.
// This behavior is incorrect. So if theres no current focus, autofocus
// the last field.
//
// http://www.w3.org/html/wg/drafts/html/master/forms.html
var autofocusEl = context.find('input[autofocus], textarea[autofocus]').last()[0]
if (autofocusEl && document.activeElement !== autofocusEl) {
autofocusEl.focus()
}
executeScriptTags(container.scripts)
var scrollTo = options.scrollTo
// Ensure browser scrolls to the element referenced by the URL anchor
if (hash) {
var name = decodeURIComponent(hash.slice(1))
var target = document.getElementById(name) || document.getElementsByName(name)[0]
if (target) scrollTo = $(target).offset().top
}
if (typeof scrollTo == 'number') $(window).scrollTop(scrollTo)
fire('pjax:success', [data, status, xhr, options])
}
// Initialize pjax.state for the initial page load. Assume we're
// using the container and options of the link we're loading for the
// back button to the initial page. This ensures good back button
// behavior.
if (!pjax.state) {
pjax.state = {
id: uniqueId(),
url: window.location.href,
title: document.title,
container: options.container,
fragment: options.fragment,
timeout: options.timeout
}
window.history.replaceState(pjax.state, document.title)
}
// Cancel the current request if we're already pjaxing
abortXHR(pjax.xhr)
pjax.options = options
var xhr = pjax.xhr = $.ajax(options)
if (xhr.readyState > 0) {
if (options.push && !options.replace) {
// Cache current container element before replacing it
cachePush(pjax.state.id, [options.container, cloneContents(context)])
window.history.pushState(null, "", options.requestUrl)
}
fire('pjax:start', [xhr, options])
fire('pjax:send', [xhr, options])
}
return pjax.xhr
}
// Public: Reload current page with pjax.
//
// Returns whatever $.pjax returns.
function pjaxReload(container, options) {
var defaults = {
url: window.location.href,
push: false,
replace: true,
scrollTo: false
}
return pjax($.extend(defaults, optionsFor(container, options)))
}
// Internal: Hard replace current state with url.
//
// Work for around WebKit
// https://bugs.webkit.org/show_bug.cgi?id=93506
//
// Returns nothing.
function locationReplace(url) {
window.history.replaceState(null, "", pjax.state.url)
window.location.replace(url)
}
var initialPop = true
var initialURL = window.location.href
var initialState = window.history.state
// Initialize $.pjax.state if possible
// Happens when reloading a page and coming forward from a different
// session history.
if (initialState && initialState.container) {
pjax.state = initialState
}
// Non-webkit browsers don't fire an initial popstate event
if ('state' in window.history) {
initialPop = false
}
// popstate handler takes care of the back and forward buttons
//
// You probably shouldn't use pjax on pages with other pushState
// stuff yet.
function onPjaxPopstate(event) {
// Hitting back or forward should override any pending PJAX request.
if (!initialPop) {
abortXHR(pjax.xhr)
}
var previousState = pjax.state
var state = event.state
var direction
if (state && state.container) {
// When coming forward from a separate history session, will get an
// initial pop with a state we are already at. Skip reloading the current
// page.
if (initialPop && initialURL == state.url) return
if (previousState) {
// If popping back to the same state, just skip.
// Could be clicking back from hashchange rather than a pushState.
if (previousState.id === state.id) return
// Since state IDs always increase, we can deduce the navigation direction
direction = previousState.id < state.id ? 'forward' : 'back'
}
var cache = cacheMapping[state.id] || []
var containerSelector = cache[0] || state.container
var container = $(containerSelector), contents = cache[1]
if (container.length) {
if (previousState) {
// Cache current container before replacement and inform the
// cache which direction the history shifted.
cachePop(direction, previousState.id, [containerSelector, cloneContents(container)])
}
var popstateEvent = $.Event('pjax:popstate', {
state: state,
direction: direction
})
container.trigger(popstateEvent)
var options = {
id: state.id,
url: state.url,
container: containerSelector,
push: false,
fragment: state.fragment,
timeout: state.timeout,
scrollTo: false
}
if (contents) {
container.trigger('pjax:start', [null, options])
pjax.state = state
if (state.title) document.title = state.title
var beforeReplaceEvent = $.Event('pjax:beforeReplace', {
state: state,
previousState: previousState
})
container.trigger(beforeReplaceEvent, [contents, options])
container.html(contents)
container.trigger('pjax:end', [null, options])
} else {
pjax(options)
}
// Force reflow/relayout before the browser tries to restore the
// scroll position.
container[0].offsetHeight // eslint-disable-line no-unused-expressions
} else {
locationReplace(location.href)
}
}
initialPop = false
}
// Fallback version of main pjax function for browsers that don't
// support pushState.
//
// Returns nothing since it retriggers a hard form submission.
function fallbackPjax(options) {
var url = $.isFunction(options.url) ? options.url() : options.url,
method = options.type ? options.type.toUpperCase() : 'GET'
var form = $('<form>', {
method: method === 'GET' ? 'GET' : 'POST',
action: url,
style: 'display:none'
})
if (method !== 'GET' && method !== 'POST') {
form.append($('<input>', {
type: 'hidden',
name: '_method',
value: method.toLowerCase()
}))
}
var data = options.data
if (typeof data === 'string') {
$.each(data.split('&'), function(index, value) {
var pair = value.split('=')
form.append($('<input>', {type: 'hidden', name: pair[0], value: pair[1]}))
})
} else if ($.isArray(data)) {
$.each(data, function(index, value) {
form.append($('<input>', {type: 'hidden', name: value.name, value: value.value}))
})
} else if (typeof data === 'object') {
var key
for (key in data)
form.append($('<input>', {type: 'hidden', name: key, value: data[key]}))
}
$(document.body).append(form)
form.submit()
}
// Internal: Abort an XmlHttpRequest if it hasn't been completed,
// also removing its event handlers.
function abortXHR(xhr) {
if ( xhr && xhr.readyState < 4) {
xhr.onreadystatechange = $.noop
xhr.abort()
}
}
// Internal: Generate unique id for state object.
//
// Use a timestamp instead of a counter since ids should still be
// unique across page loads.
//
// Returns Number.
function uniqueId() {
return (new Date).getTime()
}
function cloneContents(container) {
var cloned = container.clone()
// Unmark script tags as already being eval'd so they can get executed again
// when restored from cache. HAXX: Uses jQuery internal method.
cloned.find('script').each(function(){
if (!this.src) $._data(this, 'globalEval', false)
})
return cloned.contents()
}
// Internal: Strip internal query params from parsed URL.
//
// Returns sanitized url.href String.
function stripInternalParams(url) {
url.search = url.search.replace(/([?&])(_pjax|_)=[^&]*/g, '').replace(/^&/, '')
return url.href.replace(/\?($|#)/, '$1')
}
// Internal: Parse URL components and returns a Locationish object.
//
// url - String URL
//
// Returns HTMLAnchorElement that acts like Location.
function parseURL(url) {
var a = document.createElement('a')
a.href = url
return a
}
// Internal: Return the `href` component of given URL object with the hash
// portion removed.
//
// location - Location or HTMLAnchorElement
//
// Returns String
function stripHash(location) {
return location.href.replace(/#.*/, '')
}
// Internal: Build options Object for arguments.
//
// For convenience the first parameter can be either the container or
// the options object.
//
// Examples
//
// optionsFor('#container')
// // => {container: '#container'}
//
// optionsFor('#container', {push: true})
// // => {container: '#container', push: true}
//
// optionsFor({container: '#container', push: true})
// // => {container: '#container', push: true}
//
// Returns options Object.
function optionsFor(container, options) {
if (container && options) {
options = $.extend({}, options)
options.container = container
return options
} else if ($.isPlainObject(container)) {
return container
} else {
return {container: container}
}
}
// Internal: Filter and find all elements matching the selector.
//
// Where $.fn.find only matches descendants, findAll will test all the
// top level elements in the jQuery object as well.
//
// elems - jQuery object of Elements
// selector - String selector to match
//
// Returns a jQuery object.
function findAll(elems, selector) {
return elems.filter(selector).add(elems.find(selector))
}
function parseHTML(html) {
return $.parseHTML(html, document, true)
}
// Internal: Extracts container and metadata from response.
//
// 1. Extracts X-PJAX-URL header if set
// 2. Extracts inline <title> tags
// 3. Builds response Element and extracts fragment if set
//
// data - String response data
// xhr - XHR response
// options - pjax options Object
//
// Returns an Object with url, title, and contents keys.
function extractContainer(data, xhr, options) {
var obj = {}, fullDocument = /<html/i.test(data)
// Prefer X-PJAX-URL header if it was set, otherwise fallback to
// using the original requested url.
var serverUrl = xhr.getResponseHeader('X-PJAX-URL')
obj.url = serverUrl ? stripInternalParams(parseURL(serverUrl)) : options.requestUrl
var $head, $body
// Attempt to parse response html into elements
if (fullDocument) {
$body = $(parseHTML(data.match(/<body[^>]*>([\s\S.]*)<\/body>/i)[0]))
var head = data.match(/<head[^>]*>([\s\S.]*)<\/head>/i)
$head = head != null ? $(parseHTML(head[0])) : $body
} else {
$head = $body = $(parseHTML(data))
}
// If response data is empty, return fast
if ($body.length === 0)
return obj
// If there's a <title> tag in the header, use it as
// the page's title.
obj.title = findAll($head, 'title').last().text()
if (options.fragment) {
var $fragment = $body
// If they specified a fragment, look for it in the response
// and pull it out.
if (options.fragment !== 'body') {
$fragment = findAll($fragment, options.fragment).first()
}
if ($fragment.length) {
obj.contents = options.fragment === 'body' ? $fragment : $fragment.contents()
// If there's no title, look for data-title and title attributes
// on the fragment
if (!obj.title)
obj.title = $fragment.attr('title') || $fragment.data('title')
}
} else if (!fullDocument) {
obj.contents = $body
}
// Clean up any <title> tags
if (obj.contents) {
// Remove any parent title elements
obj.contents = obj.contents.not(function() { return $(this).is('title') })
// Then scrub any titles from their descendants
obj.contents.find('title').remove()
// Gather all script[src] elements
obj.scripts = findAll(obj.contents, 'script[src]').remove()
obj.contents = obj.contents.not(obj.scripts)
}
// Trim any whitespace off the title
if (obj.title) obj.title = $.trim(obj.title)
return obj
}
// Load an execute scripts using standard script request.
//
// Avoids jQuery's traditional $.getScript which does a XHR request and
// globalEval.
//
// scripts - jQuery object of script Elements
//
// Returns nothing.
function executeScriptTags(scripts) {
if (!scripts) return
var existingScripts = $('script[src]')
scripts.each(function() {
var src = this.src
var matchedScripts = existingScripts.filter(function() {
return this.src === src
})
if (matchedScripts.length) return
var script = document.createElement('script')
var type = $(this).attr('type')
if (type) script.type = type
script.src = $(this).attr('src')
document.head.appendChild(script)
})
}
// Internal: History DOM caching class.
var cacheMapping = {}
var cacheForwardStack = []
var cacheBackStack = []
// Push previous state id and container contents into the history
// cache. Should be called in conjunction with `pushState` to save the
// previous container contents.
//
// id - State ID Number
// value - DOM Element to cache
//
// Returns nothing.
function cachePush(id, value) {
cacheMapping[id] = value
cacheBackStack.push(id)
// Remove all entries in forward history stack after pushing a new page.
trimCacheStack(cacheForwardStack, 0)
// Trim back history stack to max cache length.
trimCacheStack(cacheBackStack, pjax.defaults.maxCacheLength)
}
// Shifts cache from directional history cache. Should be
// called on `popstate` with the previous state id and container
// contents.
//
// direction - "forward" or "back" String
// id - State ID Number
// value - DOM Element to cache
//
// Returns nothing.
function cachePop(direction, id, value) {
var pushStack, popStack
cacheMapping[id] = value
if (direction === 'forward') {
pushStack = cacheBackStack
popStack = cacheForwardStack
} else {
pushStack = cacheForwardStack
popStack = cacheBackStack
}
pushStack.push(id)
id = popStack.pop()
if (id) delete cacheMapping[id]
// Trim whichever stack we just pushed to to max cache length.
trimCacheStack(pushStack, pjax.defaults.maxCacheLength)
}
// Trim a cache stack (either cacheBackStack or cacheForwardStack) to be no
// longer than the specified length, deleting cached DOM elements as necessary.
//
// stack - Array of state IDs
// length - Maximum length to trim to
//
// Returns nothing.
function trimCacheStack(stack, length) {
while (stack.length > length)
delete cacheMapping[stack.shift()]
}
// Public: Find version identifier for the initial page load.
//
// Returns String version or undefined.
function findVersion() {
return $('meta').filter(function() {
var name = $(this).attr('http-equiv')
return name && name.toUpperCase() === 'X-PJAX-VERSION'
}).attr('content')
}
// Install pjax functions on $.pjax to enable pushState behavior.
//
// Does nothing if already enabled.
//
// Examples
//
// $.pjax.enable()
//
// Returns nothing.
function enable() {
$.fn.pjax = fnPjax
$.pjax = pjax
$.pjax.enable = $.noop
$.pjax.disable = disable
$.pjax.click = handleClick
$.pjax.submit = handleSubmit
$.pjax.reload = pjaxReload
$.pjax.defaults = {
timeout: 650,
push: true,
replace: false,
type: 'GET',
dataType: 'html',
scrollTo: 0,
maxCacheLength: 20,
version: findVersion
}
$(window).on('popstate.pjax', onPjaxPopstate)
}
// Disable pushState behavior.
//
// This is the case when a browser doesn't support pushState. It is
// sometimes useful to disable pushState for debugging on a modern
// browser.
//
// Examples
//
// $.pjax.disable()
//
// Returns nothing.
function disable() {
$.fn.pjax = function() { return this }
$.pjax = fallbackPjax
$.pjax.enable = enable
$.pjax.disable = $.noop
$.pjax.click = $.noop
$.pjax.submit = $.noop
$.pjax.reload = function() { window.location.reload() }
$(window).off('popstate.pjax', onPjaxPopstate)
}
// Add the state property to jQuery's event object so we can use it in
// $(window).bind('popstate')
if ($.event.props && $.inArray('state', $.event.props) < 0) {
$.event.props.push('state')
} else if (!('state' in $.Event.prototype)) {
$.event.addProp('state')
}
// Is pjax supported by this browser?
$.support.pjax =
window.history && window.history.pushState && window.history.replaceState &&
// pushState isn't reliable on iOS until 5.
!navigator.userAgent.match(/((iPod|iPhone|iPad).+\bOS\s+[1-4]\D|WebApps\/.+CFNetwork)/)
if ($.support.pjax) {
enable()
} else {
disable()
}
})(jQuery)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,199 @@
/*
* Copyright 2022, Digi International Inc.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
// Constants.
const ID_DEVICE_CONNECTION_STATUS = "device-connection-status";
const ERROR_DEVICE_NOT_CONNECTED_TITLE = "Device offline";
const ERROR_DEVICE_NOT_CONNECTED_MESSAGE = "The selected device is offline";
// Variables.
var deviceConnectionStatus;
var prevDeviceConnectionStatus;
// Hide submenus
$("#body-row .collapse").collapse("hide");
// Collapse/Expand icon.
$("#collapse-icon").addClass("fa-angle-double-left");
// Select click.
$("#sections > a").click(function() {
selectSection($(this));
});
// Collapse click.
$("[data-toggle=sidebar-collapse]").click(function() {
sidebarCollapse();
});
$(".element-grayed").click(function(){return false;});
// Selects the given item in the sidebar.
function selectSection(selectedItem) {
// Remove decorations of previously selected element.
$("#sections .selected").removeClass(CLASS_SELECTED);
// Decorate the selected element.
selectedItem.toggleClass(CLASS_SELECTED);
}
// Collapses the sidebar to the left.
function sidebarCollapse() {
$(".menu-collapsed").toggleClass("d-none");
$(".sidebar-submenu").toggleClass("d-none");
$(".submenu-icon").toggleClass("d-none");
// Add/Remove right margin.
$(".digi-menu-icon").toggleClass("mr-3 mr-0");
$("#sidebar-container").toggleClass("sidebar-expanded sidebar-collapsed");
// Treating d-flex/d-none on separators with title.
var separatorTitle = $(".sidebar-separator-title");
if (separatorTitle.hasClass("d-flex"))
separatorTitle.removeClass("d-flex");
else
separatorTitle.addClass("d-flex");
// Collapse/Expand icon.
$("#collapse-icon").toggleClass("fa-angle-double-left fa-angle-double-right");
// Make the cards the same height. Wait some time so size is
// calculated after the content of the cards expands or collapses.
window.setTimeout(function () {
$(".adjust-card-height .card").matchHeight();
}, 100);
if (isDashboardShowing()) {
let refreshPanelsInterval = window.setInterval(adjustImageSize, 10);
window.setTimeout(function () {
window.clearInterval(refreshPanelsInterval);
}, 300);
}
}
// Sets the selected section.
function setSelectedSection(element=null) {
// First, unselect all the sections.
$("#sections li").each(function(i, n) {
n.children[0].classList.remove(CLASS_SELECTED);
});
// Select the corresponding section.
if (element != null) {
element.classList.add(CLASS_SELECTED);
} else {
$("#sections li").each(function(i, n) {
if (window.location.pathname == n.children[0].pathname) {
n.children[0].classList.add(CLASS_SELECTED);
return false;
}
});
}
}
// Verifies the given device parameters.
function verifyParameters() {
let url = new URL(window.location.href);
let device_id = url.searchParams.get("device_id");
let device_name = url.searchParams.get("device_name");
$.post(
"../ajax/check_device_connection_status",
JSON.stringify({
"device_id": device_id,
"device_name": device_name
}),
function(data) {
if (data["redirect"])
window.location.replace(data["redirect"]);
}
).fail(function(response) {
processAjaxErrorResponse(response);
});
}
// Requests an update on the connection status of the device.
function checkDeviceConnectionStatus() {
$.post(
"../ajax/check_device_connection_status",
JSON.stringify({
"device_id": getDeviceID()
}),
function(data) {
processDeviceConnectionStatusAnswer(data);
}
);
}
// Processes the device connection status answer.
function processDeviceConnectionStatusAnswer(response) {
// Sanity checks.
if (response[ID_STATUS] == null || response[ID_STATUS] == "undefined") {
// Do not continue.
return;
}
// Save the new connection status.
deviceConnectionStatus = response[ID_STATUS];
// Get icon and title based on connection status.
var statusImage = "";
var statusTitle = "";
if (deviceConnectionStatus == true) {
statusImage = IMAGE_ONLINE;
statusTitle = VALUE_ONLINE;
} else {
statusImage = IMAGE_OFFLINE;
statusTitle = VALUE_OFFLINE;
}
// Update the connection status icon and title.
var deviceStatusElement = document.getElementById(ID_DEVICE_CONNECTION_STATUS);
if (deviceStatusElement != null) {
deviceStatusElement.src = PATH_IMAGES + statusImage;
deviceStatusElement.title = statusTitle;
}
// Check if connection changed to update the displayed section.
if (prevDeviceConnectionStatus != deviceConnectionStatus) {
if (isDashboardShowing()) {
if (deviceConnectionStatus)
initDevice();
else
displayDeviceDisconnectedError();
} else if (isManagementShowing()) {
if (deviceConnectionStatus)
initializeManagementPage();
else if (!isDeviceRebooting())
displayDeviceDisconnectedError();
} else if (isHistoryShowing()) {
if (deviceConnectionStatus)
initCharts();
else
displayDeviceDisconnectedError();
}
}
// Store connection status.
prevDeviceConnectionStatus = deviceConnectionStatus;
// Schedule a new connection status update in 30 seconds.
setTimeout(checkDeviceConnectionStatus, 30000);
}
// Displays the device disconnected error.
function displayDeviceDisconnectedError() {
// Device disconnected, display error.
toastr.error(ERROR_DEVICE_NOT_CONNECTED_TITLE);
// Hide the loading panel of the device.
showLoadingPopup(false);
// Show info dialog.
showInfoPopup(true, ERROR_DEVICE_NOT_CONNECTED_TITLE, ERROR_DEVICE_NOT_CONNECTED_MESSAGE);
}

View File

@ -0,0 +1,32 @@
/*
* Copyright 2020, Digi International Inc.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
const SEPARATOR = "@@@"
var currentTime;
var timer;
function updateTime() {
currentTime += 1;
postMessage(new Date(1000 * currentTime).toISOString().substr(11, 8));
}
onmessage = function (event) {
var parts = event.data.split(SEPARATOR);
currentTime = parseInt(parts[0]);
var factor = parseInt(parts[1]);
setInterval(updateTime, 1000 / factor);
};

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.FitAddon=t():e.FitAddon=t()}(self,(function(){return(()=>{"use strict";var e={775:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.FitAddon=void 0;var r=function(){function e(){}return e.prototype.activate=function(e){this._terminal=e},e.prototype.dispose=function(){},e.prototype.fit=function(){var e=this.proposeDimensions();if(e&&this._terminal){var t=this._terminal._core;this._terminal.rows===e.rows&&this._terminal.cols===e.cols||(t._renderService.clear(),this._terminal.resize(e.cols,e.rows))}},e.prototype.proposeDimensions=function(){if(this._terminal&&this._terminal.element&&this._terminal.element.parentElement){var e=this._terminal._core;if(0!==e._renderService.dimensions.actualCellWidth&&0!==e._renderService.dimensions.actualCellHeight){var t=window.getComputedStyle(this._terminal.element.parentElement),r=parseInt(t.getPropertyValue("height")),i=Math.max(0,parseInt(t.getPropertyValue("width"))),n=window.getComputedStyle(this._terminal.element),o=r-(parseInt(n.getPropertyValue("padding-top"))+parseInt(n.getPropertyValue("padding-bottom"))),a=i-(parseInt(n.getPropertyValue("padding-right"))+parseInt(n.getPropertyValue("padding-left")))-e.viewport.scrollBarWidth;return{cols:Math.max(2,Math.floor(a/e._renderService.dimensions.actualCellWidth)),rows:Math.max(1,Math.floor(o/e._renderService.dimensions.actualCellHeight))}}}},e}();t.FitAddon=r}},t={};return function r(i){if(t[i])return t[i].exports;var n=t[i]={exports:{}};return e[i](n,n.exports,r),n.exports}(775)})()}));

File diff suppressed because one or more lines are too long