mirror of
https://github.com/ntop/ntopng.git
synced 2026-04-30 16:09:32 +00:00
2354 lines
73 KiB
Text
2354 lines
73 KiB
Text
<div class="row">
|
|
<div class="col-md-12 col-lg-12">
|
|
<div class="alert alert-danger d-none" id='alert-row-buttons' role="alert">
|
|
</div>
|
|
<div class="card">
|
|
{% if isEmptyString(script_list.search_filter) then %}
|
|
<div class="card-header">
|
|
<ul class="nav nav-tabs card-header-tabs">
|
|
<li class="nav-item">
|
|
<a id="all-scripts" class="nav-link filter-scripts-button" href="#all">{{ i18n("all") }}</a>
|
|
</li>
|
|
<li class="nav-item">
|
|
<a id="enabled-scripts" class="nav-link filter-scripts-button" href="#enabled">{{ i18n("enabled") }}</a>
|
|
</li>
|
|
<li class="nav-item">
|
|
<a id ="disabled-scripts" class="nav-link filter-scripts-button" href="#disabled">{{ i18n("disabled") }}</a>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
{% end %}
|
|
<div class="card-body">
|
|
<table id="scripts-config" class="table w-100 table-striped table-hover table-bordered mt-3">
|
|
<thead>
|
|
<tr>
|
|
<th></th>
|
|
<th>{{ i18n("name", {}) }}</th>
|
|
<th>{{ i18n("interface", {}) }}</th>
|
|
<th>{{ i18n("category", {}) }}</th>
|
|
<th>{{ i18n("severity", {}) }}</th>
|
|
<th>{{ i18n("description", {}) }}</th>
|
|
<th>{{ i18n("values", {}) }}</th>
|
|
<th>{{ i18n("action", {})}}</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody></tbody>
|
|
</table>
|
|
</div>
|
|
{% if isEmptyString(script_list.search_filter) then %}
|
|
<div class="card-footer">
|
|
|
|
<button id='btn-disable-all' disabled class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#disable-all-modal">
|
|
<i class='fas fa-toggle-off'></i> {{ i18n("checks.disable_all") }}</button>
|
|
|
|
{% if script_list.check_subdir == "all" then %}
|
|
<button id='btn-factory-reset' class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#factory-reset-modal">
|
|
<i class='fas fa-undo-alt'></i> {{ i18n("factory_reset") }}</button>
|
|
{% end %}
|
|
</div>
|
|
{% end %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class='notes bg-light border'>
|
|
<b>{{ i18n('notes') }}</b>
|
|
<ul>
|
|
<li> {{ i18n('checks.categories') }}
|
|
<ul>
|
|
{% for _, cat in pairsByKeys(check_categories) do %}
|
|
<li> {* string.format("<i class='fa %s'></i> %s: %s", cat.icon, i18n(cat.i18n_title, {product=info.product}),
|
|
i18n(cat.i18n_descr, {product=info.product})) *} </li>
|
|
{% end %}
|
|
</ul>
|
|
</li>
|
|
<li> {{ i18n('interface') }}
|
|
<ul>
|
|
<li> {* string.format("<i class='fa fa-ethernet'></i>: %s", i18n("scripts_list.note_packet_interface")) *} </li>
|
|
<li> {* string.format("<i class='fa fa-bezier-curve'></i>: %s", i18n("scripts_list.note_zmq_interface")) *} </li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
|
|
{*
|
|
script_list.template_utils.gen("modal_confirm_dialog.html", {
|
|
dialog={
|
|
id = "disable-all-modal",
|
|
message = i18n('checks.disable_all_message'),
|
|
title = i18n('checks.disable_all_checks'),
|
|
confirm = i18n("checks.disable_all"),
|
|
custom_alert_class = 'alert alert-danger',
|
|
confirm_button = 'btn-danger',
|
|
},
|
|
})
|
|
*}
|
|
|
|
{*
|
|
script_list.template_utils.gen("modal_confirm_dialog.html", {
|
|
dialog={
|
|
id = "factory-reset-modal",
|
|
message = i18n('checks.factory_reset_all_message'),
|
|
title = i18n('checks.factory_reset_all_checks'),
|
|
confirm = i18n("factory_reset"),
|
|
custom_alert_class = 'alert alert-danger',
|
|
confirm_button = 'btn-danger',
|
|
},
|
|
})
|
|
*}
|
|
|
|
|
|
{# include modals for edit_configset.lua #}
|
|
{* script_list.template_utils.gen("pages/modals/edit_configset/edit_config_modal.html", {
|
|
subdir = script_list.check_subdir,
|
|
}) *}
|
|
{# add css, js files #}
|
|
<script type="text/javascript">
|
|
|
|
check_subdir = "{{ script_list.check_subdir }}";
|
|
|
|
const scripts_categories = [
|
|
{
|
|
label: "{{ i18n('scripts_list.all') }}",
|
|
disableFilter: true
|
|
},
|
|
{% for _, cat in pairsByKeys(check_categories) do %}
|
|
{
|
|
label: "{{ i18n(cat.i18n_title) }}",
|
|
disableFilter: false
|
|
},
|
|
{% end %}
|
|
];
|
|
|
|
let pageCsrf = "{{ ntop.getRandomCSRFValue() }}";
|
|
const script_search_filter = "{{ script_list.search_filter }}";
|
|
let script_key_filter = "{{ script_list.script_filter }}";
|
|
let page_url = "{* script_list.page_url *}";
|
|
let apps_and_categories = {* script_list.apps_and_categories *};
|
|
let device_types = {* script_list.device_types *};
|
|
|
|
i18n_ext.all = '{{ i18n("all", {}) }}';
|
|
i18n_ext.enabled = '{{ i18n("enabled", {}) }}';
|
|
i18n_ext.disabled = '{{ i18n("disabled", {}) }}';
|
|
i18n_ext.request_failed_message = '{{ i18n("request_failed_message") }}';
|
|
i18n_ext.select_operator = "{{ i18n('scripts_list.select_operator') }}";
|
|
i18n_ext.empty_input_box = "{{ i18n('config_scripts.empty_value_message') }}";
|
|
i18n_ext.template_not_found = "{{ i18n('scripts_list.template_not_found') }}";
|
|
i18n_ext.view = "{{ i18n('scripts_list.actions.view') }}";
|
|
i18n_ext.view_src_script = "{{ i18n('scripts_list.actions.view_src_script') }}";
|
|
i18n_ext.edit = "{{ i18n('scripts_list.actions.edit') }}";
|
|
i18n_ext.edit_script = "{{ i18n('scripts_list.actions.edit_script') }}";
|
|
i18n_ext.items_list_comma = "{{ i18n('scripts_list.items_list_comma') }}";
|
|
i18n_ext.blacklisted_country = "{{ i18n('scripts_list.blacklisted_country') }}";
|
|
i18n_ext.expired_csrf = "{{ i18n('expired_csrf') }}";
|
|
i18n_ext.filter_categories = "{{ i18n('scripts_list.filter_dropdown') }}";
|
|
i18n_ext.showing_x_to_y_rows = "{{ i18n('showing_x_to_y_rows', {x='_START_', y='_END_', tot='_TOTAL_'}) }}";
|
|
i18n_ext.script_search = "{{ i18n('scripts_list.script_search') }}";
|
|
i18n_ext.enable_check_title = "{{ i18n("enable_check_title")}}";
|
|
i18n_ext.disable_check_title = "{{ i18n("disable_check_title")}}";
|
|
i18n_ext.edit_check_title = "{{ i18n("edit_check_title")}}";
|
|
i18n_ext.scripts_list = {};
|
|
i18n_ext.scripts_list.templates = {};
|
|
i18n_ext.scripts_list.templates.excluded_applications = "{{ i18n('scripts_list.templates.excluded_applications') }}";
|
|
i18n_ext.scripts_list.templates.flow_duration_threshold = "{{ i18n('scripts_list.templates.flow_duration_threshold') }}";
|
|
i18n_ext.scripts_list.templates.elephant_flows_l2r = "{{ i18n('scripts_list.templates.elephant_flows_l2r') }}";
|
|
i18n_ext.scripts_list.templates.elephant_flows_r2l = "{{ i18n('scripts_list.templates.elephant_flows_r2l') }}";
|
|
i18n_ext.scripts_list.templates.template_not_implemented = "{{ i18n('scripts_list.templates.template_not_implemented') }}";
|
|
i18n_ext.scripts_list.templates.blacklisted_country_list = "{{ i18n('scripts_list.templates.blacklisted_country_list') }}";
|
|
|
|
i18n_ext.enable = "{{ i18n('show_alerts.enable_alerts') }}";
|
|
i18n_ext.disable = "{{ i18n('show_alerts.disable_alerts') }}";
|
|
|
|
i18n_ext.metrics = {};
|
|
i18n_ext.metrics.minutes = "{{ i18n('metrics.minutes') }}";
|
|
i18n_ext.metrics.hours = "{{ i18n('metrics.hours') }}";
|
|
i18n_ext.metrics.days = "{{ i18n('metrics.days') }}";
|
|
|
|
i18n_ext.values = "{{ i18n('values', {}) }}";
|
|
i18n_ext.rest = {* json.encode(i18n('rest_consts')) *};
|
|
|
|
String.prototype.titleCase = function () {
|
|
|
|
return this.toLowerCase().split(' ').map(function (word) {
|
|
return word.replace(word[0], word[0].toUpperCase());
|
|
}).join(' ');
|
|
|
|
}
|
|
|
|
/* ******************************************************* */
|
|
|
|
const reloadPageAfterPOST = () => {
|
|
if (location.href.indexOf("check=") > 0) {
|
|
/* Go back to the alerts page */
|
|
//location.href = page_url + location.hash;
|
|
window.history.back();
|
|
} else {
|
|
/* The URL is still the same as before, need to force a reload */
|
|
location.reload();
|
|
}
|
|
}
|
|
|
|
/* ******************************************************* */
|
|
|
|
const hasConfigDialog = (item) => {
|
|
return !(item.all_hooks.length > 0 && item.input_handler == undefined);
|
|
}
|
|
|
|
/* ******************************************************* */
|
|
|
|
/**
|
|
* This function select the correct tab for script filtering
|
|
*/
|
|
const select_script_filter = (enabled_count) => {
|
|
|
|
// get hash from url
|
|
let hash = window.location.hash;
|
|
|
|
if (hash == undefined || hash == null || hash == "") {
|
|
// if no tab is active, show the "enabled" tab if there are any enabled
|
|
// scripts, otherwise show the "all-scripts" tab
|
|
hash = enabled_count ? '#enabled' : '#all-scripts';
|
|
}
|
|
|
|
// redirect to correct tab
|
|
if (hash == "#enabled") {
|
|
$(`#enabled-scripts`).addClass("active").trigger("click");
|
|
}
|
|
else if (hash == "#disabled") {
|
|
$(`#disabled-scripts`).addClass("active").trigger("click");
|
|
}
|
|
else {
|
|
$(`#all-scripts`).addClass("active").trigger("click");
|
|
}
|
|
}
|
|
|
|
/* ******************************************************* */
|
|
|
|
// Templates and template builder
|
|
|
|
const generate_checkbox_enabled = (id, enabled, callback) => {
|
|
|
|
const $checkbox_enabled = $(`
|
|
<div class="form-switch"">
|
|
<input
|
|
id='${id}'
|
|
name='enabled'
|
|
class="form-check-input ms-0"
|
|
type="checkbox"
|
|
${enabled ? "checked" : ""} />
|
|
<label class="form-check-label" for="${id}"></label>
|
|
</div>
|
|
`);
|
|
|
|
// bind check event on checkboxes
|
|
$checkbox_enabled.find(`input[type='checkbox']`).change(callback);
|
|
|
|
return $checkbox_enabled;
|
|
}
|
|
|
|
/* ******************************************************* */
|
|
|
|
/**
|
|
* Generate a multi select with groups
|
|
*/
|
|
const generate_multi_select = (params, has_container = true) => {
|
|
|
|
const $select = $(`<select id='multiple-select' style="height: 10rem" multiple class='form-select'></select>`);
|
|
|
|
// add groups and items
|
|
if (params.groups.length == 1) {
|
|
|
|
params.groups[0].elements.forEach((element) => {
|
|
$select.append($(`<option value='${element[0]}'>${element[1]}</option>`))
|
|
});
|
|
}
|
|
else {
|
|
|
|
params.groups.forEach((category) => {
|
|
|
|
const $group = $(`<optgroup label='${category.label}'></optgroup>`);
|
|
category.elements.forEach((element) => {
|
|
$group.append($(`<option value='${element[0]}'>${element[1]}</option>`))
|
|
});
|
|
|
|
$select.append($group);
|
|
});
|
|
}
|
|
|
|
// add attributes
|
|
if (params.name != undefined) $select.attr('name', params.name);
|
|
if (params.enabled != undefined && !params.enabled) $select.attr('disabled', '');
|
|
if (params.id != undefined) $select.attr('id', params.id);
|
|
|
|
if (params.selected_values != undefined) {
|
|
$select.val(params.selected_values);
|
|
}
|
|
|
|
if (has_container) {
|
|
return $(`
|
|
<div class='form-group mb-3 ${(params.containerCss || "mt-3")}'>
|
|
<label>${params.label || 'Default Label'}</label>
|
|
</div>
|
|
`).append($select);
|
|
}
|
|
|
|
return $select;
|
|
}
|
|
|
|
|
|
/* ******************************************************* */
|
|
|
|
const generate_input_box = (input_settings, has_container = true) => {
|
|
|
|
const $input_box = $(`<input required type='number' name='${input_settings.name}' class='form-control' />`);
|
|
|
|
// set attributes and values
|
|
if (input_settings.max != undefined) $input_box.attr("max", input_settings.max);
|
|
if (input_settings.min != undefined) $input_box.attr("min", input_settings.min);
|
|
if (input_settings.current_value != undefined) $input_box.val(input_settings.current_value);
|
|
|
|
if (input_settings.enabled != undefined && !input_settings.enabled) {
|
|
$input_box.attr("readonly", "");
|
|
}
|
|
|
|
if (has_container) {
|
|
const $input_container = $(`<div class='row'></div>`);
|
|
return $input_container.append($(`<div class='col-2'></div>`).append($input_box));
|
|
}
|
|
|
|
return $input_box;
|
|
}
|
|
|
|
/* ******************************************************* */
|
|
|
|
const generate_single_select = (params, has_container = true) => {
|
|
|
|
const $select = $(`<select name='${params.name}' class='form-select' />`);
|
|
|
|
if (params.enabled != undefined && !params.enabled) {
|
|
$select.attr("disabled", "");
|
|
}
|
|
|
|
params.elements.forEach((element) => {
|
|
$select.append($(`<option value='${element[0]}'>${element[1]}</option>`))
|
|
});
|
|
|
|
if (params.current_value != undefined) $select.val(params.current_value);
|
|
|
|
if (has_container) {
|
|
const $input_container = $(`<div class='row'></div>`);
|
|
return $input_container.append(
|
|
$(`<div class='col-10'><label class='p-2'>${params.label}</label></div>`),
|
|
$(`<div class='col-2'></div>`).append($select),
|
|
);
|
|
}
|
|
|
|
return $input_box;
|
|
}
|
|
|
|
/* ******************************************************* */
|
|
|
|
const generate_textarea = (textarea_settings) => {
|
|
|
|
const $textarea = $(`
|
|
<div class='form-group mb-3 mt-3'>
|
|
<label class='pl-2'>${textarea_settings.label}</label>
|
|
<textarea ${textarea_settings.class}
|
|
${textarea_settings.enabled ? '' : 'readonly'}
|
|
name='${textarea_settings.name}'
|
|
placeholder='${textarea_settings.placeholder}'
|
|
class='form-control ms-2'>${textarea_settings.value}</textarea>
|
|
<div class="invalid-feedback"></div>
|
|
</div>
|
|
`);
|
|
|
|
return $textarea;
|
|
};
|
|
|
|
|
|
/* ******************************************************* */
|
|
|
|
const generate_radio_buttons = (params, has_container = true) => {
|
|
const active_first_button = params.granularity.labels[0] == params.granularity.label;
|
|
const active_second_button = params.granularity.labels[1] == params.granularity.label;
|
|
const active_third_button = params.granularity.labels[2] == params.granularity.label;
|
|
|
|
let $radio_buttons = $(`
|
|
<div class="btn-group float-end btn-group-toggle" data-bs-toggle="buttons">
|
|
<input
|
|
${params.enabled ? '' : 'disabled'}
|
|
${active_first_button ? 'checked' : ''}
|
|
value='${params.granularity.values[0]}'
|
|
id="first_button_${params.name}"
|
|
type="radio"
|
|
class="btn-check"
|
|
autocomplete="off"
|
|
name="${params.name}">
|
|
<label class="btn ${active_first_button ? 'active btn-primary' : 'btn-secondary'} ${params.enabled ? '' : 'disabled'}" for="first_button_${params.name}">
|
|
${params.granularity.labels[0]} </label>
|
|
|
|
<input
|
|
${params.enabled ? '' : 'disabled'}
|
|
${active_second_button ? 'checked' : ''}
|
|
value='${params.granularity.values[1]}'
|
|
id="second_button_${params.name}"
|
|
type="radio"
|
|
class="btn-check"
|
|
autocomplete="off"
|
|
name="${params.name}">
|
|
<label class="btn ${active_second_button ? 'active btn-primary' : 'btn-secondary'} ${params.enabled ? '' : 'disabled'}" for="second_button_${params.name}">
|
|
${params.granularity.labels[1]} </label>
|
|
|
|
<input
|
|
${params.enabled ? '' : 'disabled'}
|
|
${active_third_button ? 'checked' : ''}
|
|
value='${params.granularity.values[2]}'
|
|
type="radio"
|
|
id="third_button_${params.name}"
|
|
class="btn-check"
|
|
autocomplete="off"
|
|
name="${params.name}">
|
|
<label class="btn ${active_third_button ? 'active btn-primary' : 'btn-secondary'} ${params.enabled ? '' : 'disabled'}" for="third_button_${params.name}">
|
|
${params.granularity.labels[2]}
|
|
</label>
|
|
</div>
|
|
`);
|
|
|
|
$radio_buttons.find(`label`).on('click', function (e) {
|
|
// Remove active class from every button
|
|
$radio_buttons.find('label').removeClass('active').removeClass('btn-primary').addClass('btn-secondary');
|
|
|
|
// Remove checked from buttons
|
|
const checked_input_id = $(this).attr('for');
|
|
const checked_input = $("#" + checked_input_id);
|
|
|
|
// Add attribute checked to the input associated to this label
|
|
checked_input.attr('checked', '');
|
|
// Set the right classes to this active label
|
|
$(this).addClass('active btn-primary').removeClass('btn-secondary');
|
|
});
|
|
|
|
if (has_container) {
|
|
|
|
const $radio_container = $(`<div class='col-3'></div>`);
|
|
return $radio_container.append($radio_buttons);
|
|
}
|
|
|
|
return $radio_buttons;
|
|
}
|
|
|
|
/* ******************************************************* */
|
|
|
|
const reset_radio_button = (name, value) => {
|
|
|
|
$(`input[name='${name}']`)
|
|
.removeAttr('checked')
|
|
.parent()
|
|
.removeClass('btn-primary')
|
|
.removeClass('active')
|
|
.addClass('btn-secondary');
|
|
|
|
$(`input[name='${name}'][value='${value}']`)
|
|
.attr('checked', '')
|
|
.parent()
|
|
.toggleClass('btn-secondary')
|
|
.toggleClass('btn-primary')
|
|
.toggleClass('active');
|
|
}
|
|
|
|
/* ******************************************************* */
|
|
|
|
const get_unit_bytes = (bytes) => {
|
|
|
|
if (bytes < 1048576 || bytes == undefined || bytes == null) {
|
|
return ["KB", bytes / 1024, 1024];
|
|
}
|
|
else if (bytes >= 1048576 && bytes < 1073741824) {
|
|
return ["MB", bytes / 1048576, 1048576];
|
|
}
|
|
else {
|
|
return ["GB", bytes / 1073741824, 1073741824];
|
|
}
|
|
|
|
};
|
|
|
|
/* ******************************************************* */
|
|
|
|
const get_unit_times = (seconds) => {
|
|
|
|
if (seconds < 3600 || seconds == undefined || seconds == null) {
|
|
return [`${i18n_ext.metrics.minutes}`, seconds / 60, 60];
|
|
}
|
|
else if (seconds >= 3600 && seconds < 86400) {
|
|
return [`${i18n_ext.metrics.hours}`, seconds / 3600, 3600];
|
|
}
|
|
else if (seconds >= 86400) {
|
|
return [`${i18n_ext.metrics.days}`, seconds / 86400, 86400];
|
|
}
|
|
|
|
};
|
|
|
|
/* ******************************************************* */
|
|
|
|
const apply_edits_script = (template_data, check_subdir, script_key) => {
|
|
|
|
const $apply_btn = $('#btn-apply');
|
|
const $error_label = $("#apply-error");
|
|
|
|
// remove dirty class from form
|
|
$('#edit-form').removeClass('dirty')
|
|
$apply_btn.attr('disabled', '');
|
|
|
|
$.post(`${http_prefix}/lua/edit_check_config.lua`, {
|
|
check_subdir: check_subdir,
|
|
script_key: script_key,
|
|
csrf: pageCsrf,
|
|
JSON: JSON.stringify(template_data)
|
|
})
|
|
.done((d, status, xhr) => {
|
|
|
|
if (NtopUtils.check_status_code(xhr.status, xhr.statusText, $error_label)) return;
|
|
|
|
if (!d.success) {
|
|
|
|
$error_label.text(d.error).show();
|
|
// re enable button
|
|
$apply_btn.removeAttr('disabled');
|
|
}
|
|
|
|
// if the operation was successfull then reload the page
|
|
if (d.success) reloadPageAfterPOST();
|
|
})
|
|
.fail(({ status, statusText }, a, b) => {
|
|
|
|
NtopUtils.check_status_code(status, statusText, $error_label);
|
|
|
|
if (status == 200) {
|
|
$error_label.text(`${i18n_ext.expired_csrf}`).show();
|
|
}
|
|
|
|
$apply_btn.removeAttr('disabled');
|
|
});
|
|
}
|
|
|
|
const reset_script_defaults = (script_key, check_subdir, callback_reset) => {
|
|
|
|
const $error_label = $('#apply-error');
|
|
|
|
$.get(`${http_prefix}/lua/get_check_config.lua`, {
|
|
check_subdir: check_subdir,
|
|
script_key: script_key,
|
|
factory: 'true'
|
|
})
|
|
.done((reset_data, status, xhr) => {
|
|
|
|
// if there is an error about the http request
|
|
if (NtopUtils.check_status_code(xhr.status, xhr.statusText, $error_label)) return;
|
|
|
|
const { metadata } = reset_data;
|
|
|
|
// call callback function to reset fields
|
|
callback_reset(reset_data);
|
|
|
|
// add dirty class to form
|
|
$('#edit-form').addClass('dirty');
|
|
})
|
|
.fail(({ status, statusText }) => {
|
|
|
|
NtopUtils.check_status_code(status, statusText, $error_label);
|
|
// hide modal if there is error
|
|
$("#modal-script").modal("toggle");
|
|
})
|
|
}
|
|
|
|
/* ******************************************************* */
|
|
|
|
// TEMPALTES:
|
|
|
|
const ThresholdCross = (gui, hooks, check_subdir, script_key) => {
|
|
|
|
const $table_editor = $("#script-config-editor");
|
|
|
|
const render_select_operator = (operators, key, hook) => {
|
|
|
|
const $select = $(`
|
|
<select
|
|
name='${key}-select'
|
|
required
|
|
${hook.enabled ? '' : 'disabled'}
|
|
class='btn btn-outline-secondary'></select>
|
|
`);
|
|
|
|
operators.forEach((op) => {
|
|
$select.append($(`<option value="${op}">&${op}</option>`));
|
|
});
|
|
|
|
// select the right operator
|
|
if (hook.script_conf.operator != undefined) {
|
|
$select.val(hook.script_conf.operator)
|
|
}
|
|
|
|
return $select;
|
|
}
|
|
|
|
const render_template = () => {
|
|
const { field_operator, fields_unit, field_min, field_max } = gui;
|
|
const operators = ['gt', 'lt'];
|
|
|
|
// save input fields
|
|
const $input_fields = {};
|
|
|
|
// iterate over keys to create each hooks
|
|
for (const key in hooks) {
|
|
|
|
if (key == undefined) continue;
|
|
|
|
// get hook
|
|
const hook = hooks[key];
|
|
|
|
let $select = null;
|
|
if (field_operator == undefined) {
|
|
$select = render_select_operator(operators, key, hook);
|
|
}
|
|
else {
|
|
$select = $(`<span class='input-group-text'>&${field_operator}</span>`).data('value', field_operator);
|
|
}
|
|
|
|
const $field = $(`<div class='input-group template'></div>`);
|
|
$field.append($select);
|
|
$field.append(`<input
|
|
type='number'
|
|
class='form-control text-end'
|
|
required
|
|
style='max-width: 7rem;'
|
|
name='${key}-input'
|
|
${hook.enabled ? '' : 'readonly'}
|
|
value='${hook.script_conf.threshold == undefined ? '' : hook.script_conf.threshold}'
|
|
min='${field_min == undefined ? '' : field_min}'
|
|
max='${field_max == undefined ? '' : field_max}'>`);
|
|
$field.append(`<span class='mt-auto mb-auto ms-2 me-2'>${fields_unit ? fields_unit : ""}</span>`);
|
|
$field.append(`<div class='invalid-feedback'></div>`);
|
|
|
|
const $input_container = $(`<tr id='${key}'></tr>`);
|
|
const $checkbox = $(`
|
|
<div class="form-switch">
|
|
<input class="form-check-input ms-0" id="id-${key}-check" name="${key}-check" type="checkbox" ${hook.enabled ? "checked" : ""} >
|
|
<label class="form-check-label" for="id-${key}-check"></label>
|
|
</div>
|
|
`);
|
|
|
|
// bind check event on checkboxes
|
|
$checkbox.find(`input[type='checkbox']`).change(function (e) {
|
|
|
|
const checked = $(this).prop('checked');
|
|
|
|
// if the checked option is false the disable the elements
|
|
if (!checked) {
|
|
$field.find(`input[type='number']`).attr("readonly", "");
|
|
$select.attr("disabled", "");
|
|
return;
|
|
}
|
|
|
|
$field.find(`input[type='number']`).removeAttr("readonly");
|
|
$select.removeAttr("disabled");
|
|
});
|
|
|
|
// append label and checkbox inside the row
|
|
$input_container.append(
|
|
$(`<td class='text-center align-middle'></td>`).append($checkbox),
|
|
$(`<td class='align-middle'>${hook.label ? hook.label.titleCase() : ""}</td>`),
|
|
$(`<td></td>`).append($field)
|
|
);
|
|
|
|
// save input field
|
|
$input_fields[key] = $input_container;
|
|
}
|
|
|
|
// clean script editor table from previous state
|
|
$table_editor.empty();
|
|
|
|
// append each hooks to the table
|
|
$table_editor.append(`<tr><th class='text-center'>${i18n_ext.enabled}</th></tr>`)
|
|
|
|
if ("min" in $input_fields) {
|
|
$table_editor.append($input_fields['min']);
|
|
delete $input_fields['min'];
|
|
}
|
|
if ("5mins" in $input_fields) {
|
|
$table_editor.append($input_fields['5mins']);
|
|
delete $input_fields['5mins'];
|
|
}
|
|
if ("hour" in $input_fields) {
|
|
$table_editor.append($input_fields['hour']);
|
|
delete $input_fields['hour'];
|
|
}
|
|
if ("day" in $input_fields) {
|
|
$table_editor.append($input_fields['day']);
|
|
delete $input_fields['day'];
|
|
}
|
|
|
|
let other_keys = [];
|
|
|
|
for (let key in $input_fields) other_keys.push(key);
|
|
|
|
/* Guarantees the sort order */
|
|
other_keys.sort();
|
|
|
|
$.each(other_keys, function (idx, item) {
|
|
$table_editor.append($input_fields[item]);
|
|
});
|
|
|
|
};
|
|
|
|
const apply_event = (event) => {
|
|
// prepare request to save config
|
|
const data = {};
|
|
|
|
// iterate over granularities
|
|
$table_editor.find("tr[id]").each(function (index) {
|
|
|
|
const id = $(this).attr("id");
|
|
|
|
$(this).find("input").each(function(index) {
|
|
debugger
|
|
})
|
|
const enabled = $(this).find("input[type='checkbox']").is(":checked");
|
|
const $template = $(this).find(".template");
|
|
const $error_label = $template.find(`.invalid-feedback`);
|
|
|
|
let operator = $template.find("select").val();
|
|
// if operator is undefined it means there isn't any select, so take the value from span
|
|
if (operator == undefined) {
|
|
operator = $template.find('span.input-group-text').data('value');
|
|
}
|
|
|
|
const $input_box = $template.find("input");
|
|
|
|
let threshold = parseInt($input_box.val());
|
|
|
|
// hide before errors
|
|
$error_label.hide();
|
|
|
|
// remove class error
|
|
$input_box.removeClass('is-invalid');
|
|
// save data into dictonary
|
|
data[id] = {
|
|
'enabled': enabled,
|
|
'script_conf': {
|
|
'operator': operator,
|
|
'threshold': parseInt(threshold)
|
|
}
|
|
}
|
|
});
|
|
|
|
apply_edits_script(data, check_subdir, script_key);
|
|
};
|
|
|
|
const reset_event = (event) => {
|
|
|
|
reset_script_defaults(script_key, check_subdir, (data) => {
|
|
|
|
const { hooks } = data;
|
|
|
|
// reset default values
|
|
for (key in hooks) {
|
|
|
|
const granularity = hooks[key];
|
|
|
|
$(`input[name='${key}-check']`).prop('checked', granularity.enabled);
|
|
|
|
if (granularity.script_conf.threshold === undefined) {
|
|
$(`input[name='${key}-input']`).val('');
|
|
}
|
|
else {
|
|
$(`input[name='${key}-input']`).val(granularity.script_conf.threshold);
|
|
}
|
|
|
|
if (granularity.enabled) {
|
|
$(`select[name='${key}-select']`).removeAttr("disabled");
|
|
$(`input[name='${key}-input']`).removeAttr("readonly");
|
|
}
|
|
else {
|
|
$(`input[name='${key}-input']`).attr("readonly", "");
|
|
$(`select[name='${key}-select']`).attr("disabled", "");
|
|
}
|
|
|
|
$(`select[name='${key}-select']`).val(granularity.script_conf.operator);
|
|
|
|
}
|
|
});
|
|
|
|
}
|
|
|
|
return {
|
|
apply_click_event: apply_event,
|
|
reset_click_event: reset_event,
|
|
render: render_template,
|
|
}
|
|
}
|
|
|
|
/* ********************************* */
|
|
|
|
/* Multi Threshold cross template, used to set multiple threshold cross.
|
|
* e.g.: tcp retransmissions > 4% and out of order packets > 5%
|
|
*/
|
|
const MultiThresholdCross = (gui, metadata, hooks, check_subdir, script_key) => {
|
|
const $table_editor = $("#script-config-editor");
|
|
const render_select_operator = (operators, key, hook) => {
|
|
|
|
const $select = $(`
|
|
<select
|
|
name='${key}-select'
|
|
required
|
|
${hook.enabled ? '' : 'disabled'}
|
|
class='btn btn-outline-secondary'></select>
|
|
`);
|
|
|
|
operators.forEach((op) => {
|
|
$select.append($(`<option value="${op}">&${op}</option>`));
|
|
});
|
|
|
|
// select the right operator
|
|
if (hook.script_conf.operator != undefined) {
|
|
$select.val(hook.script_conf.operator)
|
|
}
|
|
|
|
return $select;
|
|
}
|
|
|
|
const render_template = () => {
|
|
const operators = ['gt', 'lt'];
|
|
|
|
// clean script editor table from previous state
|
|
$table_editor.empty();
|
|
// append each hooks to the table
|
|
$table_editor.append(`<tr>
|
|
<th class="col-2" style="padding-left: 22px!important;">${i18n('options')}</th>
|
|
<th class="col-3 text-center align-middle">${i18n('enabled')}</th>
|
|
<th>${i18n('threshold')}</th>
|
|
</tr>`)
|
|
|
|
// iterate over keys to create each hooks
|
|
for (const key in hooks) {
|
|
if (key == undefined) continue;
|
|
|
|
// get hook
|
|
const hook = hooks[key];
|
|
for (const field in hook.script_conf) {
|
|
const $field = $(`<div class='input-group template'></div>`);
|
|
let { default_value, field_operator, fields_unit, field_min, field_max, title } = hook.script_conf[field];
|
|
let enabled = hook.script_conf[field]["enabled"]
|
|
|
|
if(enabled == undefined)
|
|
enabled = hook.enabled
|
|
if(default_value == undefined)
|
|
default_value = hook.script_conf[field]["threshold"]
|
|
if(field_operator == undefined)
|
|
field_operator = hook.script_conf[field]["operator"]
|
|
if(fields_unit == undefined)
|
|
fields_unit = metadata.default_value[field].i18n_fields_unit
|
|
if(field_min == undefined)
|
|
field_min = metadata.default_value[field].field_min
|
|
if(field_max == undefined)
|
|
field_max = metadata.default_value[field].field_max
|
|
if(title == undefined)
|
|
title = metadata.default_value[field].title
|
|
|
|
let $select = null;
|
|
|
|
if (field_operator == undefined) {
|
|
$select = render_select_operator(operators, key, hook);
|
|
} else {
|
|
$select = $(`<span class='input-group-text'>&${field_operator}</span>`).data('value', field_operator);
|
|
}
|
|
|
|
const $title = `<span class='mt-auto mb-auto ms-2 me-2'>${title ? title : ""}</span>`;
|
|
|
|
$field.append($select);
|
|
$field.append(`<input
|
|
type='number'
|
|
class='form-control text-end'
|
|
required
|
|
style='max-width: 7rem;'
|
|
name='${key}-${field}-input'
|
|
${enabled ? '' : 'readonly'}
|
|
value='${default_value == undefined ? '' : default_value}'
|
|
min='${field_min == undefined ? '' : field_min}'
|
|
max='${field_max == undefined ? '' : field_max}'>`);
|
|
$field.append(`<span class='mt-auto mb-auto ms-2 me-2'>${i18n(fields_unit) ? i18n(fields_unit) : ""}</span>`);
|
|
$field.append(`<div class='invalid-feedback'></div>`);
|
|
|
|
const $input_container = $(`<tr id='${field}'></tr>`);
|
|
const $checkbox = $(`
|
|
<div class="form-switch">
|
|
<input class="form-check-input ms-0" id="id-${key}-${field}-check" name="${key}-${field}-check" type="checkbox" ${enabled ? "checked" : ""} >
|
|
<label class="form-check-label" for="id-${key}-${field}-check"></label>
|
|
</div>
|
|
`);
|
|
|
|
// bind check event on checkboxes
|
|
$checkbox.find(`input[type='checkbox']`).change(function (e) {
|
|
const checked = $(this).prop('checked');
|
|
// if the checked option is false the disable the elements
|
|
if (!checked) {
|
|
$field.find(`input[type='number']`).attr("readonly", "");
|
|
$select.attr("disabled", "");
|
|
return;
|
|
}
|
|
|
|
$field.find(`input[type='number']`).removeAttr("readonly");
|
|
$select.removeAttr("disabled");
|
|
});
|
|
|
|
// append label and checkbox inside the row
|
|
$input_container.append(
|
|
$(`<td class='align-middle'></td>`).append($title),
|
|
$(`<td class='text-center align-middle'></td>`).append($checkbox),
|
|
$(`<td class='text-center align-middle'></td>`).append($field)
|
|
);
|
|
|
|
$table_editor.append($input_container);
|
|
}
|
|
}
|
|
};
|
|
|
|
const apply_event = (event) => {
|
|
// prepare request to save config
|
|
const data = {};
|
|
let script_threshold = {}
|
|
let script_enabled = false;
|
|
|
|
// iterate over granularities
|
|
$table_editor.find("tr[id]").each(function (index) {
|
|
const id = $(this).attr("id");
|
|
const enabled = $(this).find("input[type='checkbox']").is(":checked");
|
|
const $template = $(this).find(".template");
|
|
const $error_label = $template.find(`.invalid-feedback`);
|
|
|
|
let operator = $template.find("select").val();
|
|
// if operator is undefined it means there isn't any select, so take the value from span
|
|
if (operator == undefined) {
|
|
operator = $template.find('span.input-group-text').data('value');
|
|
}
|
|
|
|
const $input_box = $template.find("input");
|
|
|
|
let threshold = parseInt($input_box.val());
|
|
|
|
// hide before errors
|
|
$error_label.hide();
|
|
|
|
// remove class error
|
|
$input_box.removeClass('is-invalid');
|
|
// save data into dictonary
|
|
script_threshold[id] = {
|
|
'enabled': enabled,
|
|
'operator': operator,
|
|
'threshold': parseInt(threshold),
|
|
}
|
|
|
|
if(script_enabled || enabled) {
|
|
script_enabled = true
|
|
} else {
|
|
script_enabled = false;
|
|
}
|
|
});
|
|
|
|
data['all'] = {
|
|
'enabled': script_enabled,
|
|
'script_conf': script_threshold,
|
|
}
|
|
|
|
apply_edits_script(data, check_subdir, script_key);
|
|
};
|
|
|
|
const reset_event = (event) => {
|
|
|
|
reset_script_defaults(script_key, check_subdir, (data) => {
|
|
|
|
const { hooks } = data;
|
|
|
|
for (const key in hooks) {
|
|
if (key == undefined) continue;
|
|
|
|
// get hook
|
|
const hook = hooks[key];
|
|
for (const field in hook.script_conf) {
|
|
const { default_value, field_operator } = hook.script_conf[field];
|
|
|
|
$(`input[name='${key}-${field}-check']`).prop('checked', hook.enabled);
|
|
|
|
(default_value === undefined)
|
|
? $(`input[name='${key}-${field}-input']`).val('')
|
|
: $(`input[name='${key}-${field}-input']`).val(default_value);
|
|
|
|
if (hook.enabled) {
|
|
$(`select[name='${key}-${field}-select']`).removeAttr("disabled");
|
|
$(`input[name='${key}-${field}-input']`).removeAttr("readonly");
|
|
}
|
|
else {
|
|
$(`input[name='${key}-${field}-input']`).attr("readonly", "");
|
|
$(`select[name='${key}-${field}-select']`).attr("disabled", "");
|
|
}
|
|
|
|
$(`select[name='${key}-${field}-select']`).val(field_operator);
|
|
}
|
|
}
|
|
});
|
|
|
|
}
|
|
|
|
return {
|
|
apply_click_event: apply_event,
|
|
reset_click_event: reset_event,
|
|
render: render_template,
|
|
}
|
|
}
|
|
|
|
/* ******************************************************* */
|
|
|
|
const ItemsList = (gui, hooks, check_subdir, script_key) => {
|
|
|
|
const $table_editor = $("#script-config-editor");
|
|
|
|
const render_template = () => {
|
|
let enabled = undefined;
|
|
|
|
if(hooks.all)
|
|
enabled = hooks.all.enabled
|
|
else
|
|
enabled = hooks["5mins"] ? hooks["5mins"].enabled : hooks.min.enabled;
|
|
|
|
const $component_container = $(`<tr></tr>`);
|
|
const callback_checkbox = function (e) {
|
|
|
|
const checked = $(this).prop('checked');
|
|
|
|
// if the checked option is false the disable the elements
|
|
if (!checked) {
|
|
$text_area.find(`#itemslist-textarea`).attr("readonly", "");
|
|
return;
|
|
}
|
|
|
|
$text_area.find(`#itemslist-textarea`).removeAttr("readonly", "");
|
|
};
|
|
|
|
const $checkbox_enabled = generate_checkbox_enabled(
|
|
'itemslist-checkbox', enabled, callback_checkbox
|
|
);
|
|
|
|
let items_list = hooks.all ? hooks.all.script_conf.items : ( (hooks["5mins"] ? hooks["5mins"].script_conf.items : hooks.min.script_conf.items) || []);
|
|
|
|
if (items_list == null) {
|
|
items_list = []
|
|
}
|
|
|
|
const $text_area = $(`
|
|
<td>
|
|
<div class='form-row'>
|
|
<textarea
|
|
${!enabled ? "readonly" : ""}
|
|
name='items-list'
|
|
id='itemslist-textarea'
|
|
class="w-100 form-control"
|
|
rows='3'>${items_list.length > 0 ? items_list.join(',') : ''}</textarea>
|
|
<small>${gui.input_description || i18n_ext.blacklisted_country}</small>
|
|
<div class="invalid-feedback"></div>
|
|
<label></label>
|
|
</div>
|
|
</td>
|
|
`);
|
|
|
|
$component_container.append($(`<td class='text-center'></td>`).append($checkbox_enabled), $text_area);
|
|
|
|
$table_editor.empty();
|
|
|
|
$table_editor.append(`<tr><th class='text-center w-25'>${i18n_ext.enabled}</th><th>${gui.input_title || i18n_ext.scripts_list.templates.blacklisted_country_list}:</th></tr>`)
|
|
$table_editor.append($component_container);
|
|
}
|
|
|
|
const apply_event = (event) => {
|
|
|
|
const hook_enabled = $('#itemslist-checkbox').prop('checked');
|
|
const textarea_value = $('#itemslist-textarea').val().trim();
|
|
|
|
const items_list = textarea_value ? textarea_value.split(',').map(x => x.trim()) : [];
|
|
const hook = (hooks.all === undefined) ? ((hooks["5mins"] === undefined) ? "min" : "5mins") : "all";
|
|
const template_data = {
|
|
[hook]: {
|
|
enabled: hook_enabled,
|
|
script_conf: {
|
|
items: items_list
|
|
}
|
|
}
|
|
};
|
|
|
|
// make post request to save edits
|
|
apply_edits_script(template_data, check_subdir, script_key);
|
|
|
|
}
|
|
|
|
const reset_event = (event) => {
|
|
|
|
reset_script_defaults(script_key, check_subdir, (reset_data) => {
|
|
const enabled = reset_data.hooks.all ? reset_data.hooks.all.enabled : (reset_data.hooks["5mins"] ? reset_data.hooks["5mins"].enabled : reset_data.hooks.min.enabled);
|
|
let items_list = reset_data.hooks.all ? reset_data.hooks.all.script_conf.items : (reset_data.hooks["5mins"] ? reset_data.hooks["5mins"].script_conf.items : reset_data.hooks.min.script_conf.items);
|
|
|
|
if (items_list == null) {
|
|
items_list = []
|
|
}
|
|
|
|
// set textarea value with default's one
|
|
$('#itemslist-textarea').val(items_list.join(','));
|
|
$('#itemslist-checkbox').prop('checked', enabled);
|
|
|
|
// turn on readonly to textarea if enabled is false
|
|
if (!enabled) {
|
|
$('#itemslist-textarea').attr('readonly', '');
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
return {
|
|
apply_click_event: apply_event,
|
|
reset_click_event: reset_event,
|
|
render: render_template,
|
|
}
|
|
}
|
|
|
|
/* ******************************************************* */
|
|
|
|
const LongLived = (gui, hooks, check_subdir, script_key) => {
|
|
|
|
const $table_editor = $("#script-config-editor");
|
|
$("#script-config-editor").empty();
|
|
|
|
const render_template = () => {
|
|
|
|
const enabled = hooks.all.enabled;
|
|
const items_list = hooks.all.script_conf.items || [];
|
|
const current_value = hooks.all.script_conf.min_duration || 60;
|
|
const times_unit = get_unit_times(current_value);
|
|
|
|
const max_time = (times_unit[0] == `${i18n_ext.metrics.minutes}` ? 59 : (times_unit[0] == `${i18n_ext.metrics.hours}` ? 23 : 365));
|
|
|
|
const input_settings = {
|
|
name: 'duration_value',
|
|
current_value: times_unit[1],
|
|
min: 1,
|
|
max: max_time,
|
|
enabled: enabled,
|
|
};
|
|
|
|
const $time_input_box = generate_input_box(input_settings);
|
|
/* Currently disabled multi-select for appl and categories
|
|
const $multiselect_ds = generate_multi_select({
|
|
enabled: enabled,
|
|
name: 'item_list',
|
|
label: `${i18n_ext.scripts_list.templates.excluded_applications}:`,
|
|
selected_values: items_list,
|
|
groups: apps_and_categories
|
|
});
|
|
*/
|
|
// time-ds stands for: time duration selection
|
|
const radio_values = {
|
|
labels: [`${i18n_ext.metrics.minutes}`, `${i18n_ext.metrics.hours}`, `${i18n_ext.metrics.days}`],
|
|
label: times_unit[0],
|
|
values: [60, 3600, 86400]
|
|
}
|
|
const $time_radio_buttons = generate_radio_buttons({
|
|
name: 'ds_time',
|
|
enabled: enabled,
|
|
granularity: radio_values
|
|
});
|
|
|
|
// clamp values on radio change
|
|
$time_radio_buttons.find(`input[type='radio']`).on('change', function () {
|
|
|
|
const time_selected = $(this).val();
|
|
|
|
// set min/max bounds to input box
|
|
if (time_selected == 60) {
|
|
$time_input_box.find('input').attr("max", 59);
|
|
}
|
|
else if (time_selected == 3600) {
|
|
$time_input_box.find('input').attr("max", 23);
|
|
}
|
|
else {
|
|
$time_input_box.find('input').attr("max", 365);
|
|
}
|
|
|
|
});
|
|
|
|
const callback_checkbox = function (e) {
|
|
|
|
const checked = $(this).prop('checked');
|
|
|
|
// if the checked option is false the disable the elements
|
|
if (!checked) {
|
|
|
|
const $duration_input = $time_input_box.find(`input[name='duration_value']`);
|
|
|
|
$duration_input.attr("readonly", "");
|
|
$time_radio_buttons.find(`input[type='radio']`).attr("disabled", "").parent().addClass('disabled');
|
|
//$multiselect_ds.find('select').attr("disabled", "");
|
|
|
|
// if the user left the input box empty then reset previous values
|
|
if ($duration_input.val() == "") {
|
|
$duration_input.val(times_unit[1]);
|
|
$duration_input.attr('max', max_time);
|
|
reset_radio_button('ds_time', times_unit[2]);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
$time_input_box.find(`input[name='duration_value']`).removeAttr("readonly");
|
|
$time_radio_buttons.find(`input[type='radio']`).removeAttr("disabled").parent().removeClass('disabled');
|
|
//$multiselect_ds.find('select').removeAttr("disabled");
|
|
|
|
};
|
|
|
|
const $checkbox_enabled = generate_checkbox_enabled(
|
|
'ds-checkbox', hooks.all.enabled, callback_checkbox
|
|
);
|
|
|
|
// append elements on table
|
|
const $input_container = $(`<td></td>`);
|
|
$input_container.append(
|
|
$time_input_box.prepend($time_radio_buttons).prepend(
|
|
$(`<div class='col-7'><label class='p-2'>${i18n_ext.scripts_list.templates.flow_duration_threshold}:</label></div>`)
|
|
),
|
|
//$multiselect_ds
|
|
);
|
|
|
|
// initialize table row
|
|
const $container = $(`<tr></tr>`).append(
|
|
$(`<td class='text-center'></td>`).append($checkbox_enabled),
|
|
$input_container
|
|
);
|
|
|
|
$table_editor.append(`
|
|
<tr class='text-center'>
|
|
<th>${i18n_ext.enabled}</th>
|
|
</tr>
|
|
`);
|
|
|
|
$table_editor.append($container);
|
|
|
|
}
|
|
|
|
const apply_event = (event) => {
|
|
|
|
const hook_enabled = $('#ds-checkbox').prop('checked');
|
|
const items_list = $(`select[name='item_list']`).val();
|
|
|
|
// get the bytes_unit
|
|
const times_unit = $(`input[name='ds_time']:checked`).val();
|
|
const min_duration_input = $(`input[name='duration_value']`).val();
|
|
|
|
const parsed_duration = parseInt(min_duration_input);
|
|
|
|
const template_data = {
|
|
all: {
|
|
enabled: hook_enabled,
|
|
script_conf: {
|
|
items: items_list,
|
|
min_duration: parseInt(times_unit) * parsed_duration,
|
|
}
|
|
}
|
|
}
|
|
|
|
// make post request to save data
|
|
apply_edits_script(template_data, check_subdir, script_key);
|
|
|
|
}
|
|
|
|
const reset_event = (event) => {
|
|
|
|
reset_script_defaults(script_key, check_subdir, (data_reset) => {
|
|
|
|
// reset textarea content
|
|
const items_list = data_reset.hooks.all.script_conf.items || [];
|
|
$(`select[name='item_list']`).val(items_list);
|
|
|
|
// get min_duration value
|
|
const min_duration = data_reset.hooks.all.script_conf.min_duration || 60;
|
|
const times_unit = get_unit_times(min_duration);
|
|
|
|
$(`input[name='duration_value']`).val(times_unit[1]);
|
|
|
|
// select the correct radio button
|
|
reset_radio_button('ds_time', times_unit[2]);
|
|
|
|
const enabled = data_reset.hooks.all.enabled || false;
|
|
$('#ds-checkbox').prop('checked', enabled);
|
|
|
|
if (!enabled) {
|
|
$(`input[name='duration_value']`).attr('readonly', '');
|
|
$(`select[name='item_list'],input[name='ds_time']`).attr('disabled', '').parent().addClass('disabled');
|
|
}
|
|
else {
|
|
$(`input[name='duration_value']`).removeAttr('readonly');
|
|
$(`select[name='item_list'],input[name='ds_time']`).removeAttr('disabled').parent().removeClass('disabled');
|
|
}
|
|
|
|
});
|
|
}
|
|
|
|
return {
|
|
apply_click_event: apply_event,
|
|
reset_click_event: reset_event,
|
|
render: render_template,
|
|
}
|
|
}
|
|
|
|
/* ******************************************************* */
|
|
|
|
const ElephantFlows = (gui, hooks, check_subdir, script_key) => {
|
|
|
|
const $table_editor = $("#script-config-editor");
|
|
$("#script-config-editor").empty();
|
|
|
|
const render_template = () => {
|
|
|
|
const enabled = hooks.all.enabled;
|
|
const items_list = hooks.all.script_conf.items || [];
|
|
|
|
let l2r_bytes_value = hooks.all.script_conf.l2r_bytes_value;
|
|
let r2l_bytes_value = hooks.all.script_conf.r2l_bytes_value;
|
|
|
|
// get units and values
|
|
const l2r_unit = get_unit_bytes(l2r_bytes_value);
|
|
const r2l_unit = get_unit_bytes(r2l_bytes_value);
|
|
|
|
// configure local to remote input
|
|
const input_settings_l2r = {
|
|
min: 1,
|
|
max: 1023,
|
|
current_value: l2r_unit[1],
|
|
name: 'l2r_value',
|
|
enabled: enabled
|
|
};
|
|
const $input_box_l2r = generate_input_box(input_settings_l2r);
|
|
|
|
// configure remote to locale input
|
|
const input_settings_r2l = {
|
|
min: 1,
|
|
max: 1023,
|
|
current_value: r2l_unit[1],
|
|
name: 'r2l_value',
|
|
enabled: enabled
|
|
};
|
|
const $input_box_r2l = generate_input_box(input_settings_r2l);
|
|
|
|
/* Currently disabled textarea
|
|
// create textarea to append
|
|
const $multiselect_bytes = generate_multi_select({
|
|
enabled: enabled,
|
|
name: 'item_list',
|
|
label: `${i18n_ext.scripts_list.templates.excluded_applications}:`,
|
|
selected_values: items_list,
|
|
groups: apps_and_categories
|
|
});
|
|
*/
|
|
|
|
// create radio button with its own values
|
|
const radio_values_l2r = {
|
|
labels: ["KB", "MB", "GB"],
|
|
label: l2r_unit[0],
|
|
values: [1024, 1048576, 1073741824]
|
|
};
|
|
const radio_values_r2l = {
|
|
labels: ["KB", "MB", "GB"],
|
|
label: r2l_unit[0],
|
|
values: [1024, 1048576, 1073741824]
|
|
};
|
|
|
|
const $radio_button_l2r = generate_radio_buttons({
|
|
name: 'bytes_l2r',
|
|
enabled: enabled,
|
|
granularity: radio_values_l2r
|
|
}
|
|
);
|
|
const $radio_button_r2l = generate_radio_buttons({
|
|
name: 'bytes_r2l',
|
|
enabled: enabled,
|
|
granularity: radio_values_r2l
|
|
}
|
|
);
|
|
|
|
const $checkbox_enabled = generate_checkbox_enabled(
|
|
'elephant-flows-checkbox', enabled, function (e) {
|
|
|
|
const checked = $(this).prop('checked');
|
|
const $r2l_input = $input_box_r2l.find(`input[name='r2l_value']`);
|
|
const $l2r_input = $input_box_l2r.find(`input[name='l2r_value']`);
|
|
|
|
// if the checked option is false the disable the elements
|
|
if (!checked) {
|
|
$r2l_input.attr("readonly", "");
|
|
$l2r_input.attr("readonly", "");
|
|
$radio_button_l2r.find(`input[type='radio']`).attr("disabled", "").parent().addClass('disabled');
|
|
$radio_button_r2l.find(`input[type='radio']`).attr("disabled", "").parent().addClass('disabled');
|
|
//$multiselect_bytes.find('select').attr("disabled", "");
|
|
|
|
// if the user left the input box empty then reset previous values
|
|
if ($r2l_input.val() == "") {
|
|
$r2l_input.val(r2l_unit[1]);
|
|
reset_radio_button('bytes_r2l', r2l_unit[2]);
|
|
}
|
|
if ($l2r_input.val() == "") {
|
|
$l2r_input.val(l2r_unit[1]);
|
|
reset_radio_button('bytes_l2r', l2r_unit[2]);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
$r2l_input.removeAttr("readonly", "");
|
|
$l2r_input.removeAttr("readonly", "");
|
|
$radio_button_l2r.find(`input[type='radio']`).removeAttr("disabled").parent().removeClass('disabled');
|
|
$radio_button_r2l.find(`input[type='radio']`).removeAttr("disabled").parent().removeClass('disabled');
|
|
//$multiselect_bytes.find('select').removeAttr("disabled");
|
|
}
|
|
);
|
|
|
|
// append elements on table
|
|
const $input_container = $(`<td></td>`);
|
|
$input_container.append(
|
|
$input_box_l2r
|
|
.prepend($radio_button_l2r)
|
|
.prepend($(`<label class='col'>${i18n_ext.scripts_list.templates.elephant_flows_l2r}</label>`)),
|
|
$input_box_r2l
|
|
.prepend($radio_button_r2l)
|
|
.prepend($(`<label class='col'>${i18n_ext.scripts_list.templates.elephant_flows_r2l}</label>`)),
|
|
//$multiselect_bytes
|
|
);
|
|
|
|
// initialize table row
|
|
const $container = $(`<tr></tr>`).append(
|
|
$(`<td class='text-center'></td>`).append($checkbox_enabled),
|
|
$input_container
|
|
);
|
|
|
|
$table_editor.append(`<tr class='text-center'><th>${i18n_ext.enabled}</th></tr>`);
|
|
|
|
// append all inside the table
|
|
$table_editor.append($container);
|
|
|
|
}
|
|
|
|
const apply_event = (event) => {
|
|
|
|
const hook_enabled = $('#elephant-flows-checkbox').prop('checked');
|
|
|
|
const items_list = $(`select[name='item_list']`).val();
|
|
|
|
// get the bytes_unit
|
|
const unit_l2r = $(`input[name='bytes_l2r']:checked`).val();
|
|
const unit_r2l = $(`input[name='bytes_r2l']:checked`).val();
|
|
|
|
const input_l2r = $(`input[name='l2r_value']`).val();
|
|
const input_r2l = $(`input[name='r2l_value']`).val();
|
|
|
|
const template_data = {
|
|
all: {
|
|
enabled: hook_enabled,
|
|
script_conf: {
|
|
items: items_list,
|
|
l2r_bytes_value: parseInt(unit_l2r) * parseInt(input_l2r),
|
|
r2l_bytes_value: parseInt(unit_r2l) * parseInt(input_r2l)
|
|
}
|
|
}
|
|
}
|
|
|
|
apply_edits_script(template_data, check_subdir, script_key);
|
|
|
|
}
|
|
|
|
const reset_event = (event) => {
|
|
|
|
reset_script_defaults(script_key, check_subdir, (data_reset) => {
|
|
|
|
// reset textarea content
|
|
const items_list = data_reset.hooks.all.script_conf.items || [];
|
|
$(`select[name='item_list']`).val(items_list);
|
|
|
|
// get min_duration value
|
|
const bytes_l2r = data_reset.hooks.all.script_conf.l2r_bytes_value || 1024;
|
|
const bytes_r2l = data_reset.hooks.all.script_conf.r2l_bytes_value || 1024;
|
|
|
|
const bytes_unit_l2r = get_unit_bytes(bytes_l2r);
|
|
const bytes_unit_r2l = get_unit_bytes(bytes_r2l);
|
|
|
|
$(`input[name='l2r_value']`).val(bytes_unit_l2r[1]);
|
|
$(`input[name='r2l_value']`).val(bytes_unit_r2l[1]);
|
|
|
|
// select the correct radio button
|
|
reset_radio_button('bytes_l2r', bytes_unit_l2r[2]);
|
|
reset_radio_button('bytes_r2l', bytes_unit_r2l[2]);
|
|
|
|
const enabled = data_reset.hooks.all.enabled || false;
|
|
$('#elephant-flows-checkbox').prop('checked', enabled);
|
|
|
|
if (!enabled) {
|
|
$(`input[name='l2r_value'],input[name='r2l_value']`).attr('readonly', '');
|
|
$(`select[name='item_list'],input[name='bytes_l2r']`).attr('disabled', '').parent().addClass('disabled');
|
|
$(`input[name='bytes_r2l']`).attr('disabled', '').parent().addClass('disabled');
|
|
}
|
|
else {
|
|
$(`input[name='l2r_value'],input[name='r2l_value']`).removeAttr('readonly');
|
|
$(`select[name='item_list'],input[name='bytes_l2r']`).removeAttr('disabled').parent().removeClass('disabled');
|
|
$(`input[name='bytes_r2l']`).removeAttr('disabled').parent().removeClass('disabled');
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
return {
|
|
apply_click_event: apply_event,
|
|
reset_click_event: reset_event,
|
|
render: render_template,
|
|
}
|
|
}
|
|
|
|
/* ******************************************************* */
|
|
|
|
const MultiSelect = (gui, hooks, check_subdir, script_key) => {
|
|
|
|
const $table_editor = $("#script-config-editor");
|
|
$("#script-config-editor").empty();
|
|
|
|
const render_template = () => {
|
|
|
|
const enabled = hooks.all.enabled;
|
|
const items_list = hooks.all.script_conf.items || [];
|
|
// create textarea to append
|
|
const $multiselect = generate_multi_select({
|
|
enabled: enabled,
|
|
name: 'item_list',
|
|
label: gui.i8n_multiselect_label,
|
|
containerCss: 'm-0',
|
|
selected_values: items_list,
|
|
groups: gui.groups
|
|
});
|
|
|
|
const $checkbox_enabled = generate_checkbox_enabled(
|
|
'multiselect-checkbox', enabled, function (e) {
|
|
|
|
const checked = $(this).prop('checked');
|
|
// if the checked option is false the disable the elements
|
|
(!checked)
|
|
? $multiselect.find('select').attr("disabled", "")
|
|
: $multiselect.find('select').removeAttr("disabled");
|
|
}
|
|
);
|
|
|
|
// append elements on table
|
|
const $input_container = $(`<td></td>`);
|
|
$input_container.append($multiselect);
|
|
|
|
// initialize table row
|
|
const $container = $(`<tr></tr>`).append(
|
|
$(`<td class='text-center'></td>`).append($checkbox_enabled),
|
|
$input_container
|
|
);
|
|
|
|
$table_editor.append(`<tr class='text-center'><th>${i18n_ext.enabled}</th></tr>`);
|
|
|
|
// append all inside the table
|
|
$table_editor.append($container);
|
|
}
|
|
|
|
const apply_event = (event) => {
|
|
|
|
const hook_enabled = $('#multiselect-checkbox').prop('checked');
|
|
const items_list = $(`select[name='item_list']`).val();
|
|
|
|
const template_data = {
|
|
all: {
|
|
enabled: hook_enabled,
|
|
script_conf: {
|
|
items: items_list,
|
|
}
|
|
}
|
|
}
|
|
|
|
apply_edits_script(template_data, check_subdir, script_key);
|
|
}
|
|
|
|
const reset_event = (event) => {
|
|
reset_script_defaults(script_key, check_subdir, (data_reset) => {
|
|
|
|
// reset textarea content
|
|
const items_list = data_reset.hooks.all.script_conf.items || [];
|
|
$(`select[name='item_list']`).val(items_list);
|
|
|
|
const enabled = data_reset.hooks.all.enabled || false;
|
|
$('#multiselect-checkbox').prop('checked', enabled);
|
|
});
|
|
}
|
|
|
|
return {
|
|
apply_click_event: apply_event,
|
|
reset_click_event: reset_event,
|
|
render: render_template,
|
|
}
|
|
}
|
|
|
|
/* ******************************************************* */
|
|
|
|
const DefaultTemplate = (gui, hooks, check_subdir, script_key) => {
|
|
|
|
const $tableEditor = $("#script-config-editor");
|
|
|
|
return {
|
|
apply_click_event: function () {
|
|
|
|
const template_data = {
|
|
all: {
|
|
enabled: true,
|
|
script_conf: {}
|
|
}
|
|
}
|
|
|
|
apply_edits_script(template_data, check_subdir, script_key);
|
|
},
|
|
reset_click_event: function () {
|
|
reset_script_defaults(script_key, check_subdir, (data_reset) => { });
|
|
},
|
|
render: function () {
|
|
$tableEditor.empty();
|
|
},
|
|
}
|
|
}
|
|
|
|
/* ******************************************************* */
|
|
|
|
const EmptyTemplate = (gui = null, hooks = null, check_subdir = null, script_key = null) => {
|
|
|
|
const $tableEditor = $("#script-config-editor");
|
|
|
|
return {
|
|
apply_click_event: function () { },
|
|
reset_click_event: function () { },
|
|
render: function () {
|
|
|
|
// add an info alert to inform the user about the problem
|
|
const $alert = $("<div class='alert alert-info'></div>");
|
|
$alert.html(i18n_ext.scripts_list.templates.template_not_implemented);
|
|
$tableEditor.append($alert);
|
|
// hide the apply and the reset button because there are no inputs to fill
|
|
$(`#btn-apply,#btn-reset`).hide();
|
|
},
|
|
}
|
|
}
|
|
|
|
// END OF TEMPLATES
|
|
|
|
|
|
/* ******************************************************* */
|
|
|
|
// get script key and script name
|
|
const initScriptConfModal = (script_key, script_subdir, script_title, script_desc) => {
|
|
// change title to modal
|
|
$("#script-name").html(script_title);
|
|
$('#script-description').html(script_desc);
|
|
|
|
$("#modal-script form").off('submit');
|
|
$("#modal-script").on("submit", "form", function (e) {
|
|
e.preventDefault();
|
|
|
|
$('#edit-form').trigger('reinitialize.areYouSure').removeClass('dirty');
|
|
$("#btn-apply").trigger("click");
|
|
});
|
|
|
|
$.get(`${http_prefix}/lua/get_check_config.lua`,
|
|
{
|
|
check_subdir: script_subdir,
|
|
script_key: script_key,
|
|
factory: false
|
|
}
|
|
)
|
|
.then((data, status, xhr) => {
|
|
|
|
// check status code
|
|
if (NtopUtils.check_status_code(xhr.status, xhr.statusText, null)) return;
|
|
|
|
// hide previous error
|
|
$("#apply-error").hide();
|
|
|
|
const template = TemplateBuilder(data, script_subdir, script_key);
|
|
|
|
// render template
|
|
template.render();
|
|
|
|
// bind on_apply event on apply button
|
|
$("#edit-form").off("submit").on('submit', template.apply_click_event);
|
|
$("#btn-reset").off("click").on('click', template.reset_click_event);
|
|
|
|
// bind are you sure to form
|
|
$('#edit-form').trigger('rescan.areYouSure').trigger('reinitialize.areYouSure');
|
|
})
|
|
.fail(({ status, statusText }) => {
|
|
|
|
NtopUtils.check_status_code(status, statusText, null);
|
|
// hide modal if there is error
|
|
$("#modal-script").modal("toggle");
|
|
})
|
|
}
|
|
|
|
/* ******************************************************* */
|
|
|
|
/**
|
|
* This function return the search criteria for the datatable
|
|
* 'true': apply filter categories criteria only on enabled scripts
|
|
* 'false': apply filter categories criteria only on disabled scripts
|
|
* '': apply filter categories criteria for all scripts
|
|
*
|
|
* @returns {string} 'true'|'false'|''
|
|
*/
|
|
const get_search_toggle_value = hash => hash == "#enabled" ? 'true' : (hash == "#disabled" ? 'false' : '');
|
|
|
|
/* ******************************************************* */
|
|
|
|
const TemplateBuilder = ({ gui, hooks, metadata }, check_subdir, script_key) => {
|
|
|
|
// get template name
|
|
const template_name = gui.input_builder;
|
|
|
|
|
|
const templates = {
|
|
threshold_cross: ThresholdCross(gui, hooks, check_subdir, script_key),
|
|
items_list: ItemsList(gui, hooks, check_subdir, script_key),
|
|
long_lived: LongLived(gui, hooks, check_subdir, script_key),
|
|
elephant_flows: ElephantFlows(gui, hooks, check_subdir, script_key),
|
|
multi_select: MultiSelect(gui, hooks, check_subdir, script_key),
|
|
multi_threshold_cross: MultiThresholdCross(gui, metadata, hooks, check_subdir, script_key)
|
|
}
|
|
|
|
const isSubdirFlow = (check_subdir === "flow")
|
|
let template_chosen = templates[template_name];
|
|
if (!template_chosen && !(isSubdirFlow)) {
|
|
template_chosen = EmptyTemplate();
|
|
// this message is for the developers
|
|
console.warn("The chosen template doesn't exist yet. See the avaible templates.")
|
|
}
|
|
else if (!template_chosen && (isSubdirFlow)) {
|
|
template_chosen = DefaultTemplate(gui, hooks, check_subdir, script_key);
|
|
}
|
|
|
|
// check if the script has an action button
|
|
const hasActionButton = gui.input_action_i18n !== undefined && gui.input_action_url !== undefined;
|
|
if (hasActionButton) {
|
|
$(`.action-button-container`).show();
|
|
delegateActionButton(gui);
|
|
}
|
|
else {
|
|
$(`.action-button-container`).hide();
|
|
$(`#action-error`).hide();
|
|
}
|
|
|
|
// restore Apply/Reset button
|
|
$(`#btn-apply,#btn-reset`).show();
|
|
|
|
return template_chosen;
|
|
}
|
|
|
|
/* ******************************************************* */
|
|
|
|
// End templates and template builder
|
|
|
|
const createScriptStatusButton = (row_data) => {
|
|
|
|
const { is_enabled } = row_data;
|
|
let enable_title = i18n_ext.enable_check_title;
|
|
let disable_title = i18n_ext.disable_check_title;
|
|
const $button = $(`<button type='button' class='btn btn-sm' style='margin: 0.25rem'></button>`);
|
|
$button.addClass('btn-danger');
|
|
$button[0].setAttribute('title', enable_title)
|
|
|
|
if (!is_enabled && row_data.input_handler) {
|
|
$button.html(`<i class='fas fa-toggle-off'></i>`);
|
|
$button.attr('data-bs-target', '#modal-script');
|
|
$button.attr('data-bs-toggle', 'modal');
|
|
return $button;
|
|
}
|
|
|
|
if (!is_enabled && !row_data.input_handler) {
|
|
$button.html(`<i class='fas fa-toggle-off'></i>`);
|
|
}
|
|
else {
|
|
$button.removeClass('btn-danger');
|
|
$button[0].setAttribute('title', disable_title)
|
|
$button.html(`<i class='fas fa-toggle-on'></i>`);
|
|
$button.addClass('btn-success');
|
|
|
|
if (row_data.enabled_hooks.length < 1) {
|
|
$button.addClass('disabled');
|
|
return $button;
|
|
}
|
|
}
|
|
|
|
$button.off('click').on('click', function () {
|
|
|
|
$.post(`${http_prefix}/lua/toggle_check.lua`, {
|
|
check_subdir: row_data.subdir,
|
|
script_key: row_data.key,
|
|
csrf: pageCsrf,
|
|
action: (is_enabled) ? 'disable' : 'enable'
|
|
})
|
|
.done((d, status, xhr) => {
|
|
|
|
if (!d.success) {
|
|
$("#alert-row-buttons").text(d.error).removeClass('d-none').show();
|
|
}
|
|
|
|
if (d.success) reloadPageAfterPOST();
|
|
})
|
|
.fail(({ status, statusText }) => {
|
|
NtopUtils.check_status_code(status, statusText, $("#alert-row-buttons"));
|
|
})
|
|
.always(() => {
|
|
$button.removeAttr("disabled").removeClass('disabled');
|
|
})
|
|
})
|
|
|
|
return $button;
|
|
};
|
|
|
|
function delegateActionButton(gui) {
|
|
|
|
const $button = $(`#btn-action-config`);
|
|
$button.text(gui.input_action_i18n);
|
|
$button.off('click').click(function (e) {
|
|
|
|
e.preventDefault();
|
|
|
|
if (gui.input_action_confirm && !window.confirm(gui.input_action_i18n_confirm)) {
|
|
return;
|
|
}
|
|
|
|
$button.attr("disabled", "disabled");
|
|
const $alert = $(`#action-error`);
|
|
$alert.hide();
|
|
|
|
const req = $.post(`${http_prefix}/${gui.input_action_url}`, { csrf: pageCsrf });
|
|
req.then(function ({ rc, rc_str }) {
|
|
|
|
// if the return code is zero then everything went alright
|
|
if (rc == 0) {
|
|
$alert.removeClass('alert-danger').addClass('alert-success').html(i18n_ext.rest[rc_str]).show().fadeOut(3000);
|
|
return;
|
|
}
|
|
// otherwise show an error!
|
|
$alert.removeClass('alert-success').addClass('alert-danger').html(i18n_ext.rest[rc_str]).show();
|
|
});
|
|
req.fail(function (jqXHR) {
|
|
if (jqXHR.status == 404) {
|
|
NtopUtils.check_status_code(jqXHR.status, jqXHR.statusText, $alert);
|
|
return;
|
|
}
|
|
const { rc_str } = jqXHR.responseJSON;
|
|
$alert.removeClass('alert-success').addClass('alert-danger').html(i18n_ext.rest[rc_str]).show();
|
|
});
|
|
req.always(function () {
|
|
$button.removeAttr("disabled");
|
|
});
|
|
});
|
|
}
|
|
|
|
function delegateTooltips() {
|
|
$(`span[data-bs-toggle='popover']`).popover({
|
|
trigger: 'manual',
|
|
html: true,
|
|
animation: false,
|
|
})
|
|
.on('mouseenter', function () {
|
|
let self = this;
|
|
$(this).popover("show");
|
|
$(".popover").on('mouseleave', function () {
|
|
$(self).popover('hide');
|
|
});
|
|
})
|
|
.on('mouseleave', function () {
|
|
let self = this;
|
|
setTimeout(function () {
|
|
if (!$('.popover:hover').length) {
|
|
$(self).popover('hide');
|
|
}
|
|
}, 50);
|
|
});
|
|
}
|
|
|
|
$(function () {
|
|
|
|
const CATEGORY_COLUMN_INDEX = 3;
|
|
const VALUES_COLUMN_INDEX = 6;
|
|
|
|
const add_filter_categories_dropdown = () => {
|
|
|
|
const $dropdown = $(`
|
|
<div id='category-filter-menu' class='dropdown d-inline'>
|
|
<button class='btn btn-link dropdown-toggle' data-bs-toggle='dropdown' type='button'>
|
|
<span>${i18n_ext.filter_categories}</span>
|
|
</button>
|
|
<div id='category-filter' class='dropdown-menu'>
|
|
</div>
|
|
</div>
|
|
`);
|
|
|
|
$dropdown.find('#category-filter').append(
|
|
|
|
scripts_categories.map((c, index) => {
|
|
|
|
// list element to append inside the dropdown selector
|
|
const $list_element = $(`<li class='dropdown-item pointer'>${c.label}</li>`);
|
|
|
|
// when a user click the filter category then the datatable
|
|
// will be filtered
|
|
$list_element.click(function () {
|
|
|
|
// if the category is not inside the array
|
|
// it means the filter category is `All`
|
|
if (c.disableFilter) {
|
|
$script_table
|
|
.column(CATEGORY_COLUMN_INDEX).search('')
|
|
.column(VALUES_COLUMN_INDEX).search(get_search_toggle_value(location.hash))
|
|
.draw();
|
|
$dropdown.find('button span').text(`${i18n_ext.filter_categories}`);
|
|
return;
|
|
}
|
|
|
|
$dropdown.find('button span').html(`<i class='fas fa-filter'></i> ${c.label}`);
|
|
$script_table
|
|
.column(CATEGORY_COLUMN_INDEX).search(c.label)
|
|
.column(VALUES_COLUMN_INDEX).search(get_search_toggle_value(location.hash))
|
|
.draw();
|
|
});
|
|
|
|
return $list_element;
|
|
})
|
|
);
|
|
|
|
$('#scripts-config_filter').prepend($dropdown);
|
|
|
|
return $dropdown;
|
|
}
|
|
|
|
const hide_categories_dropdown = () => {
|
|
// get alla categories from current datatable instance
|
|
const data_rows = $script_table
|
|
.column(CATEGORY_COLUMN_INDEX)
|
|
.search('')
|
|
// .rows({ filter: 'applied' }) /* Causes issues with invalid cats when switching tabs */
|
|
.data();
|
|
const categories_set = new Set();
|
|
|
|
for (let i = 0; i < data_rows.length; i++) {
|
|
categories_set.add(data_rows[i].category_title);
|
|
}
|
|
|
|
const enabled_categories = [...categories_set];
|
|
|
|
$('#category-filter-menu button span').text(`${i18n_ext.filter_categories}`);
|
|
$script_table.column(CATEGORY_COLUMN_INDEX).search('').draw();
|
|
|
|
$('#category-filter li').each(function (index, element) {
|
|
|
|
const value = $(this).text();
|
|
|
|
// all filter must be always enabled
|
|
if (scripts_categories.find(e => e.label == value).disableFilter) return;
|
|
|
|
// hide category
|
|
if (enabled_categories.indexOf(value) == -1) {
|
|
$(this).hide();
|
|
return;
|
|
}
|
|
|
|
$(this).show();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
const truncate_string = (str, lim, strip_html = false) => {
|
|
|
|
if (strip_html) {
|
|
let str_sub = str.replace(/(<([^>]+)>)/ig, "");
|
|
return (str_sub.length > lim) ? str_sub.substr(0, lim) + '...' : str_sub;
|
|
}
|
|
|
|
return (str.length > lim) ? str.substr(0, lim) + '...' : str;
|
|
}
|
|
|
|
if(typeof check_subdir === 'undefined') return;
|
|
|
|
// initialize script table
|
|
const $script_table = $("#scripts-config").DataTable({
|
|
dom: "Bfrtip",
|
|
pagingType: 'full_numbers',
|
|
columnDefs: [
|
|
{ type: "severity", targets: 4 },
|
|
],
|
|
language: {
|
|
info: i18n_ext.showing_x_to_y_rows,
|
|
search: i18n_ext.script_search,
|
|
infoFiltered: "",
|
|
paginate: {
|
|
previous: '<',
|
|
next: '>',
|
|
first: '«',
|
|
last: '»'
|
|
}
|
|
},
|
|
lengthChange: false,
|
|
ajax: {
|
|
url: `${http_prefix}/lua/get_checks.lua?check_subdir=${check_subdir}`,
|
|
type: 'get',
|
|
dataSrc: ''
|
|
},
|
|
stateSave: true,
|
|
initComplete: function (settings, json) {
|
|
|
|
// add categories dropdown
|
|
const $categories_filter = add_filter_categories_dropdown();
|
|
|
|
// check if there is a previous filter
|
|
if (settings.oLoadedState != null) {
|
|
const loaded_filter = settings.oLoadedState.columns[CATEGORY_COLUMN_INDEX].search.search;
|
|
if (loaded_filter != "") $categories_filter.find('button span').html(`<i class='fas fa-filter'></i> ${loaded_filter}`);
|
|
}
|
|
|
|
const [enabled_count, disabled_count] = count_scripts();
|
|
// enable the disable all button if there are more than one enabled scripts
|
|
if (enabled_count > 0) $(`#btn-disable-all`).removeAttr('disabled');
|
|
|
|
// clean searchbox
|
|
$(".dataTables_filter").find("input[type='search']").val('').trigger('keyup');
|
|
|
|
// hide category in base selected pill
|
|
hide_categories_dropdown();
|
|
$('#all-scripts,#enabled-scripts,#disabled-scripts').click(function () {
|
|
hide_categories_dropdown();
|
|
});
|
|
|
|
delegateTooltips();
|
|
|
|
// update the tabs counters
|
|
const INDEX_SEARCH_COLUMN = 6;
|
|
|
|
const $disabled_button = $(`#disabled-scripts`);
|
|
const $all_button = $("#all-scripts");
|
|
const $enabled_button = $(`#enabled-scripts`);
|
|
|
|
$all_button.html(`${i18n_ext.all} (${enabled_count + disabled_count})`)
|
|
$enabled_button.html(`${i18n_ext.enabled} (${enabled_count})`);
|
|
$disabled_button.html(`${i18n_ext.disabled} (${disabled_count})`);
|
|
|
|
const filterButonEvent = ($button, searchValue, tab) => {
|
|
$('.filter-scripts-button').removeClass('active');
|
|
$button.addClass('active');
|
|
this.DataTable().columns(INDEX_SEARCH_COLUMN).search(searchValue).draw();
|
|
window.history.replaceState(undefined, undefined, tab);
|
|
delegateTooltips();
|
|
}
|
|
|
|
$all_button.click(function () {
|
|
filterButonEvent($(this), "", "#all");
|
|
});
|
|
$enabled_button.click(function () {
|
|
filterButonEvent($(this), "true", "#enabled");
|
|
});
|
|
$disabled_button.click(function () {
|
|
filterButonEvent($(this), "false", "#disabled");
|
|
});
|
|
|
|
// select the correct tab
|
|
select_script_filter(enabled_count);
|
|
|
|
if (script_search_filter) {
|
|
this.DataTable().columns(INDEX_SEARCH_COLUMN).search("").draw(true);
|
|
this.DataTable().search(script_search_filter).draw(true);
|
|
// disable the search box
|
|
$(`#scripts-config_filter input[type='search']`).attr("readonly", "");
|
|
}
|
|
|
|
if (script_key_filter) {
|
|
let elem = json.filter((x) => { return (x.key == script_key_filter); })[0];
|
|
|
|
if (elem) {
|
|
let title = elem.title;
|
|
let desc = elem.description;
|
|
this.DataTable().search(title).draw();
|
|
|
|
if (hasConfigDialog(elem)) {
|
|
initScriptConfModal(script_key_filter, elem.subdir, title, desc);
|
|
$("#modal-script").modal("show");
|
|
}
|
|
}
|
|
}
|
|
},
|
|
order: [[1, "asc"]],
|
|
buttons: {
|
|
buttons: [
|
|
{
|
|
text: '<i class="fas fa-sync"></i>',
|
|
className: 'btn-link no-wrap',
|
|
action: function (e, dt, node, config) {
|
|
$script_table.ajax.reload(function () {
|
|
const [enabled_count, disabled_count] = count_scripts();
|
|
// enable the disable all button if there are more than one enabled scripts
|
|
if (enabled_count > 0) $(`#btn-disable-all`).removeAttr('disabled');
|
|
$("#all-scripts").html(`${i18n_ext.all} (${enabled_count + disabled_count})`)
|
|
$(`#enabled-scripts`).html(`${i18n_ext.enabled} (${enabled_count})`);
|
|
$(`#disabled-scripts`).html(`${i18n_ext.disabled} (${disabled_count})`);
|
|
}, false);
|
|
}
|
|
}
|
|
],
|
|
dom: {
|
|
button: {
|
|
className: 'btn btn-link'
|
|
},
|
|
container: {
|
|
className: 'border-start ms-1 float-end'
|
|
}
|
|
}
|
|
},
|
|
columns: [
|
|
{
|
|
data: 'subdir_title',
|
|
visible: false,
|
|
render: function (data, type, row) {
|
|
if (type == 'display') return `${data}`;
|
|
return data;
|
|
},
|
|
},
|
|
{
|
|
data: 'title',
|
|
render: function (data, type, row) {
|
|
if (type == 'display') return `<b>${data}</b>`;
|
|
return data;
|
|
},
|
|
},
|
|
{
|
|
data: null,
|
|
sortable: true,
|
|
searchable: false,
|
|
className: 'text-center',
|
|
render: function (data, type, row) {
|
|
let icon = `<i class='fas fa-ethernet'></i>`;
|
|
|
|
if(!row.packet_interface_only) {
|
|
icon += ` <i class='fas fa-bezier-curve'></i>`;
|
|
}
|
|
|
|
if (type == "display") return `${icon}`;
|
|
return row.packet_interface_only;
|
|
}
|
|
},
|
|
{
|
|
data: null,
|
|
sortable: true,
|
|
searchable: true,
|
|
className: 'text-center',
|
|
render: function (data, type, row) {
|
|
const icon = (!row.category_icon) ? '' : `<i class='fa ${row.category_icon}'></i>`;
|
|
if (type == "display") return `${icon}`;
|
|
return row.category_title;
|
|
}
|
|
},
|
|
{
|
|
data: 'severity',
|
|
sortable: true,
|
|
searchable: true,
|
|
className: 'text-center no-wrap',
|
|
render: function (data, type, row) {
|
|
let severity = ''
|
|
if (Object.keys(data).length > 0) {
|
|
severity = `${data.title || ''} <i class="${data.icon}"></i>`
|
|
}
|
|
return severity;
|
|
}
|
|
},
|
|
{
|
|
data: 'description',
|
|
sortable: false,
|
|
render: function (data, type, row) {
|
|
|
|
if (type == "display") {
|
|
|
|
return `<span
|
|
${data.length >= 120 ? `data-bs-toggle='popover' data-placement='top' data-html='true' title="${row.title}" data-bs-content="${data}"` : ``}
|
|
data-content="${data}" >
|
|
${truncate_string(data, 120, true)}
|
|
</span>`;
|
|
}
|
|
|
|
return data;
|
|
|
|
},
|
|
},
|
|
{
|
|
data: 'enabled_hooks',
|
|
sortable: false,
|
|
className: 'text-start',
|
|
render: function (data, type, row) {
|
|
|
|
// if the type is flter return true if the data length is greather or equal
|
|
// than 0 so the script table can detect if a script is enabled
|
|
if (data.length <= 0 && type == "filter") return false;
|
|
if (data.length > 0 && type == "filter") return true;
|
|
|
|
return (type == 'display') ? `
|
|
<span
|
|
title="${i18n_ext.values}"
|
|
${row.value_description.length >= 32 ? `data-bs-toggle='popover' data-placement='top'` : ``}
|
|
data-content='${row.value_description}'>
|
|
${row.value_description.substr(0, 32)}${row.value_description.length >= 32 ? '...' : ''}
|
|
</span>
|
|
` : '';
|
|
|
|
},
|
|
},
|
|
{
|
|
targets: -1,
|
|
data: null,
|
|
name: 'actions',
|
|
className: 'text-center no-wrap',
|
|
sortable: false,
|
|
width: '7%',
|
|
render: function (data, type, script) {
|
|
const isScriptEnabled = script.is_enabled;
|
|
const isSubdirFlow = (script.subdir === "flow");
|
|
const srcCodeButtonEnabled = data.edit_url && isScriptEnabled ? '' : 'disabled';
|
|
const editScriptButtonEnabled = ((!script.input_handler && !isSubdirFlow) || !isScriptEnabled) ? 'disabled' : '';
|
|
|
|
return DataTableUtils.createActionButtons([
|
|
{ class: `btn-info ${editScriptButtonEnabled}`, modal: '#modal-script', icon: 'fa-edit', title: i18n_ext.edit_check_title },
|
|
]);
|
|
},
|
|
createdCell: function (td, cellData, row) {
|
|
|
|
const $enableButton = createScriptStatusButton(row);
|
|
$(td).find('div').prepend($enableButton);
|
|
}
|
|
}
|
|
]
|
|
});
|
|
|
|
// initialize are you sure
|
|
$("#edit-form").areYouSure({ message: i18n_ext.are_you_sure });
|
|
|
|
// handle modal-script close event
|
|
$("#modal-script").on("hide.bs.modal", function (e) {
|
|
|
|
// if the forms is dirty then ask to the user
|
|
// if he wants save edits
|
|
if ($('#edit-form').hasClass('dirty')) {
|
|
|
|
// ask to user if he REALLY wants close modal
|
|
const result = confirm(`${i18n_ext.are_you_sure}`);
|
|
if (!result) e.preventDefault();
|
|
|
|
// remove dirty class from form
|
|
$('#edit-form').removeClass('dirty');
|
|
}
|
|
})
|
|
.on("shown.bs.modal", function (e) {
|
|
// add focus to btn apply to enable focusing on the modal hence user can press escape button to
|
|
// close the modal
|
|
$("#btn-apply").trigger('focus');
|
|
});
|
|
|
|
const getCheckData = function(row_data) {
|
|
const script_key = row_data.key;
|
|
const script_subdir = row_data.subdir;
|
|
const script_title = row_data.title;
|
|
const script_desc = row_data.description;
|
|
|
|
initScriptConfModal(script_key, script_subdir, script_title, script_desc);
|
|
}
|
|
|
|
// load templates for the script
|
|
$('#scripts-config').on('click', 'button[href="#modal-script"],[data-bs-target="#modal-script"]', function (e) {
|
|
const row_data = $script_table.row($(this).parent().parent()).data();
|
|
getCheckData(row_data)
|
|
});
|
|
|
|
// load templates for the script
|
|
$('#scripts-config').on('click', 'a[href="#modal-script"]', function (e) {
|
|
const row_data = $script_table.row($(this).parent().parent().parent().parent()).data();
|
|
getCheckData(row_data)
|
|
});
|
|
|
|
|
|
/**
|
|
* Count the scripts that are enabled, disabled inside the script table
|
|
*/
|
|
const count_scripts = () => {
|
|
|
|
let enabled_count = 0;
|
|
let disabled_count = 0;
|
|
|
|
$script_table.data().each(d => {
|
|
|
|
if (d.is_enabled) {
|
|
enabled_count++;
|
|
return;
|
|
}
|
|
|
|
disabled_count++;
|
|
});
|
|
|
|
return [enabled_count, disabled_count];
|
|
}
|
|
|
|
$(`.filter-scripts-button`).click(function () {
|
|
$(`#scripts-config a[href^='/lua/code_viewer.lua']`).each(function () {
|
|
const encoded = encodeURIComponent(`${location.pathname}${location.search}${location.hash}`);
|
|
$(this).attr('href', `${$(this).attr('href')}&referal_url=${encoded}`);
|
|
});
|
|
});
|
|
|
|
$(`#btn-confirm-action_disable-all-modal`).click(async function () {
|
|
|
|
$(this).attr("disabled", "disabled");
|
|
$.post(`${http_prefix}/lua/toggle_all_checks.lua`, {
|
|
action: 'disable',
|
|
check_subdir: check_subdir,
|
|
csrf: pageCsrf
|
|
})
|
|
.then((result) => {
|
|
if (result.success) location.reload();
|
|
})
|
|
.catch((error) => {
|
|
console.error(error);
|
|
})
|
|
.always(() => {
|
|
$(`#btn-disable-all`).removeAttr("disabled");
|
|
})
|
|
})
|
|
|
|
$(`#btn-confirm-action_factory-reset-modal`).click(async function () {
|
|
$.post(`${http_prefix}/lua/rest/v2/reset/checks/config.lua`, {
|
|
csrf: pageCsrf
|
|
})
|
|
.then((result) => {
|
|
if (result.rc_str == "OK") location.reload();
|
|
})
|
|
.catch((error) => {
|
|
console.error(error);
|
|
})
|
|
.always(() => {
|
|
})
|
|
})
|
|
|
|
});
|
|
</script>
|
|
|