
* Added external client IP to dashboard client Id column tooltip * Added client info (cpu, cores, cpu features, current configured threads, current hash mode ..) to client id column tooltip
333 lines
No EOL
12 KiB
HTML
333 lines
No EOL
12 KiB
HTML
<!DOCTYPE html>
|
|
<html lang=\"en\">
|
|
<head>
|
|
<meta charset=\"utf-8\">
|
|
<title>XMRigCC Dashboard</title>
|
|
|
|
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.16/css/jquery.dataTables.min.css">
|
|
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
|
|
|
|
<style>
|
|
.left{text-align:left;}
|
|
.right{text-align:right;}
|
|
.center{text-align:center;}
|
|
.toolbar { float: right; padding-left: 10pt;}
|
|
.online { color: green}
|
|
.offline { color: red}
|
|
</style>
|
|
|
|
<script type="text/javascript" language="javascript" src="//code.jquery.com/jquery-1.12.4.js"></script>
|
|
<script type="text/javascript" language="javascript" src="https://cdn.datatables.net/1.10.16/js/jquery.dataTables.min.js"></script>
|
|
<script type="text/javascript" language="javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery-timeago/1.6.1/jquery.timeago.min.js"></script>
|
|
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
|
|
<script src="https://use.fontawesome.com/6b3cdfc597.js"></script>
|
|
|
|
<script type="text/javascript">
|
|
$.fn.dataTable.ext.search.push(
|
|
function( settings, data, dataIndex ) {
|
|
var hide = document.getElementById("hideOffline").checked;
|
|
|
|
var lastStatus = settings.aoData[dataIndex]._aData.client_status.last_status_update * 1000;
|
|
var threshold = new Date().getTime() - 60 * 1000;
|
|
|
|
if (lastStatus > threshold || !hide) {
|
|
return true;
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
}
|
|
);
|
|
|
|
$(document).ready(function() {
|
|
var table = $('#clientStatusList').DataTable({
|
|
dom: '<"toolbar">frtip',
|
|
processing : true,
|
|
bPaginate : false,
|
|
ajax : {
|
|
url : "/admin/getClientStatusList",
|
|
dataSrc : 'client_status_list'
|
|
},
|
|
columns: [
|
|
{ data: "client_status.client_id", render: clientInfo},
|
|
{ data: "client_status.current_pool"},
|
|
{ data: "client_status.current_status"},
|
|
{ data: "client_status.current_algo_name"},
|
|
{ data: "client_status.hashrate_short", render: round, className: "right"},
|
|
{ data: "client_status.hashrate_medium", render: round, className: "right"},
|
|
{ data: "client_status.hashrate_long", render: round, className: "right"},
|
|
{ data: "client_status.hashrate_highest", render: round, className: "right"},
|
|
{ data: "client_status.hashes_total", className: "right"},
|
|
{ data: "client_status.avg_time", className: "right"},
|
|
{ data: "client_status.shares_good", className: "right"},
|
|
{ data: "client_status.shares_total", className: "right"},
|
|
{ data: "client_status.last_status_update", render: laststatus},
|
|
{
|
|
targets: -1,
|
|
data: null,
|
|
defaultContent:
|
|
"<td><button type='button' id='START' class='btn btn-xs btn-success' data-toggle='tooltip' title='Start'><i class='fa fa-play'></i></button></td>" +
|
|
"<td><button type='button' id='STOP' class='btn btn-xs btn-warning' data-toggle='tooltip' title='Stop'><i class='fa fa-pause'></i></button></td>" +
|
|
"<td><button type='button' id='RESTART' class='btn btn-xs' data-toggle='tooltip' title='Restart'><i class='fa fa-repeat'></i></button></td>" +
|
|
"<td><button type='button' id='UPDATE_CONFIG' class='btn btn-xs btn-info' data-toggle='tooltip' title='Update Config'><i class='fa fa-refresh'></i></button></td>" +
|
|
"<td><button type='button' id='EDIT' class='btn btn-xs btn-primary' data-toggle='tooltip' title='Edit Client Config'><i class='fa fa-cog'></i></button></td>" +
|
|
"<td><button type='button' id='SHUTDOWN' class='btn btn-xs btn-danger' data-toggle='tooltip' title='Stutdown Client'><i class='fa fa-power-off'></i></button></td>",
|
|
className: "center"
|
|
}
|
|
],
|
|
order: [ 0, 'asc' ],
|
|
|
|
"footerCallback": function ( row, data, start, end, display ) {
|
|
var api = this.api();
|
|
|
|
sumHashrateShort = round(api
|
|
.column(4)
|
|
.data()
|
|
.reduce( function (a, b) {
|
|
return a + b;
|
|
}, 0 ));
|
|
|
|
sumHashrateMedium = round(api
|
|
.column(5)
|
|
.data()
|
|
.reduce( function (a, b) {
|
|
return a + b;
|
|
}, 0 ));
|
|
|
|
sumHashrateLong = round(api
|
|
.column(6)
|
|
.data()
|
|
.reduce( function (a, b) {
|
|
return a + b;
|
|
}, 0 ));
|
|
|
|
sumHashrateHighest = round(api
|
|
.column(7)
|
|
.data()
|
|
.reduce( function (a, b) {
|
|
return a + b;
|
|
}, 0 ));
|
|
|
|
sumHashesTotal = api
|
|
.column(8)
|
|
.data()
|
|
.reduce( function (a, b) {
|
|
return a + b;
|
|
}, 0 );
|
|
|
|
avgTimeTotal = round(api
|
|
.column(9)
|
|
.data()
|
|
.reduce( function (a, b) {
|
|
return a + b;
|
|
}, 0 )/end);
|
|
|
|
sumSharesGood = api
|
|
.column(10)
|
|
.data()
|
|
.reduce( function (a, b) {
|
|
return a + b;
|
|
}, 0 );
|
|
|
|
sumSharedTotal = api
|
|
.column(11)
|
|
.data()
|
|
.reduce( function (a, b) {
|
|
return a + b;
|
|
}, 0 );
|
|
|
|
// Update footer
|
|
$(api.column(4).footer()).html(sumHashrateShort);
|
|
$(api.column(5).footer()).html(sumHashrateMedium);
|
|
$(api.column(6).footer()).html(sumHashrateLong);
|
|
$(api.column(7).footer()).html(sumHashrateHighest);
|
|
$(api.column(8).footer()).html(sumHashesTotal);
|
|
$(api.column(9).footer()).html(avgTimeTotal);
|
|
$(api.column(10).footer()).html(sumSharesGood);
|
|
$(api.column(11).footer()).html(sumSharedTotal);
|
|
}
|
|
});
|
|
|
|
$("div.toolbar").html('<input type="checkbox" id="hideOffline" value="hide" checked style="margin-right: 5pt"><label>Hide offline miners</label>');
|
|
|
|
$('#clientStatusList tbody').on( 'click', 'button', function () {
|
|
var data = table.row( $(this).parents('tr') ).data();
|
|
var clientId = data['client_status']['client_id'];
|
|
var action = this.id;
|
|
|
|
if (action != "EDIT"){
|
|
$.ajax({
|
|
type: "POST",
|
|
url: "/admin/setClientCommand?clientId=" + clientId,
|
|
dataType:"text",
|
|
data: '{"control_command":{"command": "' + action + '"}}',
|
|
success: function(data){
|
|
alert("Successfully send: " + action + " to: " + clientId);
|
|
},
|
|
error: function (data) {
|
|
alert("Failed to send: " + action +" to: " + clientId + "\nError: " + JSON.stringify(data,undefined, 2));
|
|
}
|
|
});
|
|
}
|
|
else {
|
|
$.ajax({
|
|
type: "GET",
|
|
url: "/admin/getClientConfig?clientId=" + clientId,
|
|
dataType:"json",
|
|
success: function(jsonClientConfig) {
|
|
var htmlContent = "<div class='form-group' id='editor' data-value='" + clientId + "'>" +
|
|
"<label for='config'>Config for: " + clientId + "</label>"+
|
|
"<textarea class='form-control' rows='20' id='config'>" +
|
|
JSON.stringify(jsonClientConfig,undefined, 2) +
|
|
"</textarea>" +
|
|
"</div>";
|
|
|
|
$('#editConfig').find('.modal-body').html(htmlContent);
|
|
$('#editConfig').modal('show');
|
|
},
|
|
error: function (data) {
|
|
alert("Unable to fetch " + clientId + "_config.json or default_config.json, please check your Server configuration and the the config files are located on the Server!");
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
$('button.btn.btn-success').click(function(event)
|
|
{
|
|
var clientId = $('#editConfig').find('.form-group')["0"].dataset.value;
|
|
|
|
event.preventDefault();
|
|
$.ajax({
|
|
url: "/admin/setClientConfig?clientId=" + clientId,
|
|
type: 'POST',
|
|
dataType: "text",
|
|
data: $('#config').val(),
|
|
success: function(data){
|
|
alert("Successfully saved config for: " + clientId);
|
|
},
|
|
error: function (data) {
|
|
alert("Failed to store config for: " + clientId + "\nError: " + JSON.stringify(data,undefined, 2));
|
|
}
|
|
});
|
|
});
|
|
|
|
$('#hideOffline').click( function() {
|
|
table.draw();
|
|
} );
|
|
|
|
setInterval(function () {
|
|
table.ajax.reload();
|
|
}, 10000);
|
|
});
|
|
|
|
function laststatus( data, type, row ) {
|
|
var date = new Date(data*1000);
|
|
|
|
return '<span data-toggle="tooltip" title="' + date + '">' + jQuery.timeago(date) + '</span>';
|
|
}
|
|
|
|
function clientInfo( data, type, row ) {
|
|
var tooltip = "CPU: " + row.client_status.cpu_brand;
|
|
tooltip += '\n';
|
|
tooltip += "CPU Flags: " + (row.client_status.cpu_has_aes ? "AES-NI " : "");
|
|
tooltip += (row.client_status.cpu_is_x64 ? "x64" : "");
|
|
tooltip += '\n';
|
|
tooltip += "CPU Cache L2/L3: " + (row.client_status.cpu_l2 / 1024) + " MB/"+ (row.client_status.cpu_l3 / 1024) + " MB";
|
|
tooltip += '\n';
|
|
tooltip += "Huge Pages: " + (row.client_status.hugepages_available ? " available, " : " unavailable, ");
|
|
tooltip += (row.client_status.hugepages_enabled ? "enabled" : "disabled");
|
|
tooltip += '\n';
|
|
tooltip += "Threads: " + row.client_status.current_threads;
|
|
tooltip += (row.client_status.double_hash_mode ? " [double hash mode]" :"");
|
|
tooltip += '\n';
|
|
tooltip += "Client IP: " + row.client_status.external_ip;
|
|
tooltip += '\n';
|
|
tooltip += "Status: ";
|
|
|
|
var lastStatus = row.client_status.last_status_update * 1000;
|
|
var threshold = new Date().getTime() - 60 * 1000;
|
|
if (lastStatus > threshold) {
|
|
tooltip += "Online";
|
|
return '<span data-toggle="tooltip" title="'+ tooltip + '"><div class="online">' + data + '</div></span>';
|
|
}
|
|
else {
|
|
tooltip += "Offline";
|
|
return '<span data-toggle="tooltip" title="'+ tooltip + '"><div class="offline">' + data + '</div></span>';
|
|
}
|
|
}
|
|
|
|
function round( data, type, row ) {
|
|
return Math.round(data * 100) / 100;
|
|
}
|
|
|
|
</script>
|
|
|
|
</head>
|
|
<body>
|
|
<br/>
|
|
<div style="width: 90%; margin:0 auto;">
|
|
<div class="center">
|
|
<h1>XMRigCC Dashboard</h1>
|
|
</div>
|
|
<table id="clientStatusList" class="display" cellspacing="0" width="100%">
|
|
<thead>
|
|
<tr>
|
|
<th>Client Id</th>
|
|
<th>Pool</th>
|
|
<th>Status</th>
|
|
<th>Algo</th>
|
|
|
|
<th>Hashrate</th>
|
|
<th>Hashrate 5m</th>
|
|
<th>Hashrate 60m</th>
|
|
|
|
<th>Hashrate Highest</th>
|
|
<th>Hashes Total</th>
|
|
<th>Avg. Time</th>
|
|
|
|
<th>Shares Good</th>
|
|
<th>Shares Total</th>
|
|
<th>Last Update</th>
|
|
<th colspan="6" class="center">Action</th>
|
|
</tr>
|
|
</thead>
|
|
<tfoot>
|
|
<tr>
|
|
<th class="left">Total:</th>
|
|
<th></th>
|
|
<th></th>
|
|
<th></th>
|
|
<th></th>
|
|
<th></th>
|
|
<th></th>
|
|
<th></th>
|
|
<th></th>
|
|
<th></th>
|
|
<th></th>
|
|
<th></th>
|
|
<th></th>
|
|
<th></th>
|
|
</tr>
|
|
</tfoot>
|
|
</table>
|
|
|
|
<div class="modal fade" id="editConfig" role="dialog">
|
|
<div class="modal-dialog modal-lg">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<button type="button" class="close" data-dismiss="modal">×</button>
|
|
<h4 class="modal-title">Config editor</h4>
|
|
</div>
|
|
<div class="modal-body">
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-success" data-dismiss="modal">Save</button>
|
|
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html> |