Fixed pie chart no data messagae missing, handle no data from component (#10238)

This commit is contained in:
GabrieleDeri 2026-04-01 08:55:43 +02:00 committed by GitHub
parent 90f0ebe8f7
commit c755e701f0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 158 additions and 28 deletions

View file

@ -261,6 +261,7 @@ await build({
outDir: 'httpdocs/dist',
emptyOutDir: false,
minify: isProd ? 'esbuild' : false,
reportCompressedSize: false,
rollupOptions: {
input: { login: resolve(__dirname, 'assets/scripts/login.js') },
output: {

View file

@ -176,11 +176,17 @@ function render(data) {
/* Filtered data, excludes values too small to be shown in the chart
* values with a number lesser then 0.0%
*/
const filtered_data = data.map((d, i) => ({
const filtered_data = data
.filter((d) => d.value > 0) // only exclude actual zeros
.map((d) => ({
label: d.label,
value: d.value,
percentage: total > 0 ? (d.value / total * 100).toFixed(1) : "0"
})).filter((el) => el.percentage > 0.0);
percentage: total > 0 ? (d.value / total * 100).toFixed(2) : "0"
}));
// there is no data to show
if (filtered_data.length === 0) {
no_data.value = true;
}
items.value = filtered_data.map((d, i) => ({
name: d.label,

View file

@ -3542,6 +3542,15 @@ local lang = {
["unresolved_hostname_description"] = "Trigger an alert when a TLS/QUIC/HTTP flow connects with a symbolic hostname not previously resolved via DNS",
},
["flow_details"] = {
["bgp_peer_id"] = "Peer ID",
["bgp_prefix"] = "BGP Prefix",
["bgp_peer_id"] = "Peer ID",
["bgp_origin"] = "Origin",
["bgp_as_path"] = "AS Path",
["bgp_next_hop"] = "Next Hop",
["bgp_med"] = "MED",
["bgp_local_pref"] = "Local Preference",
["bgp_communities"]= "Communities",
["acceptable_label"] = "Acceptable",
["actual_peak_throughput"] = "Actual / Peak / Average Throughput",
["additional_alert_type"] = "Other Issues",
@ -6143,6 +6152,13 @@ local lang = {
["total_flow_duration"] = "Total Duration",
["total_num_calls"] = "Total %{subdir} Scripts Num Calls",
["total_stats"] = "Total %{subdir} Scripts Stats",
["alerts_drops"] = "Alerts Drops",
["any_issue"] = "Any Issue",
["availability"] = "Availability",
["num_filtered"] = "Filtered",
["periodic_activities_tot_not_executed_descr_short"] = "Not Executed",
["periodic_activities_tot_running_slow_descr_short"] = "Running Slow",
["script"] = "Script",
["work_completion"] = "Completion",
},
["invalid_filters"] = {
@ -7125,6 +7141,7 @@ local lang = {
["timeout_warning"] = "Request Timeout",
["ask_a_question"] = "Ask nAnalyst a question",
["error_label"] = "Error",
["calls"] = "Calls",
["input_placeholder"] = "Ask a question",
["analyzing"] = "Analyzing...",
["investigating"] = "Investigating...",
@ -7149,6 +7166,11 @@ local lang = {
["usage_by_user"] = "Usage By User",
["initial_call"] = "User Question",
["tool_followup"] = "Tool Followup",
["total_tokens"] = "Total Tokens",
["unique_chats"] = "Unique Chats",
["token_share"] = "Token Share",
["avg_ms"] = "Avg Response ms",
["max_ms"] = "Max Response ms",
["final_response"] = "Final Response",
["retry"] = "Retry",
["stat_total_calls"] = "Total LLM Calls",

View file

@ -6,6 +6,107 @@ local format_utils = {}
local clock_start = os.clock()
function format_utils.formatBgpBmpInfo(bgp_data)
for prefix, peers in pairs(bgp_data) do
local peer_list = {}
for bgp_id, info in pairs(peers) do
peer_list[#peer_list + 1] = { id = bgp_id, info = info }
end
print("</table>\n")
print("<table class='table table-bordered table-striped' width='100%'>")
-- Prefix
print("<tr><th colspan=" .. (#peer_list + 1) .. ">" ..
i18n("flow_details.bgp_prefix") .. ":&nbsp;" .. prefix .. "</th></tr>\n")
-- Peer ID
print("<tr><th>" .. i18n("flow_details.bgp_peer_id") .."</th>")
for _, peer in ipairs(peer_list) do
print("<th>" .. peer.id .. "</th>")
end
print("</tr>\n")
-- BGP Origin
print("<tr><th>" .. i18n("flow_details.bgp_origin") .. "</th>")
for _, peer in ipairs(peer_list) do
print("<td>" .. (peer.info["origin"] or "") .. "</td>")
end
print("</tr>\n")
-- AS Path
print("<tr><th>" .. i18n("flow_details.bgp_as_path") .. "</th>")
for _, peer in ipairs(peer_list) do
local as_path_string = ""
if peer.info["as_path"] and #peer.info["as_path"] > 0 then
local parts = {}
for _, asn in ipairs(peer.info["as_path"]) do
parts[#parts + 1] = tostring(asn)
end
as_path_string = table.concat(parts, ' ')
end
print("<td>" .. as_path_string .. "</td>")
end
print("</tr>\n")
-- Next Hop
print("<tr><th>" .. i18n("flow_details.bgp_next_hop") .. "</th>")
for _, peer in ipairs(peer_list) do
print("<td>" .. (peer.info["next_hop"] or "") .. "</td>")
end
print("</tr>\n")
-- MED
print("<tr><th>" .. i18n("flow_details.bgp_med") .. "</th>")
for _, peer in ipairs(peer_list) do
local med_string = (peer.info["med"] ~= nil) and tostring(peer.info["med"]) or ""
print("<td>" .. med_string .. "</td>")
end
print("</tr>\n")
-- Local Preference
print("<tr><th>" .. i18n("flow_details.bgp_local_pref") .. "</th>")
for _, peer in ipairs(peer_list) do
local lp_string = (peer.info["local_pref"] ~= nil) and tostring(peer.info["local_pref"]) or ""
print("<td>" .. lp_string .. "</td>")
end
print("</tr>\n")
-- Communities
print("<tr><th>" .. i18n("flow_details.bgp_communities") .. "</th>")
for _, peer in ipairs(peer_list) do
local communities_string = ""
if peer.info["communities"] and #peer.info["communities"] > 0 then
local badges = {}
for _, c in ipairs(peer.info["communities"]) do
badges[#badges + 1] = "<span class='badge bg-secondary'>" .. c .. "</span>"
end
communities_string = table.concat(badges, " ")
end
print("<td>" .. communities_string .. "</td>")
end
print("</tr>\n")
print("</table>\n")
print("<table class='table table-bordered table-striped'>\n")
end
end
function format_utils.createBreakdown(percentage1, percentage2, label1, label2)
if percentage1 == 0 and percentage2 == 0 then
return '<div style="height:8px;background:var(--border-subtle,#e9ecef);border-radius:100px;" data-bs-toggle="tooltip" title="No data available"></div>'
@ -80,19 +181,19 @@ function format_utils.timeToSeconds(time)
local index = 1 -- represents which time we are analyzing, seconds, minutes, ecc.
-- Split by : to get days, hours, minutes and seconds
for _, time_in_string in pairsByKeys(time_splitted:split(":") or {}, rev) do
for _, time_in_stringing in pairsByKeys(time_splitted:split(":") or {}, rev) do
if index == 1 then
-- Seconds
seconds = seconds + tonumber(time_in_string)
seconds = seconds + tonumber(time_in_stringing)
elseif index == 2 then
-- Minutes
seconds = seconds + tonumber(time_in_string) * 60
seconds = seconds + tonumber(time_in_stringing) * 60
elseif index == 3 then
-- Hours
seconds = seconds + tonumber(time_in_string) * 3600
seconds = seconds + tonumber(time_in_stringing) * 3600
elseif index == 4 then
-- Days
seconds = seconds + tonumber(time_in_string) * 86400
seconds = seconds + tonumber(time_in_stringing) * 86400
end
index = index + 1
@ -788,9 +889,9 @@ local _asn_cache = {}
-- asn name formatted consistently
-- @params asn: ASN Id
-- short_version: Boolean, true if short version is needed (only name)
-- shorten_string: Boolean, true if 64 char must be used
-- shorten_stringing: Boolean, true if 64 char must be used
-- @returns The formatted ASN name
function format_utils.formatASN(asn, short_version, shorten_string)
function format_utils.formatASN(asn, short_version, shorten_stringing)
local name = ""
if asn then
@ -813,7 +914,7 @@ function format_utils.formatASN(asn, short_version, shorten_string)
-- if no asn info is present, curl to get ASN name
name = ntop.getASNameFromASN(asn)
end
if (shorten_string) then
if (shorten_stringing) then
name = shortenString(name)
end
end

View file

@ -78,13 +78,6 @@ function stats_utils.collapse_top_stats(stats, threshold)
value = other_total,
}
end
if #top_res == 0 then
top_res[#top_res + 1] = {
label = i18n("no_flows"),
value = 0,
}
end
return top_res
end

View file

@ -29,10 +29,12 @@ end
local data = {}
for key, value in pairsByField(stats.qoe, "num", rev) do
data[#data + 1] = {
label = i18n("flow_details.qoe_" .. key .. "_label") or "",
value = value.num
}
if value.num > 0 then
data[#data + 1] = {
label = i18n("flow_details.qoe_" .. key .. "_label") or "",
value = value.num
}
end
end
if collapse_stats then

View file

@ -19,11 +19,16 @@ interface.select(ifid)
local ifstats = interface.getFlowsStatus()
local data = {
{ label = i18n('enstablished'), value = ifstats["Established"] },
{ label = i18n('syn'), value = ifstats["SYN"] },
{ label = i18n('rst'), value = ifstats["RST"] },
{ label = i18n('fin'), value = ifstats["FIN"] },
}
local function add_entry(t, label_key, val)
if val ~= 0 then
table.insert(t, { label = i18n(label_key), value = val })
end
end
local data = {}
add_entry(data, 'enstablished', ifstats["Established"])
add_entry(data, 'syn', ifstats["SYN"])
add_entry(data, 'rst', ifstats["RST"])
add_entry(data, 'fin', ifstats["FIN"])
rest_utils.answer(rest_utils.consts.success.ok, data)