mirror of
https://github.com/ntop/ntopng.git
synced 2026-05-03 09:20:10 +00:00
461 lines
19 KiB
Vue
461 lines
19 KiB
Vue
<!-- (C) 2024 - ntop.org -->
|
||
<template>
|
||
<div class="m-2 mb-3">
|
||
<div class="">
|
||
<TableWithConfig ref="table_assets" :table_id="table_id" :csrf="context.csrf" :showLoading="true"
|
||
:f_map_columns="map_table_def_columns" :get_extra_params_obj="get_extra_params_obj"
|
||
@custom_event="on_table_custom_event">
|
||
<template v-slot:custom_header>
|
||
<div class="dropdown me-3 d-inline-block" v-for="item in filter_table_array">
|
||
<span class="no-wrap d-flex align-items-center my-auto me-2 filters-label"><b>{{
|
||
item["basic_label"]
|
||
}}</b></span>
|
||
<!-- :key="host_filters_key" -->
|
||
<SelectSearch v-model:selected_option="item['current_option']" theme="bootstrap-5"
|
||
dropdown_size="small" :options="item['options']" @select_option="add_table_filter">
|
||
</SelectSearch>
|
||
</div>
|
||
<div class="d-flex justify-content-center align-items-center">
|
||
<div class="btn btn-sm btn-primary mt-2 me-3" type="button" @click="reset_filters">
|
||
{{ _i18n('reset') }}
|
||
</div>
|
||
</div>
|
||
</template> <!-- Dropdown filters -->
|
||
</TableWithConfig>
|
||
<div class="card-footer mt-3">
|
||
<button class="btn btn-primary me-1" type="button" @click="import_assets">
|
||
<i class="fa-solid fa-file-arrow-down" data-bs-toggle="tooltip" data-bs-placement="top"
|
||
:title="_i18n('asset_details.import')"></i> {{
|
||
_i18n('asset_details.import') }}
|
||
</button>
|
||
<a class="btn btn-primary" download="assets.csv" :href="export_assets_url">
|
||
<i class="fa-solid fa-file-arrow-up" data-bs-toggle="tooltip" data-bs-placement="top"
|
||
:title="_i18n('asset_details.export')"></i> {{
|
||
_i18n('asset_details.export') }}
|
||
</a>
|
||
<button v-if="props.context.is_admin" type="button" @click="delete_assets()"
|
||
class="btn btn-danger ms-1">
|
||
<i class="fas fa fa-trash"></i>
|
||
{{ _i18n("delete_all_entries") }}
|
||
</button>
|
||
<button v-if="props.context.is_admin" type="button" @click="delete_assets_epoch"
|
||
class="btn btn-danger ms-1">
|
||
<i class="fas fa fa-trash"></i>
|
||
{{ _i18n("asset_details.delete_asset_older_title") }}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<ModalImportAssets ref="modal_import_assets" :context="context" @add="import_assets_rest">
|
||
</ModalImportAssets>
|
||
<ModalDeleteAssets ref="modal_delete_assets" :context="context" @delete="refresh_table">
|
||
</ModalDeleteAssets>
|
||
<ModalDeleteAssetsEpoch ref="modal_delete_assets_epoch" :context="context" @delete="refresh_table">
|
||
</ModalDeleteAssetsEpoch>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, nextTick, onMounted } from "vue";
|
||
import { default as TableWithConfig } from "./table-with-config.vue";
|
||
import { default as SelectSearch } from "./select-search.vue";
|
||
import { default as dataUtils } from "../utilities/data-utils.js";
|
||
import { default as osUtils } from "../utilities/map/os-utils.js";
|
||
import { default as ModalDeleteAssets } from "./modal-delete-assets.vue";
|
||
import { default as ModalDeleteAssetsEpoch } from "./modal-delete-assets-epoch.vue";
|
||
import { default as ModalImportAssets } from "./modal-import-assets.vue"
|
||
import { ntopng_url_manager } from "../services/context/ntopng_globals_services.js";
|
||
import FormatterUtils from "../utilities/formatter-utils.js";
|
||
|
||
/* ************************************** */
|
||
|
||
const props = defineProps({
|
||
context: Object,
|
||
});
|
||
|
||
const _i18n = (t) => i18n(t);
|
||
|
||
/* ************************************** */
|
||
|
||
const import_assets_url = `${http_prefix}/lua/pro/rest/v2/add/assets/assets.lua`;
|
||
// For the export, it’s necessary to know if the page is the SNMP page
|
||
const export_assets_url = `${http_prefix}/lua/pro/rest/v2/export/assets/assets.lua?is_snmp=${props.context.is_system_interface}`
|
||
const modal_import_assets = ref();
|
||
|
||
const host_filters_key = ref(0);
|
||
const table_id = ref(props.context.is_system_interface ? 'assets_snmp' : 'assets');
|
||
const filter_table_array = ref([]);
|
||
const table_assets = ref();
|
||
const modal_delete_assets = ref();
|
||
const modal_delete_assets_epoch = ref();
|
||
const child_safe_icon = "<font color='#5cb85c'><i class='fas fa-lg fa-child' aria-hidden='true' title='" + i18n("host_pools.children_safe") + "'></i></font>"
|
||
const system_host_icon = "<i class='fas fa-flag' title='" + i18n("system_host") + "'></i>"
|
||
const hidden_from_top_icon = "<i class='fas fa-eye-slash' title='" + i18n("hidden_from_top_talkers") + "'></i>"
|
||
const dhcp_host_icon = '<i class="fa-solid fa-bolt" title="DHCP Host"></i>'
|
||
const blacklisted_icon = "<i class='fas fa-ban fa-sm' title='" + i18n("hosts_stats.blacklisted") + "'></i>"
|
||
const crawler_bot_scanner_host_icon = "<i class='fas fa-spider fa-sm' title='" + i18n("hosts_stats.crawler_bot_scanner") + "'></i>"
|
||
const multicast_icon = "<abbr title='" + i18n("multicast") + "'><span class='badge bg-primary'>" + i18n("short_multicast") + "</span></abbr>"
|
||
const localhost_icon = "<abbr data-bs-toggle='tooltip' data-bs-placement='top' data-bs-original-title='" + i18n("details.label_local_host") + "'><span class='badge bg-success'>" + i18n("details.label_short_local_host") + "</span></abbr>"
|
||
const remotehost_icon = "<abbr title='" + i18n("details.label_remote") + "'><span class='badge bg-secondary'>" + i18n("details.label_short_remote") + "</span></abbr>"
|
||
const blackhole_icon = "<abbr title='" + i18n("details.label_blackhole") + "'><span class='badge bg-info'>" + i18n("details.label_short_blackhole") + "</span></abbr>"
|
||
const blocking_quota_icon = "<i class='fas fa-hourglass' title='" + i18n("hosts_stats.blocking_traffic_policy_popup_msg") + "'></i>"
|
||
|
||
/* ************************************** */
|
||
|
||
const map_table_def_columns = (columns) => {
|
||
let map_columns = {
|
||
"ip_address": (value, row) => {
|
||
const host = row.host
|
||
let ip_address = host.ip
|
||
let icons = ''
|
||
|
||
if (dataUtils.isEmptyOrNull(ip_address)) {
|
||
return ''
|
||
}
|
||
let is_asset_online = row.online;
|
||
|
||
if (!dataUtils.isEmptyOrNull(host.vlan.name)) {
|
||
ip_address = `${ip_address}@${host.vlan.name}`
|
||
}
|
||
if (!dataUtils.isEmptyOrNull(host.system_host)) {
|
||
icons = `${icons} ${system_host_icon}`
|
||
}
|
||
if (!dataUtils.isEmptyOrNull(host.os)) {
|
||
const os_icon = osUtils.getOS(host.os);
|
||
icons = `${icons} ${os_icon.icon}`
|
||
}
|
||
if (!dataUtils.isEmptyOrNull(host.device_type)) {
|
||
icons = `${icons} ${osUtils.getAssetIcon(host.device_type) || ''}`
|
||
}
|
||
if (!dataUtils.isEmptyOrNull(host.hidden_from_top)) {
|
||
icons = `${icons} ${hidden_from_top_icon}`
|
||
}
|
||
if (!dataUtils.isEmptyOrNull(host.child_safe)) {
|
||
icons = `${icons} ${child_safe_icon}`
|
||
}
|
||
if (!dataUtils.isEmptyOrNull(host.dhcp_host)) {
|
||
icons = `${icons} ${dhcp_host_icon}`
|
||
}
|
||
if (!dataUtils.isEmptyOrNull(host.blocking_traffic_policy)) {
|
||
icons = `${icons} ${blocking_quota_icon}`
|
||
}
|
||
if (!dataUtils.isEmptyOrNull(host.country)) {
|
||
icons = `${icons} <a href='${http_prefix}/lua/hosts_stats.lua?country=${host.country}'><img src='${http_prefix}/dist/images/blank.gif' class='flag flag-${host.country.toLowerCase()}'></a>`
|
||
}
|
||
if (!dataUtils.isEmptyOrNull(host.is_blacklisted)) {
|
||
icons = `${icons} ${blacklisted_icon}`
|
||
}
|
||
if (!dataUtils.isEmptyOrNull(host.crawler_bot_scanner_host)) {
|
||
icons = `${icons} ${crawler_bot_scanner_host_icon}`
|
||
}
|
||
if (!dataUtils.isEmptyOrNull(host.is_multicast)) {
|
||
icons = `${icons} ${multicast_icon}`
|
||
}
|
||
|
||
if (!dataUtils.isEmptyOrNull(host.remotehost)) {
|
||
icons = `${icons} ${remotehost_icon}`
|
||
}
|
||
if (!dataUtils.isEmptyOrNull(host.is_blackhole)) {
|
||
icons = `${icons} ${blackhole_icon}`
|
||
}
|
||
if (!dataUtils.isEmptyOrNull(host.is_dhcp_server)) {
|
||
icons = `${icons} <span class="badge bg-success">${i18n("details.label_dhcp_server")}</span>`
|
||
}
|
||
if (!dataUtils.isEmptyOrNull(host.is_dns_server)) {
|
||
icons = `${icons} <span class="badge bg-success">${i18n("details.label_dns_server")}</span>`
|
||
}
|
||
if (!dataUtils.isEmptyOrNull(host.is_smtp_server)) {
|
||
icons = `${icons} <span class="badge bg-success">${i18n("details.label_smtp_server")}</span>`
|
||
}
|
||
if (!dataUtils.isEmptyOrNull(host.is_ntp_server)) {
|
||
icons = `${icons} <span class="badge bg-success">${i18n("details.label_ntp_server")}</span>`
|
||
}
|
||
if (!dataUtils.isEmptyOrNull(host.is_imap_server)) {
|
||
icons = `${icons} <span class="badge bg-success">${i18n("details.label_imap_server")}</span>`
|
||
}
|
||
if (!dataUtils.isEmptyOrNull(host.is_pop_server)) {
|
||
icons = `${icons} <span class="badge bg-success">${i18n("details.label_pop_server")}</span>`
|
||
}
|
||
if (!dataUtils.isEmptyOrNull(host.is_ssh_server)) {
|
||
icons = `${icons} <span class="badge bg-success">${i18n("details.label_ssh_server")}</span>`
|
||
}
|
||
if (!dataUtils.isEmptyOrNull(host.is_http_server)) {
|
||
icons = `${icons} <span class="badge bg-success">${i18n("details.label_http_server")}</span>`
|
||
}
|
||
if (!dataUtils.isEmptyOrNull(host.is_rdp_server)) {
|
||
icons = `${icons} <span class="badge bg-success">${i18n("details.label_rdp_server")}</span>`
|
||
}
|
||
if (!dataUtils.isEmptyOrNull(host.is_modbus_server)) {
|
||
icons = `${icons} <span class="badge bg-success">${i18n("details.label_modbus_server")}</span>`
|
||
}
|
||
if (!dataUtils.isEmptyOrNull(host.is_s7comm_server)) {
|
||
icons = `${icons} <span class="badge bg-success">${i18n("details.label_s7comm_server")}</span>`
|
||
}
|
||
if (!dataUtils.isEmptyOrNull(host.is_profinet_server)) {
|
||
icons = `${icons} <span class="badge bg-success">${i18n("details.label_profinet_server")}</span>`
|
||
}
|
||
|
||
const host_url = create_button_host_details(row);
|
||
|
||
// If host is online show host details icon fas-laptop to jump to host details page
|
||
let host_icon = `<a href='/lua/host_details.lua?host=${row.host.ip}&vlan=${row.host.vlan.id}' data-bs-toggle='tooltip' data-bs-placement='top' title='Host Details'><i class='fas fa-laptop'></i></a>`;
|
||
|
||
if (is_asset_online) {
|
||
return `<a href="${host_url}">${ip_address}</a> ${host_icon} ${icons}`
|
||
}
|
||
|
||
return `<a href="${host_url}">${ip_address}</a> ${icons}`
|
||
|
||
},
|
||
"host_name": (value, row) => {
|
||
let name = value.name
|
||
if (!dataUtils.isEmptyOrNull(value.alt_name)) {
|
||
name = value.alt_name
|
||
if (value.alt_name != value.name && !dataUtils.isEmptyOrNull(value.name)) {
|
||
name = `${name} [${value.name}]`
|
||
}
|
||
}
|
||
|
||
return name
|
||
},
|
||
"switch_ip": (value, row) => {
|
||
const url = http_prefix + "/lua/pro/enterprise/snmp_device_details.lua?host=" + value.value
|
||
if (!dataUtils.isEmptyOrNull(value.name) && value.name != value.value) {
|
||
return `<span data-bs-toggle="tooltip" data-bs-placement="top" data-bs-original-title='${value.value}'><a href='${url}'>${value.name}</a></span>`
|
||
}
|
||
return `<a href='${url}'>${value.value}</a>`
|
||
},
|
||
"switch_port": (value, row) => {
|
||
const url = http_prefix + "/lua/pro/enterprise/snmp_interface_details.lua?host=" + row.switch_ip.value + "&snmp_port_idx=" + value.value
|
||
if (!dataUtils.isEmptyOrNull(value.name) && value.name != value.value) {
|
||
return `<span data-bs-toggle="tooltip" data-bs-placement="top" data-bs-original-title='${value.value}'><a href='${url}'>${value.name}</a></span>`
|
||
}
|
||
return `<a href='${url}'>${value.value}</a>`
|
||
},
|
||
"mac": (value, row) => {
|
||
let result = value.value
|
||
if (!dataUtils.isEmptyOrNull(value.name)) {
|
||
result = `<span data-bs-toggle="tooltip" data-bs-placement="top" data-bs-original-title='${value.value}'>${value.name}</span>`
|
||
}
|
||
if (value.is_in_memory) {
|
||
result = `<a href='${http_prefix}/lua/mac_details.lua?host=${value.value}'>${result}</a>`
|
||
}
|
||
|
||
return result;
|
||
},
|
||
"manufacturer": (value, row) => {
|
||
return value;
|
||
},
|
||
"model": (value, row) => {
|
||
return value;
|
||
},
|
||
"status": (value, row) => {
|
||
let badge = `<span class="badge bg-secondary">${i18n('asset_details.offline')}</span>`
|
||
|
||
if (row.online) {
|
||
badge = `<span class="badge bg-success">${i18n('asset_details.online')}</span>`
|
||
}
|
||
return badge
|
||
},
|
||
"first_seen": (value, row) => {
|
||
return FormatterUtils.formatDateTime(value.timestamp)
|
||
},
|
||
"last_seen": (value, row) => {
|
||
if (row.online) {
|
||
return ""
|
||
}
|
||
return FormatterUtils.formatDateTime(value.timestamp)
|
||
}
|
||
};
|
||
|
||
columns.forEach((c) => {
|
||
c.render_func = map_columns[c.data_field];
|
||
if (c.id == "actions") {
|
||
const visible_dict = {
|
||
historical_flows: props.context.historical_available,
|
||
details: true,
|
||
delete: props.context.is_admin
|
||
};
|
||
c.button_def_array.forEach((b) => {
|
||
if (!visible_dict[b.id]) {
|
||
b.class.push("disabled");
|
||
}
|
||
});
|
||
}
|
||
});
|
||
|
||
return columns;
|
||
};
|
||
|
||
/* ************************************** */
|
||
|
||
function delete_assets_epoch() {
|
||
modal_delete_assets_epoch.value.show();
|
||
}
|
||
|
||
/* ************************************** */
|
||
|
||
function delete_assets(row) {
|
||
modal_delete_assets.value.show(row);
|
||
}
|
||
|
||
/* ************************************** */
|
||
|
||
function reset_filters() {
|
||
filter_table_array.value.forEach((el, index) => {
|
||
/* Getting the currently selected filter */
|
||
ntopng_url_manager.set_key_to_url(el.id, ``);
|
||
})
|
||
load_table_filters_array();
|
||
refresh_table();
|
||
}
|
||
|
||
/* ************************************** */
|
||
|
||
function set_filter_array_label() {
|
||
filter_table_array.value.forEach((el, index) => {
|
||
/* Setting the basic label */
|
||
if (el.basic_label == null) {
|
||
el.basic_label = el.label;
|
||
}
|
||
|
||
/* Getting the currently selected filter */
|
||
const url_entry = ntopng_url_manager.get_url_entry(el.id)
|
||
el.options.forEach((option) => {
|
||
if (option.value.toString() === url_entry) {
|
||
el.current_option = option;
|
||
}
|
||
})
|
||
})
|
||
}
|
||
|
||
/* ************************************** */
|
||
|
||
async function add_table_filter(opt) {
|
||
ntopng_url_manager.set_key_to_url(opt.key, `${opt.value}`);
|
||
set_filter_array_label();
|
||
table_assets.value.refresh_table();
|
||
}
|
||
|
||
/* ************************************** */
|
||
|
||
async function load_table_filters_array() {
|
||
let extra_params = get_extra_params_obj();
|
||
let url_params = ntopng_url_manager.obj_to_url_params(extra_params);
|
||
const url = `${http_prefix}/lua/pro/rest/v2/get/host/assets_filters.lua?${url_params}`;
|
||
let res = await ntopng_utility.http_request(url);
|
||
host_filters_key.value = host_filters_key.value + 1
|
||
|
||
filter_table_array.value = res.map((t) => {
|
||
const key_in_url = ntopng_url_manager.get_url_entry(t.name);
|
||
if (dataUtils.isEmptyOrNull(key_in_url)) {
|
||
ntopng_url_manager.set_key_to_url(t.name, ``);
|
||
}
|
||
return {
|
||
id: t.name,
|
||
label: t.label,
|
||
title: t.tooltip,
|
||
options: t.value,
|
||
hidden: (t.value.length == 1)
|
||
};
|
||
});
|
||
set_filter_array_label();
|
||
}
|
||
|
||
/* ************************************** */
|
||
|
||
const get_extra_params_obj = () => {
|
||
let extra_params = ntopng_url_manager.get_url_object();
|
||
extra_params = {
|
||
...{ ifid: props.context.ifid },
|
||
...extra_params,
|
||
}
|
||
return extra_params;
|
||
};
|
||
|
||
/* ************************************** */
|
||
|
||
function create_historical_flows_url_link(row) {
|
||
return `${http_prefix}/lua/pro/db_search.lua?ip=${row.host.ip};eq&vlan_id=${row.host.vlan.id};eq&epoch_begin=${row.first_seen.timestamp}&epoch_end=${row.last_seen.timestamp}`
|
||
}
|
||
|
||
/* ************************************** */
|
||
|
||
function create_button_host_details(row) {
|
||
let url = `/lua/pro/asset_details.lua?ifid=${props.context.ifid}&serial_key=${row.key}`
|
||
|
||
return `${http_prefix}${url}`
|
||
}
|
||
|
||
/* ************************************** */
|
||
|
||
function click_button_delete(event) {
|
||
const row = event.row;
|
||
delete_assets(row);
|
||
}
|
||
|
||
/* ************************************** */
|
||
|
||
function click_button_historical_flows(event) {
|
||
const row = event.row;
|
||
window.open(create_historical_flows_url_link(row));
|
||
}
|
||
|
||
/* ************************************** */
|
||
|
||
function click_button_host_details(event) {
|
||
const row = event.row;
|
||
window.open(create_button_host_details(row));
|
||
}
|
||
|
||
/* ************************************** */
|
||
|
||
function on_table_custom_event(event) {
|
||
let events_managed = {
|
||
"click_button_historical_flows": click_button_historical_flows,
|
||
"click_button_host_details": click_button_host_details,
|
||
"click_button_delete": click_button_delete,
|
||
};
|
||
if (events_managed[event.event_id] == null) {
|
||
return;
|
||
}
|
||
events_managed[event.event_id](event);
|
||
}
|
||
|
||
/* ************************************** */
|
||
|
||
function refresh_table() {
|
||
table_assets.value.refresh_table();
|
||
}
|
||
|
||
/* ************************************** */
|
||
|
||
function import_assets() {
|
||
modal_import_assets.value.show();
|
||
}
|
||
|
||
/* ************************************** */
|
||
|
||
const import_assets_rest = async function (params) {
|
||
const url = import_assets_url;
|
||
const result = await ntopng_utility.http_post_request(url, { ...{ csrf: props.context.csrf }, ...params }, false, true);
|
||
|
||
if (result == null) {
|
||
modal_import_assets.value.show_bad_feedback(_i18n("asset_details.import_error"));
|
||
} else if (result.rc < 0) {
|
||
modal_import_assets.value.show_bad_feedback(result.rsp.feedback);
|
||
refresh_table();
|
||
} else {
|
||
setTimeout(() => { modal_import_assets.value.close(); refresh_table(); }, 1000);
|
||
}
|
||
}
|
||
|
||
/* ************************************** */
|
||
|
||
onMounted(async () => {
|
||
load_table_filters_array();
|
||
});
|
||
|
||
/* ************************************** */
|
||
|
||
</script>
|