mirror of
https://github.com/ntop/ntopng.git
synced 2026-05-03 09:20:10 +00:00
311 lines
10 KiB
Vue
311 lines
10 KiB
Vue
<!--
|
|
(C) 2013-22 - ntop.org
|
|
-->
|
|
|
|
<template>
|
|
<div class="row">
|
|
<div class="col-md-12 col-lg-12">
|
|
<div class="card card-shadow">
|
|
<Loading v-if="loading"></Loading>
|
|
<Sankey ref="sankey_chart" :width="width" :height="height" :no_data_message="no_data_message"
|
|
:sankey_data="sankey_data" @update_width="update_width" @update_height="update_height"
|
|
@node_click="on_node_click">
|
|
</Sankey>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, onMounted, onBeforeMount } from "vue";
|
|
import { default as Loading } from "./loading.vue"
|
|
import { ntopng_utility, ntopng_url_manager } from "../services/context/ntopng_globals_services.js";
|
|
import { default as Sankey } from "./sankey.vue";
|
|
|
|
const active_filter_list = {}
|
|
const props = defineProps({
|
|
ifid: Number,
|
|
available_filters: Object,
|
|
});
|
|
|
|
const _i18n = (t) => i18n(t);
|
|
const max_entries_reached = ref(false)
|
|
const max_entry_title = _i18n('ports_analysis.max_entries')
|
|
const no_data_message = _i18n('ports_analysis.no_data')
|
|
const sankey_chart = ref(null)
|
|
const body_div = ref(null);
|
|
const width = ref(null);
|
|
const height = ref(null);
|
|
const sankey_data = ref({});
|
|
const live_rest = `${http_prefix}/lua/pro/rest/v2/get/vlan/live_ports.lua`
|
|
const historical_rest = `${http_prefix}/lua/pro/rest/v2/get/vlan/historical_ports.lua`
|
|
const loading = ref(false)
|
|
|
|
onBeforeMount(() => {
|
|
/* Before mounting the various widgets, update the url to the correct one, by adding ifid, ecc. */
|
|
});
|
|
|
|
onMounted(() => {
|
|
update_height();
|
|
update_width();
|
|
set_sankey_data();
|
|
});
|
|
|
|
function on_node_click(node) {
|
|
if (node.is_link_node == true) { return; }
|
|
if (node.link) { ntopng_url_manager.go_to_url(node.link); }
|
|
}
|
|
|
|
const reload = function () {
|
|
update_sankey()
|
|
}
|
|
|
|
const click_item = function (item) {
|
|
ntopng_url_manager.set_key_to_url(item.filter_name, item.id)
|
|
update_sankey();
|
|
}
|
|
|
|
const update_sankey = function () {
|
|
set_sankey_data();
|
|
}
|
|
|
|
function check_max_entries(data) {
|
|
max_entries_reached.value = data.max_entries_reached
|
|
}
|
|
|
|
async function set_sankey_data() {
|
|
loading.value = true;
|
|
let data = {
|
|
nodes: [
|
|
{ index: 0, name: "Liikevaihto", hours: "100%" },
|
|
{ index: 1, name: "Kiinteät kulut", hours: "85%" },
|
|
{ index: 2, name: "Muuttuvat kulut", hours: "3:00" },
|
|
{ index: 3, name: "Palkkakulut", hours: "1:20" },
|
|
{ index: 4, name: "Muut kiinte", hours: "1:40" },
|
|
{ index: 5, name: "Kate", hours: "1:40" }
|
|
],
|
|
links: [
|
|
{ source: 0, target: 1, value: 75, hours: "+1:00" },
|
|
{ source: 0, target: 2, value: 10, hours: "+2:00" },
|
|
{ source: 1, target: 3, value: 69, hours: "+1:20" },
|
|
{ source: 1, target: 4, value: 6, hours: "+1:40" },
|
|
{ source: 0, target: 5, value: 15, hours: "+1:40" }
|
|
]
|
|
};
|
|
|
|
sankey_data.value = data;
|
|
loading.value = false;
|
|
}
|
|
|
|
async function get_sankey_data() {
|
|
const url_request = get_sankey_url();
|
|
let graph = await ntopng_utility.http_request(url_request);
|
|
check_max_entries(graph);
|
|
graph = make_complete_graph(graph);
|
|
const sankey_data = get_sankey_data_from_rest_data(graph);
|
|
|
|
return sankey_data;
|
|
}
|
|
|
|
function get_sankey_url() {
|
|
let vlan = ntopng_url_manager.get_url_entry("vlan");
|
|
let timeframe = ntopng_url_manager.get_url_entry("timeframe");
|
|
let l4proto = ntopng_url_manager.get_url_entry("l4proto");
|
|
if (vlan == 'none') { vlan = ''; }
|
|
if (timeframe == 'none') { timeframe = ''; }
|
|
if (l4proto == 'none') { l4proto = ''; }
|
|
|
|
let url_request = '';
|
|
let params = {
|
|
ifid: ntopng_url_manager.get_url_entry("ifid"),
|
|
vlan: vlan,
|
|
timeframe: timeframe,
|
|
l4proto: l4proto
|
|
};
|
|
let url_params = ntopng_url_manager.obj_to_url_params(params);
|
|
|
|
if (timeframe == '') { url_request = `${live_rest}?${url_params}`; }
|
|
else { url_request = `${historical_rest}?${url_params}`; }
|
|
|
|
return url_request;
|
|
}
|
|
|
|
function get_sankey_data_from_rest_data(res) {
|
|
let node_dict = {}, link_to_nodes_dict = {};
|
|
// create a node dict
|
|
res.nodes.forEach((node) => node_dict[node.node_id] = node);
|
|
|
|
let f_get_link_node_id = (link) => {
|
|
return `${link.source_node_id}_${link.label}`;
|
|
};
|
|
// merge all links by label
|
|
res.links.forEach((link) => {
|
|
let link_node_id = f_get_link_node_id(link);
|
|
let link_to_nodes = link_to_nodes_dict[link_node_id];
|
|
if (link_to_nodes == null) {
|
|
link_to_nodes = {
|
|
id: link_node_id,
|
|
label: link.label,
|
|
link: link.optional_info.link,
|
|
node_links: [],
|
|
};
|
|
link_to_nodes_dict[link_node_id] = link_to_nodes;
|
|
}
|
|
link_to_nodes.node_links.push({
|
|
source: node_dict[link.source_node_id],
|
|
target: node_dict[link.target_node_id],
|
|
value: link.value,
|
|
});
|
|
});
|
|
|
|
// create nodes and links
|
|
let nodes = res.nodes.map((n) => n), links = [];
|
|
for (let link_node_id in link_to_nodes_dict) {
|
|
let link_to_nodes = link_to_nodes_dict[link_node_id];
|
|
let link_node = {
|
|
node_id: link_to_nodes.id,
|
|
label: link_to_nodes.label,
|
|
link: link_to_nodes.link,
|
|
};
|
|
nodes.push(link_node);
|
|
link_to_nodes.node_links.forEach((link) => {
|
|
links.push({
|
|
source_node_id: link.source.node_id,
|
|
target_node_id: link_node.node_id,
|
|
label: `${link.source.label} - ${link.target.label}: ${link_node.label}`,
|
|
value: link.value,
|
|
});
|
|
links.push({
|
|
source_node_id: link_node.node_id,
|
|
target_node_id: link.target.node_id,
|
|
label: `${link.source.label} - ${link.target.label}: ${link_node.label}`,
|
|
value: link.value,
|
|
});
|
|
});
|
|
}
|
|
let sankey_nodes = nodes.map((n, index) => {
|
|
return { index, label: n.label, data: n };
|
|
});
|
|
let sankey_node_dict = {};
|
|
sankey_nodes.forEach((sn, index) => sankey_node_dict[sn.data.node_id] = sn);
|
|
let sankey_links = links.map((l) => {
|
|
let source_index = sankey_node_dict[l.source_node_id].index;
|
|
let target_index = sankey_node_dict[l.target_node_id].index;
|
|
return {
|
|
source: source_index,
|
|
target: target_index,
|
|
value: l.value,
|
|
label: l.label,
|
|
};
|
|
});
|
|
return { nodes: sankey_nodes, links: sankey_links };
|
|
}
|
|
|
|
// remove all links with a not existing node
|
|
function make_complete_graph(graph) {
|
|
let f_log_link = (l) => console.error(`link (source: ${l.source_node_id}, target: ${l.target_node_id}) removed for not existing source/target node`);
|
|
let links = get_links_with_existing_node(graph, f_log_link);
|
|
return { nodes: graph.nodes, links };
|
|
}
|
|
|
|
// remeove all circular links and return a dag graph
|
|
function make_dag_graph(graph) {
|
|
let nodes_dest_dict = {}; // dictionary { [node_source_id]: nodes_target[] }
|
|
graph.links.forEach((l) => {
|
|
let nodes_dest = nodes_dest_dict[l.source_node_id];
|
|
if (nodes_dest == null) {
|
|
nodes_dest = [];
|
|
nodes_dest_dict[l.source_node_id] = nodes_dest;
|
|
}
|
|
nodes_dest.push(l.target_node_id);
|
|
});
|
|
let nodes_to_check = {}; // temp dictionary used from f_add_circular_link
|
|
graph.nodes.forEach((n) => {
|
|
nodes_to_check[n.node_id] = { checked: false, visited: false };
|
|
});
|
|
|
|
// circular links dict (key: `${source_node_id}_${target_node_id}`)
|
|
let circular_links = {};
|
|
let f_get_link_key = (source_id, target_id) => `${source_id}_${target_id}`;
|
|
|
|
// deep navigate starting from node_id and add circular_links visited in circular_links dict
|
|
let f_set_circular_links = (node_id, from_node_id) => {
|
|
let node_to_check = nodes_to_check[node_id];
|
|
if (node_to_check.checked == true) { return; }
|
|
else if (node_to_check.visited == true) {
|
|
let link_key = f_get_link_key(from_node_id, node_id);
|
|
circular_links[link_key] = true;
|
|
console.error(`Link (source: ${from_node_id}, target: ${node_id} ) is a circular link`);
|
|
node_to_check.visited = false;
|
|
return;
|
|
}
|
|
node_to_check.visited = true;
|
|
let nodes_dest = nodes_dest_dict[node_id];
|
|
if (nodes_dest != null) {
|
|
for (let i = 0; i < nodes_dest.length; i += 1) {
|
|
let target_node_id = nodes_dest[i];
|
|
f_set_circular_links(target_node_id, node_id);
|
|
}
|
|
}
|
|
node_to_check.visited = false;
|
|
node_to_check.checked = true;
|
|
};
|
|
// set circular_links dictionary
|
|
graph.nodes.forEach((n) => f_set_circular_links(n.node_id));
|
|
|
|
// remove no dag nodes/links
|
|
let f_filter_link = (l) => {
|
|
let link_key = f_get_link_key(l.source_node_id, l.target_node_id);
|
|
let take_link = circular_links[link_key] == null;
|
|
return take_link;
|
|
};
|
|
let f_log_link = (l) => console.error(`link (source: ${l.source_node_id}, target: ${l.target_node_id}) removed for circular links`);
|
|
let links = filter_log(graph.links, f_filter_link, f_log_link);
|
|
|
|
let f_log_node = (n) => console.error(`node ${n.node_id} removed for circular links`);
|
|
let nodes = get_nodes_with_existing_link({ nodes: graph.nodes, links }, f_log_node);
|
|
|
|
// return a dag graph
|
|
return { nodes, links };
|
|
}
|
|
|
|
function get_links_with_existing_node(graph, f_log) {
|
|
let node_dict = {};
|
|
graph.nodes.forEach((n) => node_dict[n.node_id] = true);
|
|
let f_filter = (l) => node_dict[l.source_node_id] != null && node_dict[l.target_node_id] != null;
|
|
let links = filter_log(graph.links, f_filter, f_log);
|
|
return links;
|
|
}
|
|
|
|
function get_nodes_with_existing_link(graph, f_log) {
|
|
let link_source_dict = {};
|
|
let link_target_dict = {};
|
|
graph.links.forEach((l) => {
|
|
link_source_dict[l.source_node_id] = true;
|
|
link_target_dict[l.target_node_id] = true;
|
|
});
|
|
let f_filter = (n) => link_source_dict[n.node_id] == true || link_target_dict[n.node_id] == true;
|
|
let nodes = filter_log(graph.nodes, f_filter, f_log);
|
|
return nodes;
|
|
}
|
|
|
|
// log elements deleted if f_log != null
|
|
function filter_log(elements, f_filter, f_log) {
|
|
return elements.filter((e) => {
|
|
const take_element = f_filter(e);
|
|
if (take_element == false && f_log != null) {
|
|
f_log(e);
|
|
}
|
|
return take_element;
|
|
});
|
|
}
|
|
|
|
function update_height() {
|
|
height.value = $(body_div.value).height() - 100;
|
|
}
|
|
|
|
function update_width() {
|
|
width.value = $(body_div.value).width() - 10;
|
|
}
|
|
|
|
</script>
|