From c755e701f012d55dcffc62318f558a1d0c911565 Mon Sep 17 00:00:00 2001 From: GabrieleDeri <33870399+DGabri@users.noreply.github.com> Date: Wed, 1 Apr 2026 08:55:43 +0200 Subject: [PATCH] Fixed pie chart no data messagae missing, handle no data from component (#10238) --- build.mjs | 1 + http_src/vue/charts/pie-chart.vue | 12 +- scripts/locales/en.lua | 22 ++++ scripts/lua/modules/format_utils.lua | 117 ++++++++++++++++-- scripts/lua/modules/stats_utils.lua | 7 -- .../lua/rest/v2/get/interface/qoe/stats.lua | 10 +- .../lua/rest/v2/get/interface/tcp_stats.lua | 17 ++- 7 files changed, 158 insertions(+), 28 deletions(-) diff --git a/build.mjs b/build.mjs index 63f94f1ce4..335eff8ca8 100644 --- a/build.mjs +++ b/build.mjs @@ -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: { diff --git a/http_src/vue/charts/pie-chart.vue b/http_src/vue/charts/pie-chart.vue index f360b08737..5e062d9133 100644 --- a/http_src/vue/charts/pie-chart.vue +++ b/http_src/vue/charts/pie-chart.vue @@ -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, diff --git a/scripts/locales/en.lua b/scripts/locales/en.lua index 9c1f7e404c..f621a6b8f0 100644 --- a/scripts/locales/en.lua +++ b/scripts/locales/en.lua @@ -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", diff --git a/scripts/lua/modules/format_utils.lua b/scripts/lua/modules/format_utils.lua index 4bdff18950..a6c64ba0cb 100644 --- a/scripts/lua/modules/format_utils.lua +++ b/scripts/lua/modules/format_utils.lua @@ -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("\n") + + print("") + + -- Prefix + print("\n") + + -- Peer ID + print("") + for _, peer in ipairs(peer_list) do + print("") + end + print("\n") + + -- BGP Origin + print("") + for _, peer in ipairs(peer_list) do + print("") + end + + print("\n") + + -- AS Path + print("") + 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("") + end + + print("\n") + + -- Next Hop + print("") + for _, peer in ipairs(peer_list) do + print("") + end + + print("\n") + + -- MED + print("") + for _, peer in ipairs(peer_list) do + local med_string = (peer.info["med"] ~= nil) and tostring(peer.info["med"]) or "" + print("") + end + + print("\n") + + -- Local Preference + print("") + for _, peer in ipairs(peer_list) do + local lp_string = (peer.info["local_pref"] ~= nil) and tostring(peer.info["local_pref"]) or "" + print("") + end + + print("\n") + + -- Communities + print("") + 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] = "" .. c .. "" + end + communities_string = table.concat(badges, " ") + end + print("") + + end + print("\n") + + print("
" .. + i18n("flow_details.bgp_prefix") .. ": " .. prefix .. "
" .. i18n("flow_details.bgp_peer_id") .."" .. peer.id .. "
" .. i18n("flow_details.bgp_origin") .. "" .. (peer.info["origin"] or "") .. "
" .. i18n("flow_details.bgp_as_path") .. "" .. as_path_string .. "
" .. i18n("flow_details.bgp_next_hop") .. "" .. (peer.info["next_hop"] or "") .. "
" .. i18n("flow_details.bgp_med") .. "" .. med_string .. "
" .. i18n("flow_details.bgp_local_pref") .. "" .. lp_string .. "
" .. i18n("flow_details.bgp_communities") .. "" .. communities_string .. "
\n") + print("\n") + + end +end + function format_utils.createBreakdown(percentage1, percentage2, label1, label2) if percentage1 == 0 and percentage2 == 0 then return '
' @@ -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 diff --git a/scripts/lua/modules/stats_utils.lua b/scripts/lua/modules/stats_utils.lua index c3fd60c697..9de52fb569 100644 --- a/scripts/lua/modules/stats_utils.lua +++ b/scripts/lua/modules/stats_utils.lua @@ -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 diff --git a/scripts/lua/rest/v2/get/interface/qoe/stats.lua b/scripts/lua/rest/v2/get/interface/qoe/stats.lua index e9126405ff..ce2b1a0bd2 100644 --- a/scripts/lua/rest/v2/get/interface/qoe/stats.lua +++ b/scripts/lua/rest/v2/get/interface/qoe/stats.lua @@ -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 diff --git a/scripts/lua/rest/v2/get/interface/tcp_stats.lua b/scripts/lua/rest/v2/get/interface/tcp_stats.lua index 9aa6c03139..a0e3e3c685 100644 --- a/scripts/lua/rest/v2/get/interface/tcp_stats.lua +++ b/scripts/lua/rest/v2/get/interface/tcp_stats.lua @@ -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) \ No newline at end of file