mirror of
https://github.com/ntop/ntopng.git
synced 2026-05-06 03:45:26 +00:00
713 lines
25 KiB
Vue
713 lines
25 KiB
Vue
<!-- (C) 2022 - ntop.org -->
|
|
<template>
|
|
<div class="col-12 mb-2 mt-2">
|
|
<AlertInfo></AlertInfo>
|
|
<div class="card h-100 overflow-hidden">
|
|
<DataTimeRangePicker style="margin-top:0.5rem;"
|
|
:id="id_date_time_picker"
|
|
:enable_refresh="true"
|
|
ref="date_time_picker"
|
|
@epoch_change="epoch_change">
|
|
<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 class="btn btn-link btn-sm" @click="show_modal_download_file" :title="_i18n('page_stats.title_modal_download_file')"><i class="fas fa-lg fa-file-image"></i></button>
|
|
</template>
|
|
</DataTimeRangePicker>
|
|
<!-- select metric -->
|
|
<div v-show="ts_menu_ready" class="form-group ms-1 me-1 mt-1">
|
|
<div class="inline select2-size me-2 mt-2">
|
|
<SelectSearch v-model:selected_option="selected_metric"
|
|
:options="metrics"
|
|
@select_option="select_metric">
|
|
</SelectSearch>
|
|
</div>
|
|
<div class="inline select2-size me-2 mt-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">
|
|
<div class="m-3" style="height:300px;">
|
|
<Chart :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">
|
|
</Chart>
|
|
</div>
|
|
</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 Chart } from "./chart.vue";
|
|
import { default as DataTimeRangePicker } from "./data-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 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 { DataTableUtils } from "../utilities/datatable/sprymedia-datatable-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,
|
|
});
|
|
|
|
ntopng_utility.check_and_set_default_interval_time();
|
|
|
|
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 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);
|
|
|
|
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 () => {
|
|
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) {
|
|
if (!force_refresh && last_push_custom_metric == push_custom_metric) { return metrics.value; }
|
|
|
|
let metrics = await metricsManager.get_metrics(http_prefix);
|
|
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 */
|
|
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, true);
|
|
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;
|
|
async function load_page_stats_data(timeseries_groups, reload_charts_data, reload_top_table_options, refreshed_time_interval) {
|
|
let status = ntopng_status_manager.get_status();
|
|
let ts_compare = get_ts_compare(status);
|
|
if (reload_charts_data) {
|
|
ts_charts_options = await timeseriesUtils.getTsChartsOptions(http_prefix, status, ts_compare, timeseries_groups, props.is_ntop_pro);
|
|
}
|
|
|
|
// update timeseries_groups source label
|
|
set_timeseries_groups_source_label(timeseries_groups, ts_charts_options);
|
|
|
|
let charts_options = timeseriesUtils.tsArrayToApexOptionsArray(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();
|
|
}
|
|
|
|
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?.query?.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(options);
|
|
});
|
|
}
|
|
|
|
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 <= 30) {
|
|
return "30m";
|
|
} else if (r <= 60) {
|
|
return "1h";
|
|
} else if (r <= 60 * 24) {
|
|
return "1d";
|
|
} else if (r <= 60 * 24 * 7) {
|
|
return "1w";
|
|
} else if (r <= 60 * 24 * 30) {
|
|
return "1M";
|
|
} else {
|
|
return "1Y";
|
|
}
|
|
}
|
|
|
|
function get_top_table_url(ts_group, table_value, table_view, table_source_def_value_dict, status) {
|
|
if (status == null) {
|
|
status = ntopng_status_manager.get_status();
|
|
}
|
|
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 = [];
|
|
let select_options = [];
|
|
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") },
|
|
{ id: "avg", label: _i18n("page_stats.average") },
|
|
{ id: "perc_95", label: _i18n("page_stats.95_perc") },
|
|
{ id: "max", label: _i18n("page_stats.max") },
|
|
{ id: "min", label: _i18n("page_stats.min") },
|
|
{ id: "total", label: _i18n("page_stats.total") },
|
|
];
|
|
|
|
const stats_rows = ref([]);
|
|
|
|
function set_stats_rows(ts_charts_options, timeseries_groups, status) {
|
|
let extend_serie_name = true;
|
|
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) => {
|
|
if (type == "bps") { return "bytes_network"; }
|
|
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;
|
|
if (ts_group.metric.type == "top") {
|
|
ts_stats = options.statistics;
|
|
} else if (options?.statistics?.by_serie?.length > j) {
|
|
ts_stats = options.statistics.by_serie[j];
|
|
}
|
|
if (ts_stats == null || (ts_group.metric.type == "top" && j > 0)) {
|
|
return;
|
|
}
|
|
let name = timeseriesUtils.getSerieName(s_metadata.label, ts_id, ts_group, extend_serie_name);
|
|
let total = null;
|
|
let total_formatter_type = f_get_total_formatter_type(ts_group.metric.measure_unit);
|
|
let total_formatter = formatterUtils.getFormatter(total_formatter_type);
|
|
if (ts_stats.total != null) {
|
|
let interval = status.epoch_end - status.epoch_begin;
|
|
total = interval * ts_stats.average;
|
|
}
|
|
|
|
let row = {
|
|
metric: name,
|
|
// total: total_formatter(total),
|
|
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];
|
|
return label;
|
|
}
|
|
|
|
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 data_uri = await chart.get_data_uri();
|
|
return new Promise((resolve, reject) => {
|
|
let image = new Image();
|
|
image.src = data_uri;
|
|
image.onload = function() {
|
|
resolve(image);
|
|
};
|
|
});
|
|
});
|
|
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>
|