mirror of
https://github.com/ntop/ntopng.git
synced 2026-05-05 02:16:39 +00:00
857 lines
35 KiB
Vue
857 lines
35 KiB
Vue
<!-- (C) 2022 - ntop.org -->
|
|
<template>
|
|
<div class="col-12 mb-2 mt-2">
|
|
<AlertInfo></AlertInfo>
|
|
<div class="card h-100 overflow-hidden">
|
|
<DateTimeRangePicker style="margin-top:0.5rem;" class="ms-1" :id="id_date_time_picker"
|
|
:enable_refresh="true" ref="date_time_picker" @epoch_change="epoch_change"
|
|
:min_time_interval_id="min_time_interval_id" :custom_time_interval_list="time_preset_list">
|
|
<template v-slot:begin>
|
|
</template>
|
|
<template v-slot:extra_buttons>
|
|
<button v-if="enable_snapshots" class="btn btn-link btn-sm" @click="show_modal_snapshot"
|
|
:title="_i18n('page_stats.manage_snapshots_btn')"><i
|
|
class="fas fa-lg fa-camera-retro"></i></button>
|
|
<button v-if="traffic_extraction_permitted" class="btn btn-link btn-sm"
|
|
@click="show_modal_traffic_extraction" :title="_i18n('traffic_recording.pcap_download')"><i
|
|
class="fas fa-lg fa-download"></i></button>
|
|
<button :disabled="is_safari" class="btn btn-link btn-sm" @click="show_modal_download_file"
|
|
:title="image_button_title"><i class="fas fa-lg fa-file-image"></i></button>
|
|
<button v-if="is_history_enabled" class="btn btn-link btn-sm" @click="jump_to_historical_flows"
|
|
:title="_i18n('page_stats.historical_flows')"><i class="fas fa-search-plus"></i></button>
|
|
</template>
|
|
</DateTimeRangePicker>
|
|
<!-- select metric -->
|
|
<div v-show="ts_menu_ready" class="form-group ms-1 mt-2 d-flex align-items-center">
|
|
<div class="inline select2-size me-2">
|
|
<SelectSearch v-model:selected_option="selected_metric" :options="metrics"
|
|
@select_option="select_metric">
|
|
</SelectSearch>
|
|
</div>
|
|
<div class="inline select2-size me-2">
|
|
<SelectSearch v-model:selected_option="current_groups_options_mode" :options="groups_options_modes"
|
|
@select_option="change_groups_options_mode">
|
|
</SelectSearch>
|
|
</div>
|
|
<button type="button" @click="show_manage_timeseries" class="btn btn-sm btn-primary inline"
|
|
style='vertical-align: super;' v-if="is_ntop_pro">
|
|
Manage Timeseries
|
|
</button>
|
|
|
|
</div>
|
|
|
|
<template v-for="(item, i) in charts_options_items" :key="item.key">
|
|
<TimeseriesChart :id="id_chart + i" :ref="el => { charts[i] = el }" :chart_type="chart_type"
|
|
:register_on_status_change="false" :get_custom_chart_options="get_f_get_custom_chart_options(i)"
|
|
@zoom="epoch_change" @chart_reloaded="chart_reloaded">
|
|
</TimeseriesChart>
|
|
</template>
|
|
</div>
|
|
|
|
<div class="mt-4 card card-shadow" v-if="enable_stats_table">
|
|
<div class="card-body">
|
|
<BootstrapTable id="page_stats_bootstrap_table" :columns="stats_columns" :rows="stats_rows"
|
|
:print_html_column="(col) => print_stats_column(col)"
|
|
:print_html_row="(col, row) => print_stats_row(col, row)">
|
|
</BootstrapTable>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-4 card card-shadow" v-if="is_ntop_pro">
|
|
<div class="card-body">
|
|
<div v-if="selected_top_table?.table_config_def" class="inline select2-size me-2 mt-2">
|
|
<SelectSearch v-model:selected_option="selected_top_table" :options="top_table_options">
|
|
</SelectSearch>
|
|
</div>
|
|
<Datatable v-if="selected_top_table?.table_config_def" :key="selected_top_table?.value"
|
|
ref="top_table_ref" :table_buttons="selected_top_table.table_config_def.table_button"
|
|
:columns_config="selected_top_table.table_config_def.columns_config"
|
|
:data_url="selected_top_table.table_config_def.data_url"
|
|
:enable_search="selected_top_table.table_config_def.enable_search"
|
|
:table_config="selected_top_table.table_config_def.table_config">
|
|
</Datatable>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<ModalSnapshot v-if="enable_snapshots" ref="modal_snapshot" :csrf="csrf" :page="page_snapshots"
|
|
@added_snapshot="refresh_snapshots" @deleted_snapshots="refresh_snapshots"
|
|
@deleted_all_snapshots="refresh_snapshots">
|
|
</ModalSnapshot>
|
|
|
|
<ModalTimeseries v-if="is_ntop_pro" ref="modal_timeseries" :sources_types_enabled="sources_types_enabled"
|
|
@apply="apply_modal_timeseries">
|
|
</ModalTimeseries>
|
|
|
|
<ModalTrafficExtraction id="page_stats_modal_traffic_extraction" ref="modal_traffic_extraction">
|
|
</ModalTrafficExtraction>
|
|
|
|
<ModalDownloadFile ref="modal_download_file" :title="_i18n('page_stats.title_modal_download_file')" ext="png"
|
|
@download="download_chart_png">
|
|
</ModalDownloadFile>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, onMounted, onBeforeMount, computed, watch } from "vue";
|
|
import { default as TimeseriesChart } from "./timeseries-chart.vue";
|
|
import { default as DateTimeRangePicker } from "./date-time-range-picker.vue";
|
|
import { default as ModalSnapshot } from "./modal-snapshot.vue";
|
|
import { default as ModalTimeseries } from "./modal-timeseries.vue";
|
|
import { default as ModalTrafficExtraction } from "./modal-traffic-extraction.vue";
|
|
import { default as ModalDownloadFile } from "./modal-download-file.vue";
|
|
import { default as AlertInfo } from "./alert-info.vue";
|
|
import { default as dataUtils } from "../utilities/data-utils.js";
|
|
|
|
import { default as SelectSearch } from "./select-search.vue";
|
|
import { default as Datatable } from "./datatable.vue";
|
|
import { default as BootstrapTable } from "./bootstrap-table.vue";
|
|
|
|
import { ntopng_utility, ntopng_url_manager, ntopng_status_manager } from "../services/context/ntopng_globals_services.js";
|
|
import timeseriesUtils from "../utilities/timeseries-utils.js";
|
|
import metricsManager from "../utilities/metrics-manager.js";
|
|
import formatterUtils from "../utilities/formatter-utils";
|
|
import NtopUtils from "../utilities/ntop-utils";
|
|
|
|
const props = defineProps({
|
|
csrf: String,
|
|
is_ntop_pro: Boolean,
|
|
source_value_object: Object,
|
|
sources_types_enabled: Object,
|
|
sources_types_top_enabled: Object,
|
|
enable_snapshots: Boolean,
|
|
is_history_enabled: Boolean,
|
|
traffic_extraction_permitted: Boolean,
|
|
is_dark_mode: Boolean,
|
|
});
|
|
|
|
//ntopng_utility.check_and_set_default_time_interval();
|
|
|
|
const _i18n = (t) => i18n(t);
|
|
let id_chart = "chart";
|
|
let id_date_time_picker = "date_time_picker";
|
|
let chart_type = ntopChartApex.typeChart.TS_LINE;
|
|
const config_app_table = ref({});
|
|
const init_config_table = ref(false);
|
|
const charts = ref([]);
|
|
const date_time_picker = ref(null);
|
|
const top_table_ref = ref(null);
|
|
const modal_timeseries = ref(null);
|
|
const modal_snapshot = ref(null);
|
|
const modal_download_file = ref(null);
|
|
|
|
const is_safari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
|
|
const image_button_title = is_safari ? _i18n('page_stats.download_image_disabled') : _i18n('page_stats.title_modal_download_file');
|
|
|
|
const min_time_interval_id = ref(null);
|
|
const metrics = ref([]);
|
|
const selected_metric = ref({});
|
|
const source_type = metricsManager.get_current_page_source_type();
|
|
|
|
const enable_stats_table = ref(false);
|
|
const enable_top_table = ref(false);
|
|
|
|
/**
|
|
* { key: identifier of Chart component, if change Chart will be destroyed and recreated,
|
|
* chart_options: chart options }[]
|
|
**/
|
|
const charts_options_items = ref([]);
|
|
|
|
/**
|
|
* Modes that represent how it's possible display timeseries.
|
|
*/
|
|
const groups_options_modes = ntopng_utility.object_to_array(timeseriesUtils.groupsOptionsModesEnum);
|
|
/**
|
|
* Current display timeseries mode.
|
|
*/
|
|
const current_groups_options_mode = ref(init_groups_option_mode());
|
|
|
|
let last_timeseries_groups_loaded = null;
|
|
|
|
const custom_metric = { label: i18n('page_stats.custom_metrics'), currently_active: false };
|
|
|
|
const page_snapshots = "timeseries";
|
|
|
|
const ts_menu_ready = ref(false);
|
|
const time_preset_list = [
|
|
{ value: "10_min", label: i18n('show_alerts.presets.10_min'), currently_active: false },
|
|
{ value: "30_min", label: i18n('show_alerts.presets.30_min'), currently_active: true },
|
|
{ value: "hour", label: i18n('show_alerts.presets.hour'), currently_active: false },
|
|
{ value: "2_hours", label: i18n('show_alerts.presets.2_hours'), currently_active: false },
|
|
{ value: "6_hours", label: i18n('show_alerts.presets.6_hours'), currently_active: false },
|
|
{ value: "12_hours", label: i18n('show_alerts.presets.12_hours'), currently_active: false },
|
|
{ value: "day", label: i18n('show_alerts.presets.day'), currently_active: false },
|
|
{ value: "week", label: i18n('show_alerts.presets.week'), currently_active: false },
|
|
{ value: "month", label: i18n('show_alerts.presets.month'), currently_active: false },
|
|
{ value: "year", label: i18n('show_alerts.presets.year'), currently_active: false },
|
|
{ value: "custom", label: i18n('show_alerts.presets.custom'), currently_active: false, disabled: true, },
|
|
];
|
|
|
|
function init_groups_option_mode() {
|
|
let groups_mode = ntopng_url_manager.get_url_entry("timeseries_groups_mode");
|
|
if (groups_mode != null && groups_mode != "") {
|
|
return timeseriesUtils.getGroupOptionMode(groups_mode);
|
|
}
|
|
return groups_options_modes[0];
|
|
}
|
|
|
|
function set_default_source_object_in_url() {
|
|
if (props.source_value_object == null) { return; }
|
|
let source_type = metricsManager.get_current_page_source_type();
|
|
metricsManager.set_source_value_object_in_url(source_type, props.source_value_object);
|
|
}
|
|
|
|
onBeforeMount(async () => {
|
|
|
|
if (ntopng_url_manager.get_url_entry("page") == "va_historical") {
|
|
let columns_tmp = [];
|
|
stats_columns.forEach((item) => {
|
|
if (item.va) {
|
|
columns_tmp.push(item);
|
|
}
|
|
})
|
|
|
|
stats_columns = columns_tmp;
|
|
}
|
|
|
|
if (props.source_value_object.is_va) {
|
|
min_time_interval_id.value = "hour";
|
|
ntopng_utility.check_and_set_default_time_interval("day");
|
|
};
|
|
|
|
set_default_source_object_in_url();
|
|
});
|
|
|
|
onMounted(async () => {
|
|
init();
|
|
await Promise.all([
|
|
ntopng_sync.on_ready(id_date_time_picker),
|
|
]);
|
|
// chart.value.register_status();
|
|
});
|
|
|
|
async function init() {
|
|
//get_default_timeseries_groups
|
|
let push_custom_metric = true;
|
|
let timeseries_groups = await metricsManager.get_timeseries_groups_from_url(http_prefix);
|
|
let metric_ts_schema;
|
|
let metric_query;
|
|
if (timeseries_groups == null) {
|
|
push_custom_metric = false;
|
|
metric_ts_schema = ntopng_url_manager.get_url_entry("ts_schema");
|
|
let ts_query = ntopng_url_manager.get_url_entry("ts_query");
|
|
if (ts_query != null && ts_query != "") {
|
|
metric_query = metricsManager.get_metric_query_from_ts_query(ts_query);
|
|
}
|
|
if (metric_ts_schema == "") { metric_ts_schema = null; }
|
|
timeseries_groups = await metricsManager.get_default_timeseries_groups(http_prefix, metric_ts_schema, metric_query);
|
|
}
|
|
metrics.value = await get_metrics(push_custom_metric);
|
|
|
|
if (push_custom_metric == true) {
|
|
selected_metric.value = custom_metric;
|
|
} else {
|
|
selected_metric.value = metricsManager.get_default_metric(metrics.value, metric_ts_schema, metric_query);
|
|
}
|
|
ts_menu_ready.value = true;
|
|
await load_page_stats_data(timeseries_groups, true, true);
|
|
}
|
|
|
|
let last_push_custom_metric = null;
|
|
async function get_metrics(push_custom_metric, force_refresh) {
|
|
let metrics = await metricsManager.get_metrics(http_prefix);
|
|
if (!force_refresh && last_push_custom_metric == push_custom_metric) { return metrics.value; }
|
|
|
|
if (push_custom_metric) {
|
|
metrics.push(custom_metric);
|
|
}
|
|
if (cache_snapshots == null || force_refresh) {
|
|
cache_snapshots = await get_snapshots_metrics();
|
|
}
|
|
if (props.enable_snapshots) {
|
|
let snapshots_metrics = cache_snapshots;
|
|
snapshots_metrics.forEach((sm) => metrics.push(sm));
|
|
}
|
|
/* Order Metrics */
|
|
if (metrics.length > 0)
|
|
metrics.sort(NtopUtils.sortAlphabetically);
|
|
|
|
return metrics;
|
|
}
|
|
|
|
async function get_snapshots_metrics() {
|
|
if (!props.enable_snapshots) { return; }
|
|
let url = `${http_prefix}/lua/pro/rest/v2/get/filters/snapshots.lua?page=${page_snapshots}`;
|
|
|
|
let snapshots_obj = await ntopng_utility.http_request(url);
|
|
let snapshots = ntopng_utility.object_to_array(snapshots_obj);
|
|
let metrics_snapshots = snapshots.map((s) => {
|
|
return {
|
|
...s,
|
|
is_snapshot: true,
|
|
label: `${s.name}`,
|
|
group: "Snapshots",
|
|
};
|
|
});
|
|
return metrics_snapshots;
|
|
}
|
|
|
|
async function get_selected_timeseries_groups() {
|
|
let metric = selected_metric.value;
|
|
return get_timeseries_groups_from_metric(metric);
|
|
}
|
|
|
|
async function get_timeseries_groups_from_metric(metric) {
|
|
let source_type = metricsManager.get_current_page_source_type();
|
|
let source_array = await metricsManager.get_default_source_array(http_prefix, source_type);
|
|
let ts_group = metricsManager.get_ts_group(source_type, source_array, metric);
|
|
let timeseries_groups = [ts_group];
|
|
return timeseries_groups;
|
|
}
|
|
|
|
const add_ts_group_from_source_value_dict = async (source_type_id, source_value_dict, metric_schema) => {
|
|
let source_type = metricsManager.get_source_type_from_id(source_type_id);
|
|
let source_array = await metricsManager.get_source_array_from_value_dict(http_prefix, source_type, source_value_dict);
|
|
let metric = await metricsManager.get_metric_from_schema(http_prefix, source_type, source_array, metric_schema);
|
|
let ts_group = metricsManager.get_ts_group(source_type, source_array, metric);
|
|
add_ts_group(ts_group);
|
|
};
|
|
|
|
const add_metric_from_metric_schema = async (metric_schema, metric_query) => {
|
|
let metric = metrics.value.find((m) => m.schema == metric_schema && m.query == metric_query);
|
|
if (metric == null) {
|
|
console.error(`metric = ${metric_schema}, query = ${metric_query} not found.`);
|
|
return;
|
|
}
|
|
let timeseries_groups = await get_timeseries_groups_from_metric(metric);
|
|
// modal_timeseries.value.set_timeseries_groups(last_timeseries_groups_loaded);
|
|
// modal_timeseries.value.add_ts_group(timeseries_groups[0], true);
|
|
add_ts_group(timeseries_groups[0]);
|
|
};
|
|
|
|
function add_ts_group(ts_group) {
|
|
modal_timeseries.value.set_timeseries_groups(last_timeseries_groups_loaded);
|
|
modal_timeseries.value.add_ts_group(ts_group, true);
|
|
}
|
|
|
|
async function select_metric(metric) {
|
|
if (metric.is_snapshot == true) {
|
|
let url_parameters = metric.filters;
|
|
let timeseries_url_params = ntopng_url_manager.get_url_entry("timeseries_groups", url_parameters);
|
|
let timeseries_groups = await metricsManager.get_timeseries_groups_from_url(http_prefix, timeseries_url_params);
|
|
current_groups_options_mode.value = timeseriesUtils.getGroupOptionMode(ntopng_url_manager.get_url_entry("timeseries_groups_mode", url_parameters));
|
|
await load_page_stats_data(timeseries_groups, true, false);
|
|
} else {
|
|
await load_selected_metric_page_stats_data();
|
|
refresh_metrics(false);
|
|
}
|
|
}
|
|
|
|
async function load_selected_metric_page_stats_data() {
|
|
let timeseries_groups = await get_selected_timeseries_groups();
|
|
await load_page_stats_data(timeseries_groups, true, false);
|
|
}
|
|
|
|
function epoch_change(new_epoch) {
|
|
let push_custom_metric = selected_metric.value.label == custom_metric.label;
|
|
load_page_stats_data(last_timeseries_groups_loaded, true, false, new_epoch.refresh_data);
|
|
refresh_top_table();
|
|
refresh_metrics(push_custom_metric, true);
|
|
}
|
|
|
|
function chart_reloaded(chart_options) {
|
|
}
|
|
|
|
function show_modal_snapshot() {
|
|
modal_snapshot.value.show();
|
|
}
|
|
|
|
function show_manage_timeseries() {
|
|
if (last_timeseries_groups_loaded == null) { return; }
|
|
modal_timeseries.value.show(last_timeseries_groups_loaded);
|
|
};
|
|
|
|
/**
|
|
* Function called by Chart component to draw or update that return chart options.
|
|
**/
|
|
function get_f_get_custom_chart_options(chart_index) {
|
|
return async (url) => {
|
|
return charts_options_items.value[chart_index].chart_options;
|
|
}
|
|
}
|
|
|
|
let cache_snapshots = null;
|
|
function refresh_snapshots() {
|
|
let push_custom_metric = selected_metric.value.label == custom_metric.label;
|
|
refresh_metrics(push_custom_metric, true);
|
|
}
|
|
|
|
async function refresh_metrics(push_custom_metric, force_refresh) {
|
|
metrics.value = await get_metrics(push_custom_metric, force_refresh);
|
|
if (push_custom_metric) {
|
|
selected_metric.value = custom_metric;
|
|
}
|
|
}
|
|
|
|
async function apply_modal_timeseries(timeseries_groups) {
|
|
refresh_metrics(true);
|
|
await load_page_stats_data(timeseries_groups, true, true);
|
|
}
|
|
|
|
function change_groups_options_mode() {
|
|
load_page_stats_data(last_timeseries_groups_loaded, false, false);
|
|
}
|
|
|
|
let ts_charts_options;
|
|
/* This function load the chart data and options, doing the request and then setting the options */
|
|
async function load_page_stats_data(timeseries_groups, reload_charts_data, reload_top_table_options, refreshed_time_interval) {
|
|
/* Get the information necessary for the request, like epoch ecc. */
|
|
let status = ntopng_status_manager.get_status();
|
|
let ts_compare = get_ts_compare(status);
|
|
if (reload_charts_data) {
|
|
/* Do the request to the backend; the answer is formatted as
|
|
* [
|
|
* {
|
|
* metadata: { ... } // Containing various info regarding the series returned
|
|
* series: { ... } // Containing the series with the data, labels and statistics
|
|
* }
|
|
* ]
|
|
*/
|
|
if (timeseries_groups == null) {
|
|
timeseries_groups = [];
|
|
console.warn("Empty timeseries_groups request");
|
|
return;
|
|
}
|
|
ts_charts_options = await timeseriesUtils.getTsChartsOptions(http_prefix, status, ts_compare, timeseries_groups, props.is_ntop_pro);
|
|
}
|
|
|
|
/* Update timeseries label to display */
|
|
set_timeseries_groups_source_label(timeseries_groups, ts_charts_options);
|
|
|
|
/* Format the options for the timeseries library */
|
|
let charts_options = timeseriesUtils.tsArrayToOptionsArray(ts_charts_options, timeseries_groups, current_groups_options_mode.value, ts_compare);
|
|
if (refreshed_time_interval) {
|
|
update_charts(charts_options);
|
|
} else {
|
|
set_charts_options_items(charts_options);
|
|
}
|
|
set_stats_rows(ts_charts_options, timeseries_groups, status);
|
|
if (reload_top_table_options) {
|
|
set_top_table_options(timeseries_groups, status);
|
|
}
|
|
// set last_timeseries_groupd_loaded
|
|
last_timeseries_groups_loaded = timeseries_groups;
|
|
// update url params
|
|
update_url_params();
|
|
}
|
|
|
|
/* This function returns set the label of the timeseries; if available it should be
|
|
* found in response.metadata.label field
|
|
*/
|
|
function set_timeseries_groups_source_label(timeseries_groups, ts_charts_options) {
|
|
timeseries_groups.forEach((ts_group, i) => {
|
|
let ts_options = ts_charts_options[i];
|
|
let label = ts_options?.metadata?.label;
|
|
if (label != null) {
|
|
let source_index = timeseriesUtils.getMainSourceDefIndex(ts_group);
|
|
let source = ts_group.source_array[source_index];
|
|
source.label = label;
|
|
}
|
|
});
|
|
}
|
|
|
|
function update_url_params() {
|
|
ntopng_url_manager.set_key_to_url("timeseries_groups_mode", current_groups_options_mode.value.value);
|
|
metricsManager.set_timeseries_groups_in_url(last_timeseries_groups_loaded);
|
|
}
|
|
|
|
function update_charts(charts_options) {
|
|
charts_options.forEach((options, i) => {
|
|
// charts.value[i].update_chart_options({ yaxis: options.yaxis });
|
|
charts.value[i].update_chart_series(options?.serie);
|
|
});
|
|
}
|
|
|
|
function set_charts_options_items(charts_options) {
|
|
charts_options_items.value = charts_options.map((options, i) => {
|
|
return {
|
|
key: ntopng_utility.get_random_string(),
|
|
chart_options: options,
|
|
};
|
|
});
|
|
}
|
|
|
|
function get_ts_compare(status) {
|
|
// 5m, 30m, 1h, 1d, 1w, 1M, 1Y
|
|
let r = Number.parseInt((status.epoch_end - status.epoch_begin) / 60);
|
|
if (r <= 5) {
|
|
return "5m";
|
|
} else if (r <= 10) {
|
|
return "10m";
|
|
} else if (r <= 30) {
|
|
return "30m";
|
|
} else if (r <= 60) {
|
|
return "1h";
|
|
} else if (r <= 60 * 2) {
|
|
return "2h";
|
|
} else if (r <= 60 * 6) {
|
|
return "6h";
|
|
} else if (r <= 60 * 12) {
|
|
return "12h";
|
|
} else if (r <= 60 * 24) {
|
|
return "1d";
|
|
} else if (r <= 60 * 24 * 7) {
|
|
return "1w";
|
|
} else if (r <= 60 * 24 * 31) {
|
|
return "1M";
|
|
} else {
|
|
return "1Y";
|
|
}
|
|
}
|
|
|
|
function get_top_table_url(ts_group, table_value, table_view, table_source_def_value_dict, status) {
|
|
if (!status) {
|
|
status = ntopng_status_manager.get_status();
|
|
}
|
|
if (!status.epoch_begin) {
|
|
status.epoch_begin = ntopng_url_manager.get_url_entry("epoch_begin");
|
|
}
|
|
if (!status.epoch_end) {
|
|
status.epoch_end = ntopng_url_manager.get_url_entry("epoch_end");
|
|
}
|
|
let ts_query = timeseriesUtils.getTsQuery(ts_group, true, table_source_def_value_dict);
|
|
let v = table_value;
|
|
let data_url = `${http_prefix}/lua/pro/rest/v2/get/${v}/top/ts_stats.lua`;
|
|
//todo: get ts_query
|
|
let p_obj = {
|
|
zoom: '5m',
|
|
ts_query,
|
|
// ts_query: `ifid:${ntopng_url_manager.get_url_entry('ifid')}`,
|
|
epoch_begin: `${status.epoch_begin}`,
|
|
epoch_end: `${status.epoch_end}`,
|
|
detail_view: `${table_view}`,
|
|
new_charts: `true`
|
|
};
|
|
|
|
let p_url_request = ntopng_url_manager.add_obj_to_url(p_obj, '');
|
|
return `${data_url}?${p_url_request}`;
|
|
}
|
|
|
|
async function refresh_top_table() {
|
|
if (!props.is_ntop_pro) { return; }
|
|
let table_config = selected_top_table.value?.table_config_def;
|
|
if (table_config == null) { return; }
|
|
// NtopUtils.showOverlays();
|
|
let data_url = get_top_table_url(table_config.ts_group, table_config.table_def.table_value, table_config.table_def.view, table_config.table_source_def_value_dict);
|
|
top_table_ref.value.update_url(data_url);
|
|
top_table_ref.value.reload();
|
|
// NtopUtils.hideOverlays();
|
|
}
|
|
|
|
const top_table_options = ref([]);
|
|
const selected_top_table = ref({});
|
|
function set_top_table_options(timeseries_groups, status) {
|
|
if (!props.is_ntop_pro) { return; }
|
|
if (timeseries_groups == null) {
|
|
timeseries_groups = last_timeseries_groups_loaded;
|
|
}
|
|
if (status == null) {
|
|
status = ntopng_status_manager.get_status();
|
|
}
|
|
|
|
let sources_types_tables = metricsManager.sources_types_tables;
|
|
let ts_group_dict = {}; // dictionary with 1 ts_group for each (source_type, source_array)
|
|
timeseries_groups.forEach((ts_group) => {
|
|
let source_type = ts_group.source_type;
|
|
// let source_type_tables = sources_types_tables[source_type.id];
|
|
// let table_source_def_value_dict = source_type_tables.table_source_def_value_dict
|
|
|
|
let id = metricsManager.get_ts_group_id(ts_group.source_type, ts_group.source_array);
|
|
ts_group_dict[id] = ts_group;
|
|
});
|
|
let top_table_id_dict = {};
|
|
top_table_options.value = [];
|
|
for (let id in ts_group_dict) {
|
|
let ts_group = ts_group_dict[id];
|
|
let main_source_index = timeseriesUtils.getMainSourceDefIndex(ts_group);
|
|
let main_source = ts_group.source_array[main_source_index];
|
|
let source_type = ts_group.source_type;
|
|
let source_type_tables = sources_types_tables[source_type.id];
|
|
if (source_type_tables == null) { continue; }
|
|
|
|
source_type_tables.forEach((table_def) => {
|
|
let enables_table_value = props.sources_types_top_enabled[table_def.table_value];
|
|
if (enables_table_value == null) { return; }
|
|
let enable_table_def = enables_table_value[table_def.view];
|
|
if (!enable_table_def) { return; }
|
|
let table_source_def_value_dict = table_def.table_source_def_value_dict
|
|
|
|
let data_url = get_top_table_url(ts_group, table_def.table_value, table_def.view, table_source_def_value_dict, status);
|
|
let table_id = metricsManager.get_ts_group_id(ts_group.source_type, ts_group.source_array, null, table_source_def_value_dict, true);
|
|
table_id = `${table_id}_${table_def.view}`;
|
|
if (top_table_id_dict[table_id] != null) { return; }
|
|
top_table_id_dict[table_id] = true;
|
|
|
|
let value = `${table_def.table_value}_${table_def.view}_${table_id}`;
|
|
let label;
|
|
if (table_def.f_get_label == null) {
|
|
label = `${table_def.title} - ${source_type.label} ${main_source.label}`;
|
|
} else {
|
|
label = table_def.f_get_label(ts_group)
|
|
}
|
|
const table_config_def = {
|
|
ts_group,
|
|
table_def,
|
|
// table_value: table_def.table_value,
|
|
// table_view: table_def.view,
|
|
|
|
table_buttons: [],
|
|
data_url,
|
|
enable_search: true,
|
|
table_config: {
|
|
serverSide: false,
|
|
order: [[table_def.default_sorting_columns, 'desc']],
|
|
columnDefs: table_def.columnDefs || [],
|
|
}
|
|
};
|
|
// it should be here in this instance the vuetify object with its properties
|
|
table_config_def.columns_config = table_def.columns.map((column) => {
|
|
let render_if_context = {
|
|
is_history_enabled: props.is_history_enabled
|
|
};
|
|
let c = {
|
|
visible: !column.render_if || column.render_if(render_if_context),
|
|
...column,
|
|
};
|
|
if (c.className == null) { c.className = "text-nowrap"; }
|
|
if (c.responsivePriority == null) { c.responsivePriority = 1; }
|
|
c.render = column.render.bind({
|
|
add_metric_from_metric_schema,
|
|
add_ts_group_from_source_value_dict,
|
|
sources_types_enabled: props.sources_types_enabled,
|
|
status, source_type, source_array: ts_group.source_array,
|
|
});
|
|
return c;
|
|
});
|
|
let option = { value, label, table_config_def };
|
|
top_table_options.value.push(option);
|
|
});
|
|
}
|
|
if (selected_top_table.value != null && top_table_options.value.find((option) => option.value == selected_top_table.value.value)) {
|
|
return;
|
|
}
|
|
|
|
selected_top_table.value = top_table_options.value.find((option) => option.table_config_def.default == true);
|
|
if (selected_top_table.value == null) {
|
|
selected_top_table.value = top_table_options.value[0];
|
|
}
|
|
}
|
|
|
|
let stats_columns = [
|
|
{ id: "metric", label: _i18n("page_stats.metric"), va: true },
|
|
{ id: "avg", label: _i18n("page_stats.average"), class: "text-end", va: true },
|
|
{ id: "perc_95", label: _i18n("page_stats.95_perc"), class: "text-end", va: true },
|
|
{ id: "max", label: _i18n("page_stats.max"), class: "text-end", va: true },
|
|
{ id: "min", label: _i18n("page_stats.min"), class: "text-end", va: true },
|
|
{ id: "total", label: _i18n("page_stats.total"), class: "text-end", va: false },
|
|
];
|
|
|
|
const stats_rows = ref([]);
|
|
|
|
function set_stats_rows(ts_charts_options, timeseries_groups, status) {
|
|
const extend_serie_name = ts_charts_options.length > 1;
|
|
enable_stats_table.value = timeseries_groups.map((ts_group) => !ts_group.source_type.disable_stats).reduce((res, el) => res | el, false);
|
|
if (!enable_stats_table.value) { return; }
|
|
const f_get_total_formatter_type = (type) => {
|
|
let map_type = {
|
|
"bps": "bytes",
|
|
"fps": "flows",
|
|
"alertps": "alerts",
|
|
"hitss": "hits",
|
|
"pps": "packets",
|
|
};
|
|
if (map_type[type] != null) {
|
|
return map_type[type];
|
|
}
|
|
return type;
|
|
};
|
|
stats_rows.value = [];
|
|
ts_charts_options.forEach((options, i) => {
|
|
let ts_group = timeseries_groups[i];
|
|
if (ts_group.source_type.disable_stats == true) { return; }
|
|
options.series?.forEach((s, j) => {
|
|
let ts_id = timeseriesUtils.getSerieId(s);
|
|
let s_metadata = ts_group.metric.timeseries[ts_id];
|
|
let formatter = formatterUtils.getFormatter(ts_group.metric.measure_unit);
|
|
let ts_stats;
|
|
let name = s_metadata.label;
|
|
if (s_metadata.hidden) {
|
|
/* Skip in case it's requested to hide the Timeserie */
|
|
return;
|
|
}
|
|
if (s_metadata.use_serie_name == true) {
|
|
name = s.name;
|
|
}
|
|
if (s?.data.length > j) {
|
|
ts_stats = s.statistics;
|
|
}
|
|
if (ts_stats == null) {
|
|
return;
|
|
}
|
|
if (s.ext_label) {
|
|
name = s.ext_label
|
|
}
|
|
if (s.label) {
|
|
name = s.label
|
|
}
|
|
name = timeseriesUtils.getSerieName(name, ts_id, ts_group, extend_serie_name);
|
|
let total_formatter_type = f_get_total_formatter_type(ts_group.metric.measure_unit);
|
|
let total_formatter = formatterUtils.getFormatter(total_formatter_type);
|
|
let row = {
|
|
metric: name,
|
|
total: total_formatter(ts_stats.total),
|
|
perc_95: formatter(ts_stats["95th_percentile"]),
|
|
avg: formatter(ts_stats.average),
|
|
max: formatter(ts_stats.max_val),
|
|
min: formatter(ts_stats.min_val),
|
|
};
|
|
stats_rows.value.push(row);
|
|
});
|
|
});
|
|
}
|
|
|
|
function print_stats_column(col) {
|
|
return col.label;
|
|
}
|
|
|
|
function print_stats_row(col, row) {
|
|
let label = row[col.id];
|
|
const historical_filter = props.source_value_object.historical_link_to_table;
|
|
if (historical_filter && historical_filter.add_historical_link_to_table && historical_filter.historical_link_col_id == col.id) {
|
|
const element = historical_filter.historical_filters.find((el) => { return el.table_label === label })
|
|
if (element) {
|
|
let params = create_historical_params()
|
|
params[element.historical_filter] = params[historical_filter.historical_filter_to_change]
|
|
delete params[historical_filter.historical_filter_to_change]
|
|
params["aggregated"] = false;
|
|
params["query_preset"] = "";
|
|
params["count"] = "THROUGHPUT";
|
|
if (!params["ifid"]) {
|
|
params["ifid"] = historical_filter.historical_interface_id
|
|
}
|
|
let url_params = ntopng_url_manager.obj_to_url_params(params);
|
|
label = `<a href="${http_prefix}/lua/pro/db_search.lua?${url_params}">${label}</a>`
|
|
}
|
|
}
|
|
return label;
|
|
}
|
|
|
|
function create_historical_params() {
|
|
let status = ntopng_status_manager.get_status();
|
|
let params = { epoch_begin: status.epoch_begin, epoch_end: status.epoch_end };
|
|
/* Add the source elements to the redirect, like host, snmp, ecc. */
|
|
if (last_timeseries_groups_loaded && last_timeseries_groups_loaded.length > 0) {
|
|
const source_array = last_timeseries_groups_loaded[0].source_array
|
|
const source_def = last_timeseries_groups_loaded[0].source_type.source_def_array
|
|
/* Use the first element */
|
|
if (source_array) {
|
|
let probe = ''
|
|
source_array.forEach((elem, i) => {
|
|
if (!dataUtils.isEmptyOrNull(elem.label) && source_def[i]) {
|
|
const value = source_def[i].value
|
|
switch (value) {
|
|
case 'device':
|
|
probe = elem.value
|
|
params["probe_ip"] = `${elem.value};eq`
|
|
break;
|
|
case 'port':
|
|
case 'if_index':
|
|
params["snmp_interface"] = `${probe}_${elem.value};eq`
|
|
break;
|
|
case 'host':
|
|
params["ip"] = `${elem.value};eq`
|
|
break;
|
|
case 'mac':
|
|
params["mac"] = `${elem.value};eq`
|
|
break;
|
|
case 'subnet':
|
|
params["network"] = `${elem.value};eq`
|
|
break;
|
|
case 'asn':
|
|
params["asn"] = `${elem.value};eq`
|
|
break;
|
|
case 'country':
|
|
params["country"] = `${elem.value};eq`
|
|
break;
|
|
case 'vlan':
|
|
params["vlan_id"] = `${elem.value};eq`
|
|
break;
|
|
case 'pool':
|
|
params["host_pool_id"] = `${elem.value};eq`
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
return params
|
|
}
|
|
|
|
function jump_to_historical_flows() {
|
|
const params = create_historical_params()
|
|
let url_params = ntopng_url_manager.obj_to_url_params(params);
|
|
const historical_url = `${http_prefix}/lua/pro/db_search.lua?${url_params}`;
|
|
ntopng_url_manager.go_to_url(historical_url);
|
|
}
|
|
|
|
const modal_traffic_extraction = ref(null);
|
|
function show_modal_traffic_extraction() {
|
|
modal_traffic_extraction.value.show();
|
|
}
|
|
|
|
function show_modal_download_file() {
|
|
if (!ts_charts_options?.length) { return; }
|
|
let ts_group = last_timeseries_groups_loaded[0];
|
|
let filename = timeseriesUtils.getSerieName(null, null, ts_group);
|
|
modal_download_file.value.show(filename);
|
|
}
|
|
|
|
async function download_chart_png(filename) {
|
|
let chart_image_array_promise = charts.value.map(async (chart) => {
|
|
let canvas = new Image();
|
|
chart.get_image(canvas);
|
|
return new Promise(async (resolve, reject) => {
|
|
canvas.onload = function () {
|
|
resolve(canvas);
|
|
};
|
|
});
|
|
});
|
|
let height = 0;
|
|
let chart_image_array = await Promise.all(chart_image_array_promise);
|
|
chart_image_array.forEach((image) => {
|
|
height += image.height;
|
|
});
|
|
let canvas = document.createElement('canvas');
|
|
let canvas_context = canvas.getContext('2d');
|
|
canvas.width = chart_image_array[0].width;
|
|
canvas.height = height;
|
|
height = 0;
|
|
chart_image_array.forEach((image) => {
|
|
canvas_context.drawImage(image, 0, height, image.width, image.height);
|
|
height += image.height;
|
|
});
|
|
ntopng_utility.download_URI(canvas.toDataURL(), filename);
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
.inline {
|
|
display: inline-block;
|
|
}
|
|
|
|
.select2-size {
|
|
min-width: 18rem;
|
|
}
|
|
</style>
|