ntopng/httpdocs/templates/pages/table_pools.template
2022-03-08 16:38:45 +01:00

449 lines
17 KiB
Text

{#
(C) 2020-21 - ntop.org
This is the template to generate the Manage Pool page.
#}
<div class="row">
<div class="col-md-12 mb-4">
<div class="card card-shadow">
<div class="card-header">
{# import the navbar inside the pool page to navigate through the pool tables #}
{* template_utils.gen("pages/components/nav_tabs.template", menu) *}
</div>
<div class="card-body">
<table class="table table-bordered table-striped w-100" id="table-pools">
<thead>
<tr>
<th>{{ i18n("pools.name") }}</th>
{% if pool.is_all_pool then %}
<th>{{ i18n("pools.family") }}</th>
{% end %}
<th>{{ i18n("pools.members") }}</th>
<th>{{ i18n("actions") }}</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<div class="card-footer">
{* ui_utils.render_configuration_footer('pool', _GET["page"]) *}
</div>
</div>
</div>
</div>
{# include the modal to add a new pool #}
{* template_utils.gen("pages/modals/pools/pool_modal.template", {
modal_type = "add",
pool = pool,
}) *}
{# include the modal to edit an existing pool #}
{* template_utils.gen("pages/modals/pools/pool_modal.template", {
modal_type = "edit",
pool = pool,
}) *}
{* template_utils.gen("pages/modals/pools/remove_pool.template", {
modal_type = "remove",
pool = pool
}) *}
{* template_utils.gen("pages/modals/factory-reset.template", {
body = i18n("endpoint_notifications.factory_reset.body", { reset_element = i18n("pools.pools") }),
title = i18n("endpoint_notifications.factory_reset.title", { reset_element = i18n("pools.pools") })
}) *}
<script type="text/javascript">
let addCsrf = "{{ ntop.getRandomCSRFValue() }}";
let editCsrf = "{{ ntop.getRandomCSRFValue() }}";
let removeCsrf = "{{ ntop.getRandomCSRFValue() }}";
const all_members = {* json.encode(pool.all_members) *};
const endpoints = {* json.encode(pool.endpoints) *};
const poolType = "{{ pool.name }}";
const IS_ALL_POOL = {{ pool.is_all_pool }};
const DEFAULT_POOL_ID = {{ (pool.instance.DEFAULT_POOL_ID or 0) }};
const IS_NEDGE = {{ is_nedge or false }};
Object.freeze(all_members);
Object.freeze(endpoints);
i18n_ext.warning = "{{ i18n('warning', {}) }}";
i18n_ext.showing_x_to_y_rows = "{{ i18n('showing_x_to_y_rows', {x='_START_', y='_END_', tot='_TOTAL_'}) }}";
i18n_ext.search = "{{ i18n('search') }}";
i18n_ext.delete = "{{ i18n('delete') }}";
i18n_ext.edit = "{{ i18n('edit') }}";
i18n_ext.all = "{{ i18n('all') }}";
i18n_ext.used_by = "{{ i18n('used_by') }}";
i18n_ext.others = "{{ i18n('others') }}";
i18n_ext.other = "{{ i18n('other') }}";
i18n_ext.and = "{{ i18n('and') }}";
i18n_ext.manage = "{{ i18n('host_pools.manage_pool') }}"
i18n_ext.unbounded_members = "{{ i18n('pools.unbounded_members') }}";
i18n_ext.poolFamilies = {* json.encode(pool.pool_families) *};
i18n_ext.rest = {
INVALID_HOST: "{{ i18n('rest_consts.INVALID_HOST') }}",
INVALID_ARGUMENTS: "{{ i18n('rest_consts.INVALID_ARGUMENTS') }}",
NOT_GRANTED: "{{ i18n('rest_consts.NOT_GRANTED') }}",
ADD_POOL_FAILED: "{{ i18n('rest_consts.ADD_POOL_FAILED') }}",
EDIT_POOL_FAILED: "{{ i18n('rest_consts.EDIT_POOL_FAILED') }}",
DELETE_POOL_FAILED: "{{ i18n('rest_consts.DELETE_POOL_FAILED') }}",
};
const MAX_RECIPIENTS_TO_SHOW = 10;
const renableDisabledOptions = (selector, members) => {
members.forEach(m => {
if (!all_members || !all_members[m]) return m;
// if the member name is not defined the use the member's key
const name = all_members[m].name || m;
$(`${selector} option[value='${m}']`)
.removeAttr("disabled").removeAttr("data-pool-id").text(name);
});
$(`${selector}`).selectpicker('refresh');
}
const markUsedOptions = (selector, members, poolName, poolId) => {
members.forEach(m => {
$(`${selector} option[value='${m}']`)
.attr("disabled", "disabled")
.attr("data-pool-id", poolId)
.text(`${all_members[m].name || m} (${poolName})`);
});
$(`${selector}`).selectpicker('refresh');
}
const makeDataTableColumns = () => {
const columns = [
{
data: 'name',
width: "10%",
render: function(name, type, pool) {
if (type == "display" && pool.pool_id == DEFAULT_POOL_ID) {
return `<i>${name}</i>`;
}
return name;
}
},
{
data: null,
orderable: false,
width: "40%",
render: function(data, type, row) {
/* if it's the default pool then show an unbounded members message */
if (type == "display" && row.pool_id == DEFAULT_POOL_ID) return i18n_ext.unbounded_members;
if (type == "display" && row.members.length == 0) return "";
// show only the first 10 members, append some dots
// if the members are more than 10
const memberNames = row.members.map((memberId) => {
const member = row.member_details[memberId];
if (member.name == undefined && member.hostkey == undefined) return memberId;
if (!all_members || !all_members[memberId]) {
return member.hostkey || member.name;
}
if (all_members[memberId].name == undefined) return memberId;
return all_members[memberId].name;
});
if (type == "display") {
return NtopUtils.arrayToListString(memberNames, MAX_RECIPIENTS_TO_SHOW);
}
}
},
{
data: null, targets: -1, className: 'text-center',
width: "10%",
render: function(_, type, pool) {
let changable_pool = true;
for(const pool_names of unchangable_pool_names) {
if(pool_names === pool.name) {
changable_pool = false;
break;
}
}
/* disable actions for ALL_POOL page */
if (IS_ALL_POOL) return;
const buttons = [
{ class: 'btn-info', icon: 'fa-edit', modal: '#edit-pool', title: `${i18n_ext.edit}` },
{ class: `btn-danger ${((pool.pool_id == DEFAULT_POOL_ID || IS_NEDGE) || !changable_pool) ? 'disabled' : '' }`, icon: 'fa-trash', modal: '#remove-pool', title: `${i18n_ext.delete}`}
];
if (poolType == "host") {
buttons.unshift(
{
class: `btn-info ${(pool.pool_id == DEFAULT_POOL_ID) ? 'disabled' : '' }`,
icon: 'fa-layer-group',
href: `${http_prefix}/lua/admin/manage_host_members.lua?pool=${pool.pool_id}`,
title: `${i18n_ext.manage}`
}
);
}
return DataTableUtils.createActionButtons(buttons);
}
}
];
// if the ALL_POOL page is selected then show the pool family
if (IS_ALL_POOL) {
columns.splice(1, 0, {
data: 'key',
render: (key, type, pool) => {
if (type == "display") return i18n_ext.poolFamilies[key];
return key;
}
});
}
return columns;
}
let dtConfig = DataTableUtils.getStdDatatableConfig( [
{
text: '<i class="fas fa-plus"></i>',
enabled: !IS_ALL_POOL && !IS_NEDGE,
action: () => { $(`#add-pool`).modal('show'); }
},
{
text: '<i class="fas fa-sync"></i>',
enabled: !IS_ALL_POOL,
action: function(e, dt, node, config) {
$poolTable.ajax.reload();
}
}
]);
dtConfig = DataTableUtils.setAjaxConfig(dtConfig, endpoints.get_all_pools, 'rsp');
dtConfig = DataTableUtils.extendConfig(dtConfig, {
stateSave: true,
columns: makeDataTableColumns(),
initComplete: function(settings, json) {
const tableAPI = settings.oInstance.api();
// when the data has been fetched check if the url has a pool params
DataTableUtils.openEditModalByQuery({
paramName: 'pool_id',
datatableInstance: tableAPI,
modalHandler: $editModalHandler,
});
}
});
const $poolTable = $(`#table-pools`).DataTable(dtConfig);
DataTableUtils.addToggleColumnsDropdown($poolTable);
$(`#add-pool form`).modalHandler({
method: 'post',
csrf: addCsrf,
resetAfterSubmit: false,
endpoint: endpoints.add_pool,
beforeSumbit: function() {
const members = $(`#add-pool form select[name='members']`).val() || [];
$(`#add-modal-feedback`).hide();
return {
pool_name: $(`#add-pool form input[name='name']`).val().trim(),
pool_members: members.join(',')
};
},
onSubmitSuccess: function (response, textStatus, modalHandler) {
if (response.rc < 0) {
$(`#add-modal-feedback`).html(response.rc_str_hr).fadeIn();
return;
}
const poolName = $(`#add-pool form input[name='name']`).val().trim();
if (poolType != "host") {
// get the new members array
const members = $(`#add-pool form select[name='members']`).val();
// mark select entries with the new pool created
markUsedOptions(`#add-pool form select[name='members']`, members, poolName, response.rsp.pool_id);
markUsedOptions(`#edit-pool form select[name='members']`, members, poolName, response.rsp.pool_id);
}
$poolTable.ajax.reload();
$(`#add-pool`).modal('hide');
}
}).invokeModalInit();
const $editModalHandler = $(`#edit-pool form`).modalHandler({
method: 'post',
csrf: editCsrf,
endpoint: endpoints.edit_pool,
resetAfterSubmit: false,
onModalInit: (pool) => {
let changable_pool = true;
for(const pool_names of unchangable_pool_names) {
if(pool_names === pool.name) {
changable_pool = false;
break;
}
}
// disable pool name field if we are editing the default pool
// also hide the members multiselect
if (pool.pool_id == DEFAULT_POOL_ID || !changable_pool) {
$(`#edit-pool form input[name='name']`).attr("readonly", "true");
$(`#edit-pool .members-container`).hide();
}
else {
$(`#edit-pool form input[name='name']`).removeAttr("readonly");
$(`#edit-pool .members-container`).show();
}
// disable all the options whose have a data-pool-id attribute
$(`#edit-pool form select[name='members'] option[data-pool-id]`).attr("disabled", "disabled");
// enable only the option used by the pool
$(`#edit-pool form select[name='members'] option`).each(function() {
const id = $(this).val();
// if the id belong to the pool then remove the disabled attribute
if (pool.members.indexOf(id) > -1) {
$(this).removeAttr("disabled");
}
});
$(`#edit-pool-name-input`).off('keyup').on('keyup', function() {
const name = $(this).val()
$(`[data-pool-id='${pool.pool_id}']`).each(function() {
const m = $(this).val();
$(this).text(`${all_members[m].name || m} (${name})`);
});
});
// load the modal with the pool data
$(`#edit-pool form input[name='name']`).val(pool.name);
$(`#edit-pool form select[name='members']`).val(pool.members);
$(`#edit-pool form select[name='members']`).selectpicker('refresh');
if (poolType == "host") {
const href = $(`#edit-link`).attr('href').replace(/pool\=[0-9]+/, `pool=${pool.pool_id}`);
$(`#edit-link`).attr('href', href);
}
},
beforeSumbit: (pool) => {
const members = $(`#edit-pool form select[name='members']`).val() || [];
const data = {
pool: pool.pool_id,
pool_name: $(`#edit-pool form input[name='name']`).val().trim()
};
if (poolType != "host") {
data.pool_members = members.join(',');
}
else {
data.pool_members = pool.members.join(',');
}
return data;
},
onSubmitSuccess: (response, dataSent, modalHandler) => {
const oldPoolData = modalHandler.data;
if (response.rc < 0) {
$(`#edit-modal-feedback`).html(response.rc_str_hr).fadeIn();
return;
}
const newPoolName = $(`#edit-pool form input[name='name']`).val();
// update the pool name inside the selects if changed
if (newPoolName != oldPoolData.name) {
$(`option[data-pool-id='${oldPoolData.pool_id}']`).each(function() {
const value = $(this).val();
if (poolType != "host")
$(this).text(`${all_members[value].name || value} (${i18n_ext.used_by} ${newPoolName})`)
});
}
// the host pool modals don't have any members
if (poolType != "host" && oldPoolData.pool_id != DEFAULT_POOL_ID) {
// get the newMembers and the oldMembers and create two subset of them
const oldMembers = oldPoolData.members;
const newMembers = $(`#edit-pool form select[name='members']`).val();
// this subset contains the removed members from the pool
const oldToRenable = oldMembers.filter((m1) => !newMembers.find(m2 => m1 == m2));
// this subset contains the new members added to the pool
const newToMark = newMembers.filter((m1) => !oldMembers.find(m2 => m1 == m2));
renableDisabledOptions(`#add-pool form select[name='members']`, oldToRenable);
renableDisabledOptions(`#edit-pool form select[name='members']`, oldToRenable);
markUsedOptions(`#add-pool form select[name='members']`, newToMark, newPoolName, oldPoolData.pool_id);
markUsedOptions(`#edit-pool form select[name='members']`, newToMark, newPoolName, oldPoolData.pool_id);
}
// clean the form and reload the table
$poolTable.ajax.reload();
$(`#edit-pool`).modal('hide');
}
});
const $removeModalHandler = $(`#remove-pool form`).modalHandler({
method: 'post',
csrf: removeCsrf,
endpoint: endpoints.delete_pool,
resetAfterSubmit: false,
onModalInit: (pool) => {
$(`#remove-pool form button[type='submit']`).removeAttr("disabled");
$(`.delete-pool-name`).text(pool.name);
},
beforeSumbit: (pool) => {
return { pool: pool.pool_id };
},
onSubmitSuccess: (response, textStatus, modalHandler) => {
const oldPoolData = modalHandler.data;
if (response.rc < 0) {
$(`#remove-modal-feedback`).html(response.rc_str_hr).fadeIn();
return;
}
// renable the members removed from the pool inside the modal
renableDisabledOptions(`#add-pool form select[name='members']`, oldPoolData.members);
renableDisabledOptions(`#edit-pool form select[name='members']`, oldPoolData.members);
$poolTable.ajax.reload();
$(`#remove-pool`).modal('hide');
}
});
$(`#table-pools`).on('click', `a[href='#edit-pool']`, function (e) {
const selectedPool = $poolTable.row($(this).parent().parent().parent().parent()).data();
$editModalHandler.invokeModalInit(selectedPool);
$(`#edit-pool`).modal('show')
});
$(`#table-pools`).on('click', `a[href='#remove-pool']`, function (e) {
const selectedPool = $poolTable.row($(this).parent().parent().parent().parent()).data();
$removeModalHandler.invokeModalInit(selectedPool);
$(`#remove-pool`).modal('show')
});
</script>