in server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/ec.js [30:358]
$(function () {
if (sessionStorage.ecDetailsJSON === undefined) {
sessionStorage.ecDetailsJSON = JSON.stringify([]);
}
// display datatables errors in the console instead of in alerts
$.fn.dataTable.ext.errMode = 'throw';
compactorsTable = $('#compactorsTable').DataTable({
"ajax": {
"url": '/rest/ec/compactors',
"dataSrc": "compactors"
},
"stateSave": true,
"dom": 't<"align-left"l>p',
"columnDefs": [{
"targets": "duration",
"render": function (data, type, row) {
if (type === 'display') data = timeDuration(data);
return data;
}
},
{
"targets": "date",
"render": function (data, type, row) {
if (type === 'display') data = dateFormat(data);
return data;
}
}
],
"columns": [{
"data": "server"
},
{
"data": "groupName"
},
{
"data": "lastContact"
}
]
});
const hostnameColumnName = 'hostname';
const queueNameColumnName = 'queueName';
const tableIdColumnName = 'tableId';
const durationColumnName = 'duration';
// Create a table for running compactors
runningTable = $('#runningTable').DataTable({
"ajax": {
"url": '/rest/ec/running',
"dataSrc": "running"
},
"stateSave": true,
"dom": 't<"align-left"l>p',
"columnDefs": [{
"targets": "duration",
"render": function (data, type, row) {
if (type === 'display') data = timeDuration(data);
return data;
}
},
{
"targets": "date",
"render": function (data, type, row) {
if (type === 'display') data = dateFormat(data);
return data;
}
}
],
"columns": [{
"data": "server",
"name": hostnameColumnName
},
{
"data": "kind"
},
{
"data": "status"
},
{
"data": "queueName",
"name": queueNameColumnName
},
{
"data": "tableId",
"name": tableIdColumnName
},
{
"data": "numFiles"
},
{
"data": "progress",
"type": "html",
"render": function (data, type, row, meta) {
if (type === 'display') {
if (row.progress < 0) {
data = '--';
} else {
var p = Math.round(Number(row.progress));
console.log("Compaction progress = %" + p);
data = '<div class="progress"><div class="progress-bar" role="progressbar" style="min-width: 2em; width:' +
p + '%;">' + p + '%</div></div>';
}
}
return data;
}
},
{
"data": "lastUpdate"
},
{
"data": "duration",
"name": durationColumnName
},
{ // more column settings
"class": "details-control",
"orderable": false,
"data": null,
"defaultContent": ""
}
]
});
function handleFilterKeyup(input, feedbackElement, columnName) {
if (isValidRegex(input) || input === '') { // if valid, apply the filter
feedbackElement.hide();
$(this).removeClass('is-invalid');
const isRegex = true;
const smartEnabled = false;
runningTable
.column(`${columnName}:name`)
.search(input, isRegex, smartEnabled)
.draw();
} else { // if invalid, show the warning
feedbackElement.show();
$(this).addClass('is-invalid');
}
}
$('#hostname-filter').on('keyup', function () {
handleFilterKeyup.call(this, this.value, $('#hostname-feedback'), hostnameColumnName);
});
$('#queue-filter').on('keyup', function () {
handleFilterKeyup.call(this, this.value, $('#queue-feedback'), queueNameColumnName);
});
$('#tableid-filter').on('keyup', function () {
handleFilterKeyup.call(this, this.value, $('#tableid-feedback'), tableIdColumnName);
});
$('#duration-filter').on('keyup', function () {
runningTable.draw();
});
// Clear Filters button handler
$('#clear-filters').on('click', function () {
$(this).prop('disabled', true); // disable the clear button
// set the filter inputs to empty and trigger the keyup event to clear the filters
$('#hostname-filter').val('').trigger('keyup');
$('#queue-filter').val('').trigger('keyup');
$('#tableid-filter').val('').trigger('keyup');
$('#duration-filter').val('').trigger('keyup');
$(this).prop('disabled', false); // re-enable the clear
});
// Custom filter function for duration
$.fn.dataTable.ext.search.push(function (settings, data, dataIndex) {
if (settings.nTable.id !== 'runningTable') {
return true;
}
const durationColIndex = runningTable.column(`${durationColumnName}:name`).index();
const durationStr = data[durationColIndex];
const durationSeconds = parseDuration(durationStr);
const input = $('#duration-filter').val().trim();
if (input === '') {
$('#duration-feedback').hide();
return true;
}
const match = validateDurationInput(input);
if (!match) {
$('#duration-feedback').show();
return false;
}
$('#duration-feedback').hide();
const operator = match[1];
const value = parseInt(match[2]);
const unit = match[3];
const filterSeconds = convertToSeconds(value, unit);
switch (operator) {
case '>':
return durationSeconds > filterSeconds;
case '>=':
return durationSeconds >= filterSeconds;
case '<':
return durationSeconds < filterSeconds;
case '<=':
return durationSeconds <= filterSeconds;
default:
console.error(`Unexpected operator "${operator}" encountered in duration filter.`);
return true;
}
});
// Helper function to convert duration strings to seconds
function convertToSeconds(value, unit) {
switch (unit.toLowerCase()) {
case 's':
return value;
case 'm':
return value * 60;
case 'h':
return value * 3600;
case 'd':
return value * 86400;
default:
console.error(`Unexpected unit "${unit}" encountered in duration filter. Defaulting to seconds.`);
return value;
}
}
// Helper function to validate duration input. Makes sure that the input is in the format of '<operator> <value> <unit>'
function validateDurationInput(input) {
return input.match(/^([<>]=?)\s*(\d+)([smhd])$/i);
}
/**
* @param {number} durationStr duration in milliseconds
* @returns duration in seconds
*/
function parseDuration(durationStr) {
// Assuming durationStr is in milliseconds
const milliseconds = parseInt(durationStr, 10);
const seconds = milliseconds / 1000;
return seconds;
}
// Create a table for compaction coordinator
coordinatorTable = $('#coordinatorTable').DataTable({
"ajax": {
"url": '/rest/ec',
"dataSrc": function (data) {
// the data needs to be in an array to work with DataTables
var arr = [];
if (data === undefined) {
console.warn('the value of "data" is undefined');
} else {
arr = [data];
}
return arr;
}
},
"stateSave": true,
"searching": false,
"paging": false,
"info": false,
"columnDefs": [{
"targets": "duration",
"render": function (data, type, row) {
if (type === 'display') data = timeDuration(data);
return data;
}
}],
"columns": [{
"data": "server"
},
{
"data": "numQueues"
},
{
"data": "numCompactors"
},
{
"data": "lastContact"
}
]
});
// Array to track the ids of the details displayed rows
var detailRows = [];
$("#runningTable tbody").on('click', 'tr td.details-control', function () {
var tr = $(this).closest('tr');
var row = runningTable.row(tr);
var idx = $.inArray(tr.attr('id'), detailRows);
if (row.child.isShown()) {
tr.removeClass('details');
row.child.hide();
// Remove from the 'open' array
detailRows.splice(idx, 1);
} else {
var rci = row.data();
var ecid = rci.ecid;
var idSuffix = ecid.substring(ecid.length - 5, ecid.length);
tr.addClass('details');
// put all the information into html for a single row
var htmlRow = "<table class='table table-bordered table-striped table-condensed' id='table" + idSuffix + "'>"
htmlRow += "<thead><tr><th>#</th><th>Input Files</th><th>Size</th><th>Entries</th></tr></thead>";
htmlRow += "<tbody></tbody></table>";
htmlRow += "Output File: <span id='outputFile" + idSuffix + "'></span><br>";
htmlRow += ecid;
row.child(htmlRow).show();
// show the row then populate the table
var ecDetails = getDetailsFromStorage(idSuffix);
if (ecDetails.length === 0) {
getRunningDetails(ecid, idSuffix);
} else {
console.log("Got cached details for " + idSuffix);
populateDetails(ecDetails, idSuffix);
}
// Add to the 'open' array
if (idx === -1) {
detailRows.push(tr.attr('id'));
}
}
});
refreshECTables();
});