mirror of
https://github.com/ntop/ntopng.git
synced 2026-05-06 03:45:26 +00:00
368 lines
12 KiB
JavaScript
368 lines
12 KiB
JavaScript
jQuery.fn.dataTableExt.sErrMode = 'console';
|
|
jQuery.fn.dataTableExt.formatSecondsToHHMMSS = (data, type, row) => {
|
|
if (isNaN(data)) return data;
|
|
if (type == "display" && data <= 0) return ' ';
|
|
if (type == "display") return NtopUtils.secondsToTime(data);
|
|
return data;
|
|
};
|
|
jQuery.fn.dataTableExt.absoluteFormatSecondsToHHMMSS = (data, type, row) => {
|
|
|
|
if (isNaN(data)) return data;
|
|
if (type == "display" && (data <= 0)) return ' ';
|
|
|
|
const delta = Math.floor(Date.now() / 1000) - data;
|
|
if (type == "display") return NtopUtils.secondsToTime(delta);
|
|
return data;
|
|
};
|
|
|
|
class DataTableFiltersMenu {
|
|
|
|
/**
|
|
*
|
|
* @param {options}
|
|
*/
|
|
constructor({tableAPI, filterMenuKey, filterTitle, filters, columnIndex}) {
|
|
|
|
const self = this;
|
|
|
|
this.tableAPI = tableAPI;
|
|
this.filterTitle = filterTitle;
|
|
this.filterMenuKey = filterMenuKey;
|
|
this.columnIndex = columnIndex;
|
|
this.preventUpdate = false;
|
|
this.$datatableWrapper = $(tableAPI.context[0].nTableWrapper);
|
|
|
|
// when the datatable has been initialized render the dropdown
|
|
this.$datatableWrapper.on('init.dt', function() {
|
|
self._render(filters);
|
|
});
|
|
|
|
// on ajax reload then update the datatable entries
|
|
this.tableAPI.on('draw', function() {
|
|
self._update();
|
|
});
|
|
}
|
|
|
|
_countEntries(regex, data = []) {
|
|
|
|
if (regex === undefined) {
|
|
console.error("DataTableFiltersMenu::_countEntries() => the passed regex is undefined!");
|
|
}
|
|
|
|
const reg = new RegExp(regex);
|
|
return data.filter(cellValue => reg.test(cellValue)).length;
|
|
}
|
|
|
|
_createMenuEntry(filter) {
|
|
|
|
const self = this;
|
|
const $entry = $(`<li class='dropdown-item pointer'>${filter.label} </li>`);
|
|
|
|
if (filter.countable === undefined || filter.countable) {
|
|
|
|
const data = this.tableAPI.columns(this.columnIndex).data()[0];
|
|
const count = this._countEntries(filter.regex, data);
|
|
const $counter = $(`<span class='counter'>(${count})</span>`);
|
|
|
|
// if the count is 0 then hide the menu entry
|
|
if (count == 0) $entry.hide();
|
|
|
|
//append the $counter object inside the $entry
|
|
$entry.append($counter);
|
|
}
|
|
|
|
$entry.click(function (e) {
|
|
|
|
self.preventUpdate = true;
|
|
|
|
// set active filter title and key
|
|
if (self.$dropdown.title.parent().find(`i.fas`).length == 0) {
|
|
self.$dropdown.title.parent().prepend(`<i class='fas fa-filter'></i>`);
|
|
}
|
|
|
|
const newContent = $entry.html();
|
|
self.$dropdown.title.html(newContent);
|
|
// remove the active class from the li elements
|
|
self.$dropdown.container.find('li').removeClass(`active`);
|
|
// add active class to current entry
|
|
$entry.addClass(`active`);
|
|
// if the filter have a callback then call it
|
|
if (filter.callback) filter.callback();
|
|
// perform the table filtering
|
|
self.tableAPI.column(self.columnIndex).search(filter.regex, true, false).draw();
|
|
});
|
|
|
|
return $entry;
|
|
}
|
|
|
|
_createFilters(filters) {
|
|
|
|
const filtersCreated = {};
|
|
|
|
// for each filter defined in this.filters
|
|
for (const filter of filters) {
|
|
|
|
const $filter = this._createMenuEntry(filter);
|
|
// save the filter inside the $filters object
|
|
filtersCreated[filter.key] = { filter: filter, $node: $filter };
|
|
}
|
|
|
|
return filtersCreated;
|
|
}
|
|
|
|
_render(filters) {
|
|
|
|
const $dropdownContainer = $(`<div id='${this.filterMenuKey}-filters' class='dropdown d-inline'></div>`);
|
|
const $dropdownButton = $(`<button class='btn-link btn dropdown-toggle' data-toggle='dropdown' type='button'></button>`);
|
|
const $dropdownTitle = $(`<span class='filter-title'>${this.filterTitle}</span>`);
|
|
$dropdownButton.append($dropdownTitle);
|
|
|
|
this.filters = this._createFilters(filters);
|
|
|
|
this.$dropdown = {
|
|
container: $dropdownContainer,
|
|
title: $dropdownTitle,
|
|
button: $dropdownButton
|
|
};
|
|
|
|
const $menuContainer = $(`<ul class='dropdown-menu scrollable-dropdown' id='${this.filterMenuKey}-filter-menu'></ul>`);
|
|
for (const [_, filter] of Object.entries(this.filters)) {
|
|
$menuContainer.append(filter.$node);
|
|
}
|
|
|
|
// the All entry is created by the object
|
|
const allFilter = {
|
|
key: 'all',
|
|
label: i18n.all,
|
|
regex: '',
|
|
countable: false,
|
|
callback: () => {
|
|
this.$dropdown.title.parent().find('i.fas.fa-filter').remove();
|
|
this.$dropdown.title.html(`${this.filterTitle}`);
|
|
}
|
|
};
|
|
|
|
$menuContainer.prepend(this._createMenuEntry(allFilter));
|
|
|
|
// append the created dropdown inside
|
|
$dropdownContainer.append($dropdownButton);
|
|
$dropdownContainer.append($menuContainer);
|
|
// append the dropdown menu inside the filter wrapper
|
|
this.$datatableWrapper.find('.dataTables_filter').prepend($dropdownContainer);
|
|
|
|
this._selectFilterFromState(this.filterMenuKey);
|
|
}
|
|
|
|
_selectFilterFromState(filterKey) {
|
|
|
|
if (!this.tableAPI.state) return;
|
|
if (!this.tableAPI.state.loaded()) return;
|
|
if (!this.tableAPI.state.loaded().filters) return;
|
|
|
|
// save the current table state
|
|
tableAPI.state.save();
|
|
}
|
|
|
|
_update() {
|
|
|
|
// if the filters have not been initialized by _render then return
|
|
if (this.filters === undefined) return;
|
|
if (this.preventUpdate) {
|
|
this.preventUpdate = false;
|
|
return;
|
|
}
|
|
|
|
for (const [_, filter] of Object.entries(this.filters)) {
|
|
if (filter.countable == false) continue;
|
|
|
|
const data = this.tableAPI.columns(this.columnIndex).data()[0];
|
|
const count = this._countEntries(filter.filter.regex, data);
|
|
|
|
// hide the filter if the count is zero
|
|
(count == 0) ? filter.$node.hide() : filter.$node.show();
|
|
// update the counter label
|
|
filter.$node.find('.counter').text(`(${count})`);
|
|
// update the selected button counter
|
|
this.$dropdown.button.find('.counter').text(`(${count})`);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
class DataTableUtils {
|
|
|
|
/**
|
|
* Return a standard config for the Sprymedia (c) DataTables
|
|
*/
|
|
static getStdDatatableConfig(dtButtons = [], dom = "<'d-flex'<'mr-auto'l><'dt-search'f>B>rtip") {
|
|
return {
|
|
dom: dom,
|
|
pagingType: 'full_numbers',
|
|
lengthMenu: [[10, 25, 50, -1], [10, 25, 50, `${i18n.all}`]],
|
|
language: {
|
|
info: i18n.showing_x_to_y_rows,
|
|
search: i18n.script_search,
|
|
infoFiltered: "",
|
|
paginate: {
|
|
previous: '<',
|
|
next: '>',
|
|
first: '«',
|
|
last: '»'
|
|
}
|
|
},
|
|
saveState: true,
|
|
buttons: {
|
|
buttons: dtButtons,
|
|
dom: {
|
|
button: {
|
|
className: 'btn btn-link'
|
|
},
|
|
container: {
|
|
className: 'border-left ml-1 float-right'
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Example of action:
|
|
* {
|
|
* class: string,
|
|
* data: object,
|
|
* icon: string,
|
|
* modal: string,
|
|
* href: string,
|
|
* hidden: bool,
|
|
* }
|
|
* @param {*} actions
|
|
*/
|
|
static createActionButtons(actions = []) {
|
|
|
|
const buttons = [];
|
|
actions.forEach((action) => {
|
|
|
|
let button = (`
|
|
<a
|
|
href='${action.href || action.modal}'
|
|
${action.modal ? "data-toggle='modal'" : ""}
|
|
class='btn btn-sm ${action.class}'
|
|
${action.hidden ? "style='display: none'" : ''}
|
|
>
|
|
<i class='fas ${action.icon}'></i>
|
|
</a>
|
|
`);
|
|
|
|
buttons.push(button);
|
|
});
|
|
|
|
return (`<div class='actions-group' role='group'>${buttons.join('')}</div>`);
|
|
}
|
|
|
|
static setAjaxConfig(config, url, dataSrc = '', method = "get", params = {}) {
|
|
|
|
config.ajax = {
|
|
url: url,
|
|
type: method,
|
|
dataSrc: dataSrc,
|
|
data: function (d) {
|
|
return $.extend({}, d, params);
|
|
}
|
|
}
|
|
|
|
return config;
|
|
}
|
|
|
|
static extendConfig(config, extension) {
|
|
|
|
// if there are custom filters then manage state in this way
|
|
if (extension.hasFilters) {
|
|
|
|
extension.stateSaveCallback = function (settings, data) {
|
|
localStorage.setItem('DataTables_' + settings.sInstance, JSON.stringify(data))
|
|
};
|
|
|
|
extension.stateLoadCallback = function (settings) {
|
|
return JSON.parse(localStorage.getItem('DataTables_' + settings.sInstance));
|
|
};
|
|
|
|
// on saving the table state store the selected filters
|
|
extension.stateSaveParams = function (settings, data) {
|
|
|
|
// save the filters selected from the user inside the state
|
|
$('[data-filter]').each(function () {
|
|
|
|
const activeFilter = $(this).find(`li.active`).data('filter-key');
|
|
if (!activeFilter) return;
|
|
|
|
// if the filters object is not allocated then initizializes it
|
|
if (!data.filters) data.filters = {};
|
|
data.filters[$(this).data('filter')] = activeFilter;
|
|
|
|
});
|
|
};
|
|
}
|
|
|
|
return $.extend({}, config, extension);
|
|
}
|
|
|
|
/**
|
|
* Format the passed seconds into the "HH:MM:SS" string.
|
|
* @param {number} seconds
|
|
*/
|
|
static secondsToHHMMSS(seconds) {
|
|
|
|
const padZeroes = n => `${n}`.padStart(2, '0');
|
|
|
|
const sec = seconds % 60;
|
|
const mins = Math.floor(seconds / 60) % 60;
|
|
const hours = Math.floor(seconds / 3600);
|
|
|
|
return `${padZeroes(hours)}:${padZeroes(mins)}:${padZeroes(sec)}`;
|
|
}
|
|
|
|
/**
|
|
* Open the pool edit modal of a chosen pool if the query params contains the pool paramater
|
|
* @param tableAPI
|
|
*/
|
|
static openEditModalByQuery(params) {
|
|
|
|
const urlParams = new URLSearchParams(window.location.search);
|
|
if (!urlParams.has(params.paramName)) return;
|
|
|
|
const dataID = urlParams.get(params.paramName);
|
|
const data = params.datatableInstance.data().toArray().find((data => data[params.paramName] == dataID));
|
|
|
|
// if the cancelIf param has been passed
|
|
// then test the cancelIf function, if the return value
|
|
// is true then cancel the modal opening
|
|
if (typeof(params.cancelIf) === 'function') {
|
|
if (params.cancelIf(data)) return;
|
|
}
|
|
|
|
const $modal = $(`#${params.modalHandler.getModalID()}`);
|
|
|
|
// if the pool id is valid then open the edit modal
|
|
if (data !== undefined) {
|
|
params.modalHandler.invokeModalInit(data);
|
|
$modal.modal('show');
|
|
}
|
|
|
|
if (!urlParams.has('referer')) {
|
|
$modal.on('hidden.bs.modal', function (e) {
|
|
|
|
const url = new URL(window.location.href);
|
|
url.searchParams.delete(params.paramName);
|
|
|
|
history.replaceState({}, '', url.toString());
|
|
});
|
|
return;
|
|
}
|
|
const referer = urlParams.get('referer');
|
|
|
|
$modal.on('hidden.bs.modal', function (e) {
|
|
window.location = referer;
|
|
});
|
|
}
|
|
|
|
}
|