mirror of
https://github.com/ntop/ntopng.git
synced 2026-07-09 16:00:51 +00:00
Ported menu, footer and topbar to vuejs (#10480)
* Ported menu, footer and topbar to vuejs * Update dist
This commit is contained in:
parent
c15b731d73
commit
6e6bb7287c
20 changed files with 5859 additions and 2443 deletions
|
|
@ -71,4 +71,3 @@ import * as d3v7 from "d3v7";
|
|||
window.d3v7 = {
|
||||
...d3v7
|
||||
};
|
||||
|
||||
|
|
|
|||
874
attic/scripts/lua/inc/footer.lua
Normal file
874
attic/scripts/lua/inc/footer.lua
Normal file
|
|
@ -0,0 +1,874 @@
|
|||
--
|
||||
-- (C) 2013-26 - ntop.org
|
||||
--
|
||||
require "os"
|
||||
require "lua_utils"
|
||||
|
||||
local ts_utils = require("ts_utils_core")
|
||||
|
||||
local template = require "template_utils"
|
||||
local stats_utils = require("stats_utils")
|
||||
local page_utils = require "page_utils"
|
||||
local have_nedge = ntop.isnEdge()
|
||||
local info = ntop.getInfo(true)
|
||||
local is_admin = isAdministrator()
|
||||
local maxSpeed
|
||||
|
||||
local ifid = interface.getId()
|
||||
local _ifstats = interface.getStats()
|
||||
local http_prefix = ntop.getHttpPrefix()
|
||||
local random_csrf = ntop.getRandomCSRFValue()
|
||||
local is_pcap_dump_iface = interface.isPcapDumpInterface()
|
||||
|
||||
if not is_pcap_dump_iface and not have_nedge then
|
||||
-- if the speed in not custom we try to read the speed from the interface
|
||||
-- and, as a final resort, we use 1Gbps
|
||||
if tonumber(_ifstats.speed) ~= nil then
|
||||
maxSpeed = tonumber(_ifstats.speed) * 1e6
|
||||
else
|
||||
maxSpeed = 1000000000 -- 1 Gbit
|
||||
end
|
||||
end -- closes is_pcap_dump_iface == false
|
||||
|
||||
if not info.oem then
|
||||
|
||||
-- print ([[
|
||||
-- <hr>
|
||||
-- <footer id="n-footer">
|
||||
-- <div class="container-fluid">
|
||||
-- <div class="row mt-2">
|
||||
-- <div class="col-12 col-md-4 pl-md-0 text-center text-md-start">
|
||||
-- <small>
|
||||
-- <a href="https://www.ntop.org/products/traffic-analysis/ntop/" target="_blank">
|
||||
-- ]] .. getNtopngRelease(info) ..[[
|
||||
-- </a>
|
||||
-- </small>
|
||||
-- </div>
|
||||
-- <div class="col-12 col-md-4 text-center">
|
||||
-- <small>]].. ntop.getInfo()["copyright"] ..[[</small>
|
||||
-- ]])
|
||||
-- print [[
|
||||
-- </div>
|
||||
-- <div class="col-12 col-md-4 text-center text-md-end pr-md-0">
|
||||
-- <small>
|
||||
-- <i class="fas fa-clock" title="]] print(i18n("about.server_time")) print[["></i> <div class="d-inline-block" id='network-clock'></div> ]] if(info.tzname ~= nil) then print(info.tzname) end print(" | ") print(i18n("about.uptime")) print[[: <div class="d-inline-block" id='network-uptime'></div>
|
||||
-- </small>
|
||||
-- </div>
|
||||
-- </div>
|
||||
-- </div>
|
||||
-- </footer>
|
||||
-- ]]
|
||||
|
||||
-- else -- info.oem
|
||||
-- print[[<div class="col-12 text-end">
|
||||
-- <small>
|
||||
-- <i class="fas fa-clock"></i> <div class="d-inline-block" id='network-clock' title="]] print(i18n("about.server_time")) print[["></div> | ]] print(i18n("about.uptime")) print[[: <div class="d-inline-block" id='network-uptime'></div>
|
||||
-- </small>
|
||||
-- </div>]]
|
||||
end
|
||||
|
||||
local traffic_peity_width = "96"
|
||||
|
||||
if ts_utils.getDriverName() == "influxdb" then
|
||||
|
||||
local msg = ntop.getCache("ntopng.cache.influxdb.last_error")
|
||||
if not isEmptyString(msg) then
|
||||
print([[
|
||||
<script type="text/javascript">
|
||||
$("#influxdb-error-msg-text").html("]] .. (msg:gsub('"', '\\"')) .. [[");
|
||||
$("#influxdb-error-msg").show();
|
||||
</script>
|
||||
]])
|
||||
end
|
||||
end
|
||||
|
||||
-- Dismiss Notification Code and Toggle Dark theme
|
||||
print([[
|
||||
<script type='text/javascript'>
|
||||
$(document).ready(function() {
|
||||
|
||||
$(`.notification button.dismiss`).click(function() {
|
||||
const $toast = $(this).parents('.notification');
|
||||
const id = $toast.data("toastId");
|
||||
ToastUtils.dismissToast(id, "]] .. random_csrf ..
|
||||
[[", (data) =>{
|
||||
if (data.success) $toast.toast('hide');
|
||||
});
|
||||
});
|
||||
|
||||
$(`.toggle-dark-theme`).click(function() {
|
||||
const request = $.post(`]] .. http_prefix ..
|
||||
[[/lua/update_prefs.lua`, {
|
||||
action: 'toggle_theme', toggle_dark_theme: ]] ..
|
||||
tostring(not page_utils.is_dark_mode_enabled()) .. [[,
|
||||
csrf: "]] .. random_csrf .. [["
|
||||
});
|
||||
request.done(function(res) {
|
||||
if (res.success) location.reload();
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
]])
|
||||
|
||||
-- Restart product code
|
||||
if (is_admin and ntop.isPackage() and not ntop.isWindows()) then
|
||||
|
||||
print(template.gen("modal_confirm_dialog.html", {
|
||||
dialog = {
|
||||
id = 'restart-modal',
|
||||
action = 'restartService()',
|
||||
title = i18n("restart.restart_product", {product = info.product}),
|
||||
message = i18n("restart.confirm", {product = info.product}),
|
||||
custom_alert_class = 'alert alert-danger',
|
||||
confirm = i18n('restart.restart'),
|
||||
confirm_button = 'btn-danger'
|
||||
}
|
||||
}))
|
||||
|
||||
print [[
|
||||
<script type="text/javascript">
|
||||
|
||||
const restartCSRF = ']]
|
||||
print(random_csrf)
|
||||
print [[';
|
||||
const restartService = function() {
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: ']]
|
||||
print(http_prefix)
|
||||
print [[/lua/admin/service_restart.lua',
|
||||
data: {
|
||||
csrf: restartCSRF
|
||||
},
|
||||
success: function(rsp) {
|
||||
alert("]]
|
||||
print(i18n("restart.restarting", {product = info.product}))
|
||||
print [[");
|
||||
$('#restart-modal').modal('hide');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$('.restart-service').click(() => {
|
||||
$('#restart-modal').modal('show');
|
||||
});
|
||||
|
||||
</script>
|
||||
]]
|
||||
end
|
||||
|
||||
-- render switchable system view
|
||||
print([[
|
||||
<script type="text/javascript">
|
||||
|
||||
$(document).ready(function() {
|
||||
|
||||
// ignore scientific numbers input
|
||||
$(`.ignore-scientific`).keypress(function(e) {
|
||||
if (e.which != 8 && e.which != 0 && e.which < 48 || e.which > 57) {
|
||||
e.preventDefault();
|
||||
}
|
||||
})
|
||||
|
||||
ToastUtils.initToasts();
|
||||
});
|
||||
|
||||
const toggleSystemInterface = ($form = null) => {
|
||||
if($form != null) {
|
||||
$form.submit();
|
||||
}
|
||||
else {
|
||||
console.error("An error has occurred when switching interface!");
|
||||
}
|
||||
}
|
||||
]])
|
||||
print([[
|
||||
</script>
|
||||
]])
|
||||
|
||||
print [[
|
||||
<script type="text/javascript">
|
||||
]]
|
||||
|
||||
print [[
|
||||
var is_historical = false;
|
||||
let updatingChart_uploads = [
|
||||
$("#n-navbar .network-load-chart-upload").show().peity("line", { width: ]]
|
||||
print(traffic_peity_width)
|
||||
print [[, max: null }),
|
||||
$(".mobile-menu-stats .network-load-chart-upload").show().peity("line", { width: ]]
|
||||
print(traffic_peity_width)
|
||||
print [[, max: null }),
|
||||
];
|
||||
let updatingChart_downloads = [
|
||||
$("#n-navbar .network-load-chart-download").show().peity("line", { width: ]]
|
||||
print(traffic_peity_width)
|
||||
print [[, max: null, fill: "lightgreen"}),
|
||||
$(".mobile-menu-stats .network-load-chart-download").show().peity("line", { width: ]]
|
||||
print(traffic_peity_width)
|
||||
print [[, max: null, fill: "lightgreen"})
|
||||
];
|
||||
let updatingChart_totals = [
|
||||
$("#n-navbar .network-load-chart-total").show().peity("line", { width: ]]
|
||||
print(traffic_peity_width)
|
||||
print [[, max: null}),
|
||||
$(".mobile-menu-stats .network-load-chart-total").show().peity("line", { width: ]]
|
||||
print(traffic_peity_width)
|
||||
print [[, max: null})
|
||||
];
|
||||
|
||||
$(`.copy-http-url`).on('click', function() {
|
||||
let sampleTextarea = document.createElement("textarea");
|
||||
document.body.appendChild(sampleTextarea);
|
||||
sampleTextarea.value = $(this).attr('data-to-copy');
|
||||
sampleTextarea.select(); //select textarea content
|
||||
document.execCommand("copy");
|
||||
document.body.removeChild(sampleTextarea);
|
||||
})
|
||||
|
||||
let isFooterRefreshInProcess = false;
|
||||
const footerRefresh = function() {
|
||||
if (isFooterRefreshInProcess == true) { return; }
|
||||
isFooterRefreshInProcess = true;
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url: ']]
|
||||
print(http_prefix)
|
||||
print [[/lua/rest/v2/get/interface/data.lua',
|
||||
data: { ifid: ]]
|
||||
print(tostring(ifid))
|
||||
print [[, type: 'summary' },
|
||||
success: function(content) {
|
||||
isFooterRefreshInProcess = false;
|
||||
if(content["rc_str"] != "OK") {
|
||||
return;
|
||||
}
|
||||
|
||||
const rsp = content["rsp"];
|
||||
|
||||
try {
|
||||
ntopng_events_manager.emit_custom_event(ntopng_custom_events.GET_INTERFACE_DATA, rsp);
|
||||
let bps_upload = rsp.throughput.upload * 8;
|
||||
let bps_download = rsp.throughput.download * 8;
|
||||
|
||||
/* Upload chart */
|
||||
let values = updatingChart_uploads[0].text().split(",")
|
||||
values.shift();
|
||||
values.push(bps_upload.toString());
|
||||
updatingChart_uploads[0].text(values.join(",")).change();
|
||||
updatingChart_uploads[1].text(values.join(",")).change();
|
||||
$('.chart-upload-text:visible').html(NtopUtils.bitsToSize(bps_upload, 1000));
|
||||
|
||||
/* Download chart */
|
||||
values = updatingChart_downloads[0].text().split(",")
|
||||
values.shift();
|
||||
values.push((-bps_download).toString());
|
||||
updatingChart_downloads[0].text(values.join(",")).change();
|
||||
updatingChart_downloads[1].text(values.join(",")).change();
|
||||
$('.chart-download-text:visible').html(NtopUtils.bitsToSize(bps_download, 1000));
|
||||
|
||||
/* Disaggregate interface chart */
|
||||
values = updatingChart_totals[0].text().split(",")
|
||||
values.shift();
|
||||
values.push(rsp.throughput_bps * 8);
|
||||
updatingChart_totals[0].text(values.join(",")).change();
|
||||
updatingChart_totals[1].text(values.join(",")).change();
|
||||
]]
|
||||
|
||||
if (is_pcap_dump_iface == false) and (not have_nedge) then
|
||||
print [[
|
||||
const v = Math.round(Math.min((rsp.throughput_bps * 8 *100)/]]
|
||||
print(string.format("%u", maxSpeed))
|
||||
print [[, 100));
|
||||
$('.network-load').html(v+"%");
|
||||
]]
|
||||
end
|
||||
|
||||
-- systemInterfaceEnabled is defined inside menu.lua
|
||||
print [[
|
||||
//$('#network-clock').html(`${rsp.localtime}`);
|
||||
//$('#network-uptime').html(`${rsp.uptime}`);
|
||||
|
||||
let msg = `<div class='m-2'><div class='d-flex flex-wrap navbar-main-badges'>`;
|
||||
|
||||
if(rsp.out_of_maintenance) {
|
||||
msg += "<a href='https://www.ntop.org/support/faq/how-can-i-renew-maintenance-for-commercial-products/' target='_blank'><span class='badge bg-warning'>]]
|
||||
print(i18n("about.maintenance_expired", {product = info["product"]}))
|
||||
print [[ <i class=\"fas fa-external-link-alt\"></i></span></a> ";
|
||||
}
|
||||
|
||||
if(rsp.degraded_performance) {
|
||||
msg += "<a href=']]
|
||||
print(http_prefix)
|
||||
print [[/lua/system_interfaces_stats.lua?page=internals&tab=periodic_activities&periodic_script_issue=any_issue'>"
|
||||
msg += "<span class='badge bg-warning'><i class='fas fa-exclamation-triangle data-bs-toggle='tooltip' data-bs-placement='bottom' title=']]
|
||||
print(i18n("internals.degraded_performance"))
|
||||
print [['></i></span></a>";
|
||||
}
|
||||
|
||||
if ((rsp.engaged_alerts > 0 || rsp.alerted_flows > 0) && ]]
|
||||
print(ternary(hasAllowedNetworksSet(), "false", "true"))
|
||||
print [[) {
|
||||
|
||||
var error_color = "#B94A48";
|
||||
|
||||
if(rsp.engaged_alerts > 0) {
|
||||
let alerts_badge = "bg-info";
|
||||
|
||||
if(rsp.engaged_alerts_error > 0) alerts_badge = "bg-danger";
|
||||
else if(rsp.engaged_alerts_warning > 0) alerts_badge = "bg-warning";
|
||||
|
||||
msg += "<a href=']]
|
||||
print(http_prefix)
|
||||
print [[/lua/alert_stats.lua?ifid=]]
|
||||
print(tostring(ifid))
|
||||
print [[&status=engaged'>"
|
||||
msg += "<span class=\"badge " + alerts_badge + "\" data-bs-toggle='tooltip' data-bs-placement='bottom' title=']] print(i18n('graphs.engaged_alerts')) print[['><i class=\"fas fa-exclamation-triangle\"></i> "+NtopUtils.formatValue(rsp.engaged_alerts, 1)+"</span></a>";
|
||||
}
|
||||
|
||||
if(rsp.alerted_flows_warning > 0 && !(systemInterfaceEnabled)) {
|
||||
msg += "<a href=']]
|
||||
print(http_prefix)
|
||||
print [[/lua/flows_stats.lua?status=warning'>"
|
||||
msg += "<span class=\"badge bg-warning\" data-bs-toggle='tooltip' data-bs-placement='bottom' title=']]
|
||||
print(i18n("flow_details.alerted_flows"))
|
||||
print [['>"+NtopUtils.formatValue(rsp.alerted_flows_warning, 1)+ " <i class=\"fas fa-stream\"></i> ]]
|
||||
print [[ <i class=\"fas fa-exclamation-triangle\"></i></span></a>";
|
||||
}
|
||||
|
||||
if(rsp.alerted_flows_error > 0 && !(systemInterfaceEnabled)) {
|
||||
msg += "<a href=']]
|
||||
print(http_prefix)
|
||||
print [[/lua/flows_stats.lua?status=error'>"
|
||||
msg += "<span class=\"badge bg-danger\" data-bs-toggle='tooltip' data-bs-placement='bottom' title=']]
|
||||
print(i18n("flow_details.dangerous_flows"))
|
||||
print [['>"+NtopUtils.formatValue(rsp.alerted_flows_error, 1)+ " <i class=\"fas fa-stream\"></i> ]]
|
||||
print [[ <i class=\"fas fa-exclamation-triangle\"></i></span></a>";
|
||||
}
|
||||
|
||||
if(rsp.active_discovery_active === true) {
|
||||
msg += "<a href=']]
|
||||
print(http_prefix)
|
||||
print [[/lua/discover.lua'>"
|
||||
msg += "<span class=\"badge bg-warning\" data-bs-toggle='tooltip' data-bs-placement='bottom' title=']]
|
||||
print(i18n("prefs.network_discovery_running"))
|
||||
print [['><i class=\"fas fa-project-diagram\"></i></span></a>";
|
||||
}
|
||||
}
|
||||
|
||||
if((rsp.engaged_alerts > 0 || rsp.alerted_flows > 0) && $("#alerts-id").is(":visible") == false) {
|
||||
$("#alerts-id").show();
|
||||
}
|
||||
|
||||
if(rsp.ts_alerts && rsp.ts_alerts.influxdb && (!systemInterfaceEnabled)) {
|
||||
msg += "<a href=']]
|
||||
print(http_prefix)
|
||||
print [[/lua/monitor/influxdb_monitor.lua?ifid=]]
|
||||
print(tostring(ifid))
|
||||
print [[&page=alerts#tab-table-engaged-alerts'>"
|
||||
msg += "<span class=\"badge bg-danger\" data-bs-toggle='tooltip' data-bs-placement='bottom' title=']] print(i18n('alerts_dashboard.influxdb_error')) print[['><i class=\"fas fa-database\"></i></span></a>";
|
||||
}
|
||||
|
||||
var alarm_threshold_low = 60; /* 60% */
|
||||
var alarm_threshold_high = 90; /* 90% */
|
||||
var alert = 0;
|
||||
|
||||
if(rsp.num_local_hosts > 0 && (!systemInterfaceEnabled)) {
|
||||
msg += "<a href=']]
|
||||
print(http_prefix)
|
||||
print [[/lua/hosts_stats.lua?mode=local'>";
|
||||
msg += "<span data-bs-toggle='tooltip' data-bs-placement='bottom' title=\"]]
|
||||
print(i18n("local_hosts"))
|
||||
print [[\" class=\"badge bg-success\">";
|
||||
msg += NtopUtils.formatValue(rsp.num_local_hosts, 1);
|
||||
if(rsp.num_local_rcvd_only_hosts > 0) msg += " ("+NtopUtils.formatValue(rsp.num_local_rcvd_only_hosts, 1)+")";
|
||||
msg += " <i class=\"fas fa-laptop\" aria-hidden=\"true\"></i></span></a>";
|
||||
}
|
||||
|
||||
const num_remote_hosts = rsp.num_hosts - rsp.num_local_hosts;
|
||||
if(num_remote_hosts > 0 && (!systemInterfaceEnabled)) {
|
||||
msg += "<a href=']]
|
||||
print(http_prefix)
|
||||
print [[/lua/hosts_stats.lua?mode=remote'>";
|
||||
var remote_hosts_label = "]]
|
||||
print(i18n("remote_hosts"))
|
||||
print [[";
|
||||
|
||||
if (rsp.hosts_pctg < alarm_threshold_low && !systemInterfaceEnabled) {
|
||||
msg += "<span data-bs-toggle='tooltip' data-bs-placement='bottom' title=\"" + remote_hosts_label +"\" class=\"badge bg-secondary\">";
|
||||
} else if (rsp.hosts_pctg < alarm_threshold_high && !systemInterfaceEnabled) {
|
||||
alert = 1;
|
||||
msg += "<span data-bs-toggle='tooltip' data-bs-placement='bottom' title=\"" + remote_hosts_label +"\" class=\"badge bg-warning\">";
|
||||
} else {
|
||||
alert = 1;
|
||||
msg += "<span data-bs-toggle='tooltip' data-bs-placement='bottom' title=\"" + remote_hosts_label +"\" class=\"badge bg-danger\">";
|
||||
}
|
||||
|
||||
msg += NtopUtils.formatValue(num_remote_hosts, 1);
|
||||
num_remote_rcvd_only_hosts = rsp.num_rcvd_only_hosts - rsp.num_local_rcvd_only_hosts;
|
||||
if(num_remote_rcvd_only_hosts > 0) msg += " ("+NtopUtils.formatValue(num_remote_rcvd_only_hosts, 1)+")";
|
||||
msg += " <i class=\"fas fa-laptop\" aria-hidden=\"true\"></i></span></a>";
|
||||
}
|
||||
|
||||
if(rsp.num_devices > 0 && (!systemInterfaceEnabled)) {
|
||||
var macs_label = "]]
|
||||
print(i18n("mac_stats.layer_2_source_devices", {device_type = ""}))
|
||||
print [[";
|
||||
msg += "<a href=']]
|
||||
print(http_prefix)
|
||||
print [[/lua/macs_stats.lua?devices_mode=source_macs_only'>";
|
||||
|
||||
if (rsp.macs_pctg < alarm_threshold_low) {
|
||||
msg += "<span data-bs-toggle='tooltip' data-bs-placement='bottom' title=\"" + macs_label +"\" class=\"badge bg-secondary\">";
|
||||
} else if(rsp.macs_pctg < alarm_threshold_high) {
|
||||
alert = 1;
|
||||
msg += "<span data-bs-toggle='tooltip' data-bs-placement='bottom' title=\"" + macs_label +"\" class=\"badge bg-warning\">";
|
||||
} else {
|
||||
alert = 1;
|
||||
msg += "<span data-bs-toggle='tooltip' data-bs-placement='bottom' title=\"" + macs_label +"\" class=\"badge bg-danger\">";
|
||||
}
|
||||
|
||||
msg += NtopUtils.formatValue(rsp.num_devices, 1)+" <i class=\"fas fa-ethernet\"></i></span></a>";
|
||||
}
|
||||
|
||||
if(rsp.num_flows > 0 && (!systemInterfaceEnabled)) {
|
||||
msg += "<a href=']]
|
||||
print(http_prefix)
|
||||
print [[/lua/flows_stats.lua'>";
|
||||
const flows_label = "]]
|
||||
print(i18n("live_flows"))
|
||||
print [["
|
||||
if (rsp.flows_pctg < alarm_threshold_low) {
|
||||
msg += "<span data-bs-toggle='tooltip' data-bs-placement='bottom' title=\"" + flows_label +"\" class=\"badge bg-secondary\">";
|
||||
} else if(rsp.flows_pctg < alarm_threshold_high) {
|
||||
alert = 1;
|
||||
msg += "<span data-bs-toggle='tooltip' data-bs-placement='bottom' title=\"" + flows_label +"\" class=\"badge bg-warning\">";
|
||||
} else {
|
||||
alert = 1;
|
||||
msg += "<span data-bs-toggle='tooltip' data-bs-placement='bottom' title=\"" + flows_label +"\" class=\"badge bg-danger\">";
|
||||
}
|
||||
|
||||
msg += NtopUtils.formatValue(rsp.num_flows, 1)+" <i class=\"fas fa-stream\"></i> </span> </a>";
|
||||
|
||||
if (rsp.db && rsp.db.flow_export_drops > 0) {
|
||||
const export_pctg = rsp.db.flow_export_drops / (rsp.db.flow_export_count + rsp.db.flow_export_drops + 1);
|
||||
if (export_pctg > ]]
|
||||
print(stats_utils.UPPER_BOUND_INFO_EXPORTS)
|
||||
print [[) {
|
||||
const badge_class = (export_pctg <= ]]
|
||||
print(stats_utils.UPPER_BOUND_WARNING_EXPORTS)
|
||||
print [[) ? 'warning' : 'danger';
|
||||
msg += "<a href=']]
|
||||
print(http_prefix)
|
||||
print [[/lua/if_stats.lua'><span class=\"badge bg-"+badge_class+"\" data-bs-toggle='tooltip' data-bs-placement='bottom' title=\"]] print(i18n('flow_export_drops')) print[[\"><i class=\"fas fa-exclamation-triangle\" style=\"color: #FFFFFF;\"></i> "+NtopUtils.formatValue(rsp.db.flow_export_drops, 1)+" DB Export drop";
|
||||
if(rsp.db.flow_export_drops > 1) msg += "s";
|
||||
msg += "</span></a>";
|
||||
}
|
||||
}
|
||||
if (rsp.dropped_zmq_msg > 0) {
|
||||
msg += "<a href=']]
|
||||
print(http_prefix)
|
||||
print [[/lua/if_stats.lua'><span class=\"badge bg-warning\"><i class=\"fas fa-tint\" style=\"color: #FFFFFF;\" data-bs-toggle='tooltip' data-bs-placement='bottom' title=\"]] print(i18n('dropping_zmq_msg')) print[[\"></i> "+NtopUtils.formatValue(rsp.dropped_zmq_msg, 1)+" ZMQ Drops</span></a>";
|
||||
}
|
||||
if (rsp.dropped_flows > 0) {
|
||||
msg += "<a href=']]
|
||||
print(http_prefix)
|
||||
print [[/lua/if_stats.lua'><span class=\"badge bg-warning\"><i class=\"fas fa-tint\" style=\"color: #FFFFFF;\" data-bs-toggle='tooltip' data-bs-placement='bottom' title=\"]] print(i18n('dropping_flows')) print[[\"></i> "+NtopUtils.formatValue(rsp.dropped_flows, 1)+" Flows Drops</span></a>";
|
||||
}
|
||||
}
|
||||
|
||||
if ((rsp.num_live_captures != undefined) && (rsp.num_live_captures > 0) && (!systemInterfaceEnabled)) {
|
||||
msg += "<a href=']]
|
||||
print(http_prefix)
|
||||
print [[/lua/live_capture_stats.lua'>";
|
||||
msg += "<span class=\"badge bg-primary\" data-bs-toggle='tooltip' data-bs-placement='bottom' title=\"]] print(i18n('live_capture.active_live_captures')) print[[\">";
|
||||
msg += NtopUtils.addCommas(rsp.num_live_captures)+" <i class=\"fas fa-download fa-lg\"></i></span></a>";
|
||||
}
|
||||
|
||||
if (rsp.traffic_recording != undefined && (!systemInterfaceEnabled)) {
|
||||
var status_label="primary";
|
||||
var status_title="]]
|
||||
print(i18n("traffic_recording.recording"))
|
||||
print [[";
|
||||
|
||||
if (rsp.traffic_recording != "recording") {
|
||||
status_label = "danger";
|
||||
status_title = "]]
|
||||
print(i18n("traffic_recording.failure"))
|
||||
print [[";
|
||||
}
|
||||
|
||||
msg += "<a href=']]
|
||||
print(http_prefix)
|
||||
print [[/lua/if_stats.lua?ifid=]]
|
||||
print(tostring(ifid))
|
||||
print [[&page=traffic_recording&tab=status'>";
|
||||
msg += "<span class=\"badge bg-"+status_label+"\" data-bs-toggle='tooltip' data-bs-placement='bottom' title=\""+NtopUtils.addCommas(status_title)+"\">";
|
||||
msg += "<i class=\"fas fa-hdd fa-lg\"></i></span></a>";
|
||||
}
|
||||
|
||||
if (rsp.traffic_extraction != undefined && (!systemInterfaceEnabled)) {
|
||||
var status_title="]]
|
||||
print(i18n("traffic_recording.traffic_extraction_jobs"))
|
||||
print [[";
|
||||
var status_label = "secondary";
|
||||
|
||||
if (rsp.traffic_extraction == "ready") status_label="primary";
|
||||
|
||||
msg += "<a href=']]
|
||||
print(http_prefix)
|
||||
print [[/lua/if_stats.lua?ifid=]]
|
||||
print(tostring(ifid))
|
||||
print [[&page=traffic_recording&tab=jobs'>";
|
||||
msg += "<span class=\"badge bg-"+status_label+"\" data-bs-toggle='tooltip' data-bs-placement='bottom' title=\""+NtopUtils.addCommas(status_title)+"\">";
|
||||
msg += rsp.traffic_extraction_num_tasks+" <i class=\"fas fa-tasks fa-lg\"></i></span></a>";
|
||||
}
|
||||
|
||||
if (rsp.vs_in_progress != undefined && rsp.vs_in_progress > 0 && (!systemInterfaceEnabled)) {
|
||||
msg += "<a href=']]
|
||||
print(http_prefix)
|
||||
print [[/lua/vulnerability_scan.lua'>";
|
||||
msg += "<span class=\"badge bg-primary\" data-bs-toggle='tooltip' data-bs-placement='bottom' title=\"]] print(i18n('vulnerability_scan.vulnerability_scan_in_progress')) print[[\">";
|
||||
msg += NtopUtils.addCommas(rsp.vs_in_progress) +" <i class=\"fas fa-satellite-dish\"></i></span></a>";
|
||||
}
|
||||
|
||||
if(rsp.is_loading == true) {
|
||||
msg += "<blink><span data-bs-toggle='tooltip' data-bs-placement='bottom' title=\"]] print(i18n('loading')) print[[\" class=\"badge bg-primary\"><i class=\"fas fa-spinner\"></i> ]]
|
||||
print(i18n("loading"))
|
||||
print [[</span></blink>";
|
||||
}
|
||||
]]
|
||||
|
||||
if ntop.isOffline() then
|
||||
print [[
|
||||
msg += "<a href=\"#\" style=\"cursor: default\"><span data-bs-toggle='tooltip' data-bs-placement='bottom' title=\"]]
|
||||
print(i18n("offline"))
|
||||
print [[\" class=\"badge bg-secondary\"><i class=\"fas fa-plane\"></i></span></a>";
|
||||
]]
|
||||
end
|
||||
|
||||
print [[
|
||||
msg += '</div></div>';
|
||||
// append the message inside the network-load element
|
||||
const $msg = $(msg);
|
||||
// resize element's font size to fit better
|
||||
if ($msg.width() > $msg.css('max-width')) {
|
||||
$msg.find('span').css('font-size', '0.748rem');
|
||||
}
|
||||
|
||||
$('.network-load').html($msg);
|
||||
|
||||
NtopUtils.reloadBSTooltips();
|
||||
|
||||
} catch(e) {
|
||||
console.warn(e);
|
||||
/* alert("JSON Error (session expired?): logging out"); window.location.replace("]]
|
||||
print(http_prefix)
|
||||
print [[/lua/logout.lua"); */
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
isFooterRefreshInProcess = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$(document).ajaxError(function(err, response, ajaxSettings, thrownError) {
|
||||
if((response.status == 403) && (response.responseText == "Login Required"))
|
||||
window.location.href = "]]
|
||||
print(http_prefix .. "/lua/login.lua")
|
||||
print [[";
|
||||
});
|
||||
|
||||
footerRefresh(); /* call immediately to give the UI a more responsive look */
|
||||
|
||||
setInterval(footerRefresh, 7000); /* re-schedule every [interface-rate] seconds */
|
||||
|
||||
//Automatically open dropdown-menu
|
||||
$(document).ready(function(){
|
||||
$('ul.nav li.dropdown').hover(function() {
|
||||
$(this).find('.dropdown-menu').stop(true, true).delay(150).fadeIn(100);
|
||||
}, function() {
|
||||
$(this).find('.dropdown-menu').stop(true, true).delay(150).fadeOut(100);
|
||||
});
|
||||
$('.collapse')
|
||||
.on('shown.bs.collapse', function(){
|
||||
$(this).parent().find(".fa-caret-down").removeClass("fa-caret-down").addClass("fa-caret-up");
|
||||
})
|
||||
.on('hidden.bs.collapse', function(){
|
||||
$(this).parent().find(".fa-caret-up").removeClass("fa-caret-up").addClass("fa-caret-down");
|
||||
});
|
||||
});
|
||||
|
||||
]]
|
||||
|
||||
-- This code rewrites the current page state after a POST request to avoid Document Expired errors
|
||||
if not table.empty(_POST) then
|
||||
print [[
|
||||
if ((typeof(history) === "object")
|
||||
&& (typeof(history).replaceState === "function")
|
||||
&& (typeof(window.location.href) === "string"))
|
||||
history.replaceState(history.state, "", window.location.href);
|
||||
]]
|
||||
end
|
||||
|
||||
print [[
|
||||
|
||||
// hide the possibly shown alerts icon in the header
|
||||
]]
|
||||
if not _ifstats.isView then
|
||||
print("$('#alerts-li').hide();")
|
||||
else
|
||||
print("$('#alerts-li').show();")
|
||||
end
|
||||
|
||||
print([[
|
||||
</script>
|
||||
]])
|
||||
|
||||
-- ######################################
|
||||
|
||||
if have_nedge then
|
||||
print [[<form id="powerOffForm" method="post">
|
||||
<input name="csrf" value="]]
|
||||
print(random_csrf)
|
||||
print [[" type="hidden" />
|
||||
<input name="poweroff" value="" type="hidden" />
|
||||
</form>
|
||||
<form id="rebootForm" method="post">
|
||||
<input name="csrf" value="]]
|
||||
print(random_csrf)
|
||||
print [[" type="hidden" />
|
||||
<input name="reboot" value="" type="hidden" />
|
||||
</form>]]
|
||||
|
||||
print(template.gen("modal_confirm_dialog.html", {
|
||||
dialog = {
|
||||
id = "poweroff_dialog",
|
||||
action = "$('#powerOffForm').submit()",
|
||||
title = i18n("nedge.power_off"),
|
||||
message = i18n("nedge.power_off_confirm"),
|
||||
confirm = i18n("nedge.power_off")
|
||||
}
|
||||
}))
|
||||
|
||||
print(template.gen("modal_confirm_dialog.html", {
|
||||
dialog = {
|
||||
id = "reboot_dialog",
|
||||
action = "$('#rebootForm').submit()",
|
||||
title = i18n("nedge.reboot"),
|
||||
message = i18n("nedge.reboot_corfirm"),
|
||||
confirm = i18n("nedge.reboot")
|
||||
}
|
||||
}))
|
||||
|
||||
end
|
||||
|
||||
print(template.gen("modal_confirm_dialog.html", {
|
||||
dialog = {
|
||||
id = "ext_link_dialog",
|
||||
title = i18n("external_link"),
|
||||
message = i18n("show_alerts.confirm_external_link"),
|
||||
confirm = i18n("redirect")
|
||||
}
|
||||
}))
|
||||
|
||||
print [[
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function(){
|
||||
$(document).on('click','a.ntopng-external-link',function(event){
|
||||
event.preventDefault();
|
||||
const url=$(this)[0].href;
|
||||
$("#url_ext_link_dialog").html(url+"<br/>]]
|
||||
print(i18n("are_you_sure"))
|
||||
print [[");
|
||||
$("#btn-confirm-action_ext_link_dialog").attr('href',url);
|
||||
$('#ext_link_dialog').modal('show');
|
||||
});
|
||||
});
|
||||
</script>
|
||||
]]
|
||||
|
||||
-- Updates submenu
|
||||
if hasSoftwareUpdatesSupport() then
|
||||
|
||||
-- Updates check
|
||||
print [[
|
||||
<script type='text/javascript'>
|
||||
$('#updates-info-li').html(']]
|
||||
print(i18n("updates.checking"))
|
||||
print [[');
|
||||
$('#updates-install-li').hide();
|
||||
|
||||
const updates_csrf = ']]
|
||||
print(random_csrf)
|
||||
print [[';
|
||||
|
||||
/* Updates status */
|
||||
var updatesStatus = '';
|
||||
var updatesLastCheck = 0;
|
||||
|
||||
/* Install latest update */
|
||||
var installUpdate = function() {
|
||||
if (confirm(']]
|
||||
print(i18n("updates.install_confirm"))
|
||||
if info["pro.license_days_left"] ~= nil and info["pro.license_days_left"] <=
|
||||
0 then
|
||||
-- License is valid, however maintenance is expired: warning the user
|
||||
print(" " .. i18n("updates.maintenance_expired"))
|
||||
end
|
||||
print [[')) {
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: ']]
|
||||
print(http_prefix)
|
||||
print [[/lua/install_update.lua',
|
||||
data: {
|
||||
csrf: updates_csrf
|
||||
},
|
||||
success: function(rsp) {
|
||||
$('#updates-info-li').html(']]
|
||||
print(i18n("updates.installing"))
|
||||
print [[')
|
||||
$('#updates-info-li').attr('title', '');
|
||||
$('#updates-install-li').hide();
|
||||
$('#admin-badge').hide();
|
||||
updatesStatus = 'installing';
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for new updates */
|
||||
var checkForUpdates = function() {
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: ']]
|
||||
print(http_prefix)
|
||||
print [[/lua/check_update.lua',
|
||||
data: {
|
||||
csrf: updates_csrf,
|
||||
search: 'true'
|
||||
},
|
||||
success: function(rsp) {
|
||||
$('#updates-info-li').html(']]
|
||||
print(i18n("updates.checking"))
|
||||
print [[');
|
||||
$('#updates-info-li').attr('title', '');
|
||||
$('#updates-install-li').hide();
|
||||
$('#admin-badge').hide();
|
||||
updatesStatus = 'checking';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* Update the menu with the current updates status */
|
||||
var updatesRefresh = function() {
|
||||
const now = Date.now()/1000;
|
||||
let check_time_sec = 10;
|
||||
|
||||
if (updatesStatus == 'installing' || updatesStatus == 'checking') {
|
||||
/* Go ahead (frequent update) */
|
||||
} else if (updatesStatus == 'update-avail' || updatesStatus == 'upgrade-failure') {
|
||||
return; /* no need to check again */
|
||||
} else { /* updatesStatus == 'not-avail' || updatesStatus == 'update-failure' || updatesStatus == <other errors> || updatesStatus == '' */
|
||||
check_time_sec = 300;
|
||||
}
|
||||
|
||||
if (now < updatesLastCheck + check_time_sec) return; /* check with low freq */
|
||||
updatesLastCheck = now;
|
||||
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url: ']]
|
||||
print(http_prefix)
|
||||
print [[/lua/check_update.lua',
|
||||
data: {},
|
||||
success: function(rsp) {
|
||||
if(rsp && rsp.status) {
|
||||
|
||||
updatesStatus = rsp.status;
|
||||
|
||||
if (rsp.status == 'installing') {
|
||||
$('#updates-info-li').html(']]
|
||||
print(i18n("updates.installing"))
|
||||
print [[')
|
||||
$('#updates-info-li').attr('title', '');
|
||||
$('#updates-install-li').hide();
|
||||
$('#admin-badge').hide();
|
||||
|
||||
} else if (rsp.status == 'checking') {
|
||||
$('#updates-info-li').html(']]
|
||||
print(i18n("updates.checking"))
|
||||
print [[');
|
||||
$('#updates-info-li').attr('title', '');
|
||||
$('#updates-install-li').hide();
|
||||
$('#admin-badge').hide();
|
||||
|
||||
} else if (rsp.status == 'update-avail' || rsp.status == 'upgrade-failure') {
|
||||
|
||||
$('#updates-info-li').html('<span class="badge bg-pill bg-danger">]]
|
||||
print(i18n("updates.available"))
|
||||
print [[</span> ]]
|
||||
print(info["product"])
|
||||
print [[ ' + rsp.version);
|
||||
$('#updates-info-li').attr('title', '');
|
||||
|
||||
var icon = '<i class="fas fa-download"></i>';
|
||||
$('#updates-install-li').attr('title', '');
|
||||
if (rsp.status !== 'update-avail') {
|
||||
icon = '<i class="fas fa-exclamation-triangle text-danger"></i>';
|
||||
$('#updates-install-li').attr('title', "]]
|
||||
print(i18n("updates.update_failure_message"))
|
||||
print [[: " + rsp.status);
|
||||
}
|
||||
$('#updates-install-li').html(icon + " ]]
|
||||
print(i18n("updates.install"))
|
||||
print [[");
|
||||
$('#updates-install-li').show();
|
||||
$('#updates-install-li').off("click");
|
||||
$('#updates-install-li').click(installUpdate);
|
||||
|
||||
if (rsp.status !== 'update-avail') $('#admin-badge').html('!');
|
||||
else $('#admin-badge').html('1');
|
||||
$('#admin-badge').show();
|
||||
|
||||
} else /* (rsp.status == 'not-avail' || rsp.status == 'update-failure' || rsp.status == <other errors>) */ {
|
||||
|
||||
var icon = '';
|
||||
$('#updates-info-li').attr('title', '');
|
||||
if (rsp.status !== 'not-avail') {
|
||||
icon = '<i class="fas fa-exclamation-triangle text-danger"></i> ';
|
||||
$('#updates-info-li').attr('title', "]]
|
||||
print(i18n("updates.update_failure_message"))
|
||||
print [[: " + rsp.status);
|
||||
}
|
||||
$('#updates-info-li').html(icon + ']]
|
||||
print(i18n("updates.no_updates"))
|
||||
print [[');
|
||||
|
||||
$('#updates-install-li').html("<i class='fas fa-sync'></i> ]]
|
||||
print(i18n("updates.check"))
|
||||
print [[");
|
||||
$('#updates-install-li').show();
|
||||
$('#updates-install-li').off("click");
|
||||
$('#updates-install-li').click(checkForUpdates);
|
||||
|
||||
$('#admin-badge').hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
setInterval(updatesRefresh, 1000);
|
||||
</script>
|
||||
]]
|
||||
end
|
||||
|
||||
-- close wrapper
|
||||
print [[
|
||||
</main>
|
||||
</div>
|
||||
</body>
|
||||
</html> ]]
|
||||
1431
attic/scripts/lua/inc/menu.lua
Normal file
1431
attic/scripts/lua/inc/menu.lua
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +1,6 @@
|
|||
#n-sidebar {
|
||||
position: fixed;
|
||||
width: var(--sidebar-width);
|
||||
width: var(--sb-rail-w);
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
import "./chart_colors";
|
||||
// chart_colors (legacy footer injector) removed — footer now handled by app-shell.vue
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
:root {
|
||||
font-weight: 500;
|
||||
--sidebar-width: 4.5rem;
|
||||
--sidebar-width: 0px; /* AppShell Vue sidebar: overridden by --sb-rail-w */
|
||||
--footer-height: 4rem;
|
||||
--padding-md-four: 1.5rem;
|
||||
--scrollable-dropdown-height: 20rem;
|
||||
|
|
|
|||
316
http_src/vue/app-footer.vue
Normal file
316
http_src/vue/app-footer.vue
Normal file
|
|
@ -0,0 +1,316 @@
|
|||
<!--
|
||||
(C) 2013-26 - ntop.org
|
||||
AppFooter — orchestration component.
|
||||
Handles: software updates polling, ext_link_dialog, nEdge power/reboot modals,
|
||||
ajaxError -> login redirect, history.replaceState on POST.
|
||||
No visible UI of its own except modals.
|
||||
-->
|
||||
<template>
|
||||
<!-- External link confirmation modal -->
|
||||
<div class="modal fade" id="ext_link_dialog" tabindex="-1">
|
||||
<div class="modal-dialog modal-sm">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">{{ _i18n("external_link") }}</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<span id="url_ext_link_dialog"></span><br/>{{ _i18n("are_you_sure") }}
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-secondary btn-sm" data-bs-dismiss="modal">{{ _i18n("cancel") }}</button>
|
||||
<a id="btn-confirm-action_ext_link_dialog" class="btn btn-primary btn-sm"
|
||||
href="#" target="_blank" rel="noopener" data-bs-dismiss="modal">
|
||||
{{ _i18n("redirect") }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- nEdge poweroff/reboot modals -->
|
||||
<template v-if="ctx.is_nedge && ctx.is_admin">
|
||||
<form id="powerOffForm" method="post">
|
||||
<input name="csrf" :value="ctx.csrf" type="hidden" />
|
||||
<input name="poweroff" value="" type="hidden" />
|
||||
</form>
|
||||
<form id="rebootForm" method="post">
|
||||
<input name="csrf" :value="ctx.csrf" type="hidden" />
|
||||
<input name="reboot" value="" type="hidden" />
|
||||
</form>
|
||||
|
||||
<div class="modal fade" id="poweroff_dialog" tabindex="-1">
|
||||
<div class="modal-dialog modal-sm">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">{{ _i18n("nedge.power_off") }}</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">{{ _i18n("nedge.power_off_confirm") }}</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-secondary btn-sm" data-bs-dismiss="modal">{{ _i18n("cancel") }}</button>
|
||||
<button class="btn btn-danger btn-sm" @click="submitForm('powerOffForm')">
|
||||
{{ _i18n("nedge.power_off") }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="reboot_dialog" tabindex="-1">
|
||||
<div class="modal-dialog modal-sm">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">{{ _i18n("nedge.reboot") }}</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">{{ _i18n("nedge.reboot_corfirm") }}</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-secondary btn-sm" data-bs-dismiss="modal">{{ _i18n("cancel") }}</button>
|
||||
<button class="btn btn-primary btn-sm" @click="submitForm('rebootForm')">
|
||||
{{ _i18n("nedge.reboot") }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, onMounted, onBeforeUnmount } from "vue";
|
||||
import { ntopng_utility } from "../services/context/ntopng_globals_services.js";
|
||||
|
||||
const props = defineProps({ context: Object });
|
||||
const ctx = computed(() => props.context || {});
|
||||
|
||||
function _i18n(key) { return i18n(key) || key; }
|
||||
|
||||
// Updates
|
||||
const UPDATES_POLL_SLOW = 300; // seconds — when idle
|
||||
const UPDATES_POLL_FAST = 10; // seconds — when checking/installing
|
||||
|
||||
let updatesStatus = "";
|
||||
let updatesLastCheck = 0;
|
||||
let updatesTimer = null;
|
||||
|
||||
async function updatesRefresh() {
|
||||
if (!ctx.value.has_updates_support) return;
|
||||
|
||||
const now = Date.now() / 1000;
|
||||
const checkInterval = (updatesStatus === "installing" || updatesStatus === "checking")
|
||||
? UPDATES_POLL_FAST : UPDATES_POLL_SLOW;
|
||||
|
||||
if (updatesStatus === "update-avail" || updatesStatus === "upgrade-failure") return;
|
||||
if (now < updatesLastCheck + checkInterval) return;
|
||||
updatesLastCheck = now;
|
||||
|
||||
try {
|
||||
const data = await ntopng_utility.http_request(
|
||||
`${http_prefix}/lua/check_update.lua`
|
||||
);
|
||||
if (!data || !data.status) return;
|
||||
updatesStatus = data.status;
|
||||
applyUpdatesStatus(data);
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
function applyUpdatesStatus(data) {
|
||||
const infoEl = document.getElementById("updates-info-li");
|
||||
const installEl = document.getElementById("updates-install-li");
|
||||
const badgeEl = document.getElementById("admin-badge");
|
||||
|
||||
if (!infoEl) return;
|
||||
|
||||
if (data.status === "installing") {
|
||||
infoEl.textContent = _i18n("updates.installing");
|
||||
installEl?.style && (installEl.style.display = "none");
|
||||
badgeEl?.style && (badgeEl.style.display = "none");
|
||||
|
||||
} else if (data.status === "checking") {
|
||||
infoEl.textContent = _i18n("updates.checking");
|
||||
installEl?.style && (installEl.style.display = "none");
|
||||
badgeEl?.style && (badgeEl.style.display = "none");
|
||||
|
||||
} else if (data.status === "update-avail" || data.status === "upgrade-failure") {
|
||||
infoEl.innerHTML = `<span class="badge bg-danger">${_i18n("updates.available")}</span> ${data.version || ""}`;
|
||||
|
||||
if (installEl) {
|
||||
installEl.style.display = "";
|
||||
const icon = data.status === "update-avail"
|
||||
? '<i class="fas fa-download me-1"></i>'
|
||||
: '<i class="fas fa-exclamation-triangle text-danger me-1"></i>';
|
||||
installEl.innerHTML = `<a class="dropdown-item" href="#">${icon}${_i18n("updates.install")}</a>`;
|
||||
installEl.querySelector("a")?.addEventListener("click", e => {
|
||||
e.preventDefault();
|
||||
doInstallUpdate();
|
||||
});
|
||||
}
|
||||
|
||||
if (badgeEl) badgeEl.style.display = "";
|
||||
|
||||
// Show in major-release alert bar
|
||||
const alertEl = document.getElementById("major-release-alert");
|
||||
const textEl = document.getElementById("ntopng_update_available");
|
||||
if (alertEl && textEl) {
|
||||
textEl.textContent = `${_i18n("updates.available")}: ${data.version || ""}`;
|
||||
alertEl.style.display = "";
|
||||
}
|
||||
|
||||
} else {
|
||||
infoEl.textContent = _i18n("updates.no_updates") + ".";
|
||||
installEl?.style && (installEl.style.display = "none");
|
||||
badgeEl?.style && (badgeEl.style.display = "none");
|
||||
}
|
||||
}
|
||||
|
||||
async function doInstallUpdate() {
|
||||
let msg = _i18n("updates.install_confirm");
|
||||
if (!confirm(msg)) return;
|
||||
|
||||
try {
|
||||
await ntopng_utility.http_request(
|
||||
`${http_prefix}/lua/install_update.lua`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
||||
body: new URLSearchParams({ csrf: ctx.value.csrf || window.__CSRF_DATATABLE__ }),
|
||||
}
|
||||
);
|
||||
const infoEl = document.getElementById("updates-info-li");
|
||||
const installEl = document.getElementById("updates-install-li");
|
||||
const badgeEl = document.getElementById("admin-badge");
|
||||
if (infoEl) infoEl.textContent = _i18n("updates.installing");
|
||||
installEl?.style && (installEl.style.display = "none");
|
||||
badgeEl?.style && (badgeEl.style.display = "none");
|
||||
updatesStatus = "installing";
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
function startUpdatesCheck() {
|
||||
const infoEl = document.getElementById("updates-info-li");
|
||||
const installEl = document.getElementById("updates-install-li");
|
||||
if (infoEl) infoEl.textContent = _i18n("updates.checking");
|
||||
if (installEl) installEl.style.display = "none";
|
||||
|
||||
doManualCheck();
|
||||
}
|
||||
|
||||
async function doManualCheck() {
|
||||
try {
|
||||
await ntopng_utility.http_request(
|
||||
`${http_prefix}/lua/check_update.lua`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
||||
body: new URLSearchParams({
|
||||
csrf: ctx.value.csrf || window.__CSRF_DATATABLE__,
|
||||
search: "true",
|
||||
}),
|
||||
}
|
||||
);
|
||||
updatesStatus = "checking";
|
||||
updatesLastCheck = 0; // force a refresh on next tick
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
// ext_link_dialog — intercept .ntopng-external-link clicks
|
||||
function onExternalLinkClick(e) {
|
||||
const anchor = e.target.closest("a.ntopng-external-link");
|
||||
if (!anchor) return;
|
||||
e.preventDefault();
|
||||
|
||||
const url = anchor.href;
|
||||
const el = document.getElementById("url_ext_link_dialog");
|
||||
const btn = document.getElementById("btn-confirm-action_ext_link_dialog");
|
||||
if (el) el.textContent = url;
|
||||
if (btn) btn.href = url;
|
||||
|
||||
const modalEl = document.getElementById("ext_link_dialog");
|
||||
if (modalEl && window.bootstrap) {
|
||||
bootstrap.Modal.getOrCreateInstance(modalEl).show();
|
||||
}
|
||||
}
|
||||
|
||||
// Toast dismiss, from ToastUtils
|
||||
function onToastDismiss(e) {
|
||||
const btn = e.target.closest(".notification button.dismiss");
|
||||
if (!btn) return;
|
||||
const toast = btn.closest(".notification");
|
||||
if (!toast) return;
|
||||
const id = toast.dataset.toastId;
|
||||
if (typeof ToastUtils !== "undefined" && id) {
|
||||
ToastUtils.dismissToast(id, ctx.value.csrf || window.__CSRF_DATATABLE__, data => {
|
||||
if (data?.success) {
|
||||
const bsToast = bootstrap.Toast.getInstance(toast);
|
||||
bsToast?.hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// 403 ajaxError -> redirect to login
|
||||
function onAjaxError(_evt, xhr) {
|
||||
if (xhr?.status === 403 && xhr?.responseText === "Login Required") {
|
||||
window.location.href = `${http_prefix}/lua/login.lua`;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// nEdge form submit helper
|
||||
function submitForm(id) {
|
||||
document.getElementById(id)?.submit();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// history.replaceState (avoid Document Expired on POST pages)
|
||||
function fixHistoryState() {
|
||||
if (history?.replaceState && window.location.href) {
|
||||
history.replaceState(history.state, "", window.location.href);
|
||||
}
|
||||
}
|
||||
|
||||
function wireUpdatesInstallButton() {
|
||||
const installEl = document.getElementById("updates-install-li");
|
||||
if (installEl) {
|
||||
installEl.addEventListener("click", e => {
|
||||
e.preventDefault();
|
||||
startUpdatesCheck();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
document.addEventListener("click", onExternalLinkClick);
|
||||
document.addEventListener("click", onToastDismiss);
|
||||
document.addEventListener("ajaxError", onAjaxError);
|
||||
|
||||
// jQuery ajaxError fallback
|
||||
if (window.$) {
|
||||
$(document).ajaxError((err, response) => {
|
||||
if (response?.status === 403 && response?.responseText === "Login Required") {
|
||||
window.location.href = `${http_prefix}/lua/login.lua`;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fixHistoryState();
|
||||
wireUpdatesInstallButton();
|
||||
|
||||
if (ctx.value.has_updates_support) {
|
||||
// initial check
|
||||
updatesLastCheck = 0;
|
||||
await updatesRefresh();
|
||||
// poll every 10 seconds; the function internally throttles to slow/fast intervals
|
||||
updatesTimer = setInterval(updatesRefresh, UPDATES_POLL_FAST * 1000);
|
||||
}
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
document.removeEventListener("click", onExternalLinkClick);
|
||||
document.removeEventListener("click", onToastDismiss);
|
||||
document.removeEventListener("ajaxError", onAjaxError);
|
||||
if (updatesTimer) clearInterval(updatesTimer);
|
||||
});
|
||||
</script>
|
||||
1967
http_src/vue/app-shell.vue
Normal file
1967
http_src/vue/app-shell.vue
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -3,30 +3,32 @@
|
|||
-->
|
||||
|
||||
<template>
|
||||
<!-- Search container (expandable input + button + spinner) -->
|
||||
<div ref="searchContainer" :class="[
|
||||
'ms-auto expandable-search align-items-center position-relative d-flex',
|
||||
{ expanded: expanded }
|
||||
]">
|
||||
<!-- Search wrapper: position:relative so dropdown is anchored here -->
|
||||
<div class="search-box-wrapper" @mouseenter="onSearchEnter" @mouseleave="onSearchLeave">
|
||||
<!-- Search container (expandable input + button + spinner) -->
|
||||
<div ref="searchContainer" :class="[
|
||||
'expandable-search align-items-center position-relative d-flex',
|
||||
{ expanded: expanded }
|
||||
]">
|
||||
|
||||
<!-- Search input -->
|
||||
<input name="search" type="text" ref="searchInput" class="form-control rounded-pill ps-4-5" autocomplete="off"
|
||||
autocorrect="off" :placeholder="_i18n('search')">
|
||||
<!-- Search input -->
|
||||
<input name="search" type="text" ref="searchInput" class="form-control rounded-pill ps-4-5" autocomplete="off"
|
||||
autocorrect="off" :placeholder="_i18n('search')">
|
||||
|
||||
<!-- Loading spinner shown during async search -->
|
||||
<Spinner :show="loading" size="1rem" class="spinner-inside">
|
||||
</Spinner>
|
||||
<!-- Loading spinner shown during async search -->
|
||||
<Spinner :show="loading" size="1rem" class="spinner-inside">
|
||||
</Spinner>
|
||||
|
||||
<!-- Search icon button -->
|
||||
<button class="btn btn-link search-btn" @click="expanded = true">
|
||||
<!-- Search icon button -->
|
||||
<button class="btn btn-link search-btn">
|
||||
<i class="fa-solid fa-magnifying-glass"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<i class="fa-solid fa-magnifying-glass"></i>
|
||||
</button>
|
||||
<!-- Autocomplete dropdown list -->
|
||||
<ul ref="searchList" class="autocomplete-dropdown dropdown-menu dropdown-menu-right d-none" role="listbox">
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- Autocomplete dropdown list -->
|
||||
<ul ref="searchList" class="autocomplete-dropdown dropdown-menu dropdown-menu-right d-none" role="listbox">
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
|
@ -46,6 +48,7 @@ const props = defineProps({
|
|||
|
||||
|
||||
const expanded = ref(false);
|
||||
let searchLeaveTimer = null;
|
||||
|
||||
/* ======================================================
|
||||
* Reactive state & constants
|
||||
|
|
@ -336,6 +339,20 @@ const handleKeys = function (e) {
|
|||
* Lifecycle
|
||||
* ====================================================== */
|
||||
|
||||
function onSearchEnter() {
|
||||
clearTimeout(searchLeaveTimer);
|
||||
expanded.value = true;
|
||||
}
|
||||
|
||||
function onSearchLeave() {
|
||||
searchLeaveTimer = setTimeout(() => {
|
||||
if (!searchInput.value?.value) {
|
||||
expanded.value = false;
|
||||
}
|
||||
searchList.value?.classList.add("d-none");
|
||||
}, 250);
|
||||
}
|
||||
|
||||
const outsideClickHandler = function (e) {
|
||||
const isOutside =
|
||||
!searchContainer.value?.contains(e.target) &&
|
||||
|
|
@ -365,6 +382,12 @@ onBeforeUnmount(() => {
|
|||
});
|
||||
</script>
|
||||
<style>
|
||||
.search-box-wrapper {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.ps-4-5 {
|
||||
padding-left: 2rem !important;
|
||||
}
|
||||
|
|
@ -378,22 +401,29 @@ onBeforeUnmount(() => {
|
|||
|
||||
.autocomplete-dropdown {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
top: calc(100% + 4px);
|
||||
right: 0;
|
||||
display: inline-block;
|
||||
width: auto;
|
||||
min-width: 100%;
|
||||
min-width: 240px;
|
||||
max-width: min(400px, 40vw);
|
||||
white-space: nowrap;
|
||||
z-index: 10;
|
||||
z-index: 1060;
|
||||
max-height: 60vh;
|
||||
scrollbar-gutter: stable;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.autocomplete-dropdown .dropdown-item {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.expandable-search {
|
||||
width: 40px;
|
||||
/* collapsed */
|
||||
transition: width 0.3s ease;
|
||||
width: 36px;
|
||||
transition: width 0.25s ease;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
|
|
@ -408,14 +438,14 @@ onBeforeUnmount(() => {
|
|||
|
||||
.expandable-search .search-btn {
|
||||
position: absolute;
|
||||
right: 8px;
|
||||
right: 0;
|
||||
color: var(--icon-color);
|
||||
z-index: 2;
|
||||
padding: 0.375rem 0.5rem;
|
||||
}
|
||||
|
||||
.expandable-search.expanded {
|
||||
width: 250px;
|
||||
/* expanded */
|
||||
width: 220px;
|
||||
}
|
||||
|
||||
.expandable-search.expanded input {
|
||||
|
|
|
|||
|
|
@ -195,16 +195,23 @@ import { default as MultiPieChart } from "./charts/multi-pie-chart.vue";
|
|||
import { default as PieChart } from "./charts/pie-chart.vue";
|
||||
import { default as LineChart } from "./charts/line-chart.vue";
|
||||
import { default as PeityChart } from "./charts/peity.vue";
|
||||
|
||||
import { default as Chatbot } from "./chatbot.vue";
|
||||
import { default as PageChatbot } from "./page-chatbot.vue";
|
||||
import { default as FlowChatbotSidebar } from "./flow-chatbot-sidebar.vue";
|
||||
|
||||
// app shell
|
||||
import { default as AppShell } from "./app-shell.vue";
|
||||
import { default as AppFooter } from "./app-footer.vue";
|
||||
|
||||
let ntopVue = {
|
||||
Chatbot: Chatbot,
|
||||
PageChatbot: PageChatbot,
|
||||
FlowChatbotSidebar: FlowChatbotSidebar,
|
||||
|
||||
// app shell
|
||||
AppShell: AppShell,
|
||||
AppFooter: AppFooter,
|
||||
|
||||
// graphs
|
||||
MultiPieChart: MultiPieChart,
|
||||
PieChart: PieChart,
|
||||
|
|
@ -405,5 +412,6 @@ let ntopVue = {
|
|||
ModalSNMPInterfacesAutoRole: ModalSNMPInterfacesAutoRole,
|
||||
|
||||
Vue: Vue,
|
||||
createApp: (options) => Vue.createApp(options).use(window.vuetify),
|
||||
};
|
||||
window.ntopVue = ntopVue;
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 97c7f17dc15382297b0aacd85c7dbeaf42dad37f
|
||||
Subproject commit cbe5b89116c197109b1a797dc194e7509e32c0e4
|
||||
774
httpdocs/misc/menu_definition.json
Normal file
774
httpdocs/misc/menu_definition.json
Normal file
|
|
@ -0,0 +1,774 @@
|
|||
{
|
||||
"sections": [
|
||||
{
|
||||
"key": "dashboard",
|
||||
"i18n": "index_page.dashboard",
|
||||
"icon": "fas fa-tachometer-alt",
|
||||
"entries": [
|
||||
{
|
||||
"key": "traffic_dashboard",
|
||||
"i18n": "dashboard.traffic_dashboard",
|
||||
"icon": "fas fa-chart-area",
|
||||
"url": "/lua/index.lua"
|
||||
},
|
||||
{
|
||||
"key": "assets_dashboard",
|
||||
"i18n": "assets",
|
||||
"icon": "fas fa-boxes",
|
||||
"url": "/lua/pro/assets_dashboard.lua"
|
||||
},
|
||||
{
|
||||
"key": "gateways_users",
|
||||
"i18n": "dashboard.gateways_users",
|
||||
"icon": "fas fa-users",
|
||||
"url": "/lua/pro/nedge/dashboard.lua"
|
||||
},
|
||||
{
|
||||
"key": "traffic_report",
|
||||
"i18n": "report.traffic_report",
|
||||
"icon": "fas fa-file-alt",
|
||||
"url": "/lua/pro/report.lua"
|
||||
},
|
||||
{
|
||||
"key": "hr_chart",
|
||||
"i18n": "hr_chart.title",
|
||||
"icon": "fas fa-clock",
|
||||
"url": "/lua/pro/hr_chart.lua"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "monitoring",
|
||||
"i18n": "monitoring",
|
||||
"icon": "fas fa-eye",
|
||||
"entries": [
|
||||
{
|
||||
"key": "active_monitoring",
|
||||
"i18n": "active_monitoring_stats.active_monitoring",
|
||||
"icon": "fas fa-heartbeat",
|
||||
"url": "/lua/active_monitoring.lua"
|
||||
},
|
||||
{
|
||||
"key": "network_discovery",
|
||||
"i18n": "discover.network_discovery",
|
||||
"icon": "fas fa-search",
|
||||
"url": "/lua/discover.lua"
|
||||
},
|
||||
{
|
||||
"key": "infrastructure_dashboard",
|
||||
"i18n": "infrastructure_dashboard.infrastructure_dashboard",
|
||||
"icon": "fas fa-project-diagram",
|
||||
"url": "/lua/pro/enterprise/infrastructure_config.lua"
|
||||
},
|
||||
{
|
||||
"key": "snmp_monitoring",
|
||||
"i18n": "prefs.snmp",
|
||||
"icon": "fas fa-network-wired",
|
||||
"url": "/lua/pro/enterprise/snmpdevices_stats.lua"
|
||||
},
|
||||
{
|
||||
"key": "vulnerability_scan",
|
||||
"i18n": "scan_hosts",
|
||||
"icon": "fas fa-shield-alt",
|
||||
"url": "/lua/vulnerability_scan.lua"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "alerts",
|
||||
"i18n": "details.alerts",
|
||||
"icon": "fas fa-exclamation-triangle",
|
||||
"entries": [
|
||||
{
|
||||
"key": "alerts_list",
|
||||
"i18n": "details.alerts_list",
|
||||
"icon": "fas fa-list",
|
||||
"url": "/lua/alert_stats.lua"
|
||||
},
|
||||
{
|
||||
"key": "alerts_graph",
|
||||
"i18n": "details.alerts_graph",
|
||||
"icon": "fas fa-chart-bar",
|
||||
"url": "/lua/pro/alerts_graph.lua"
|
||||
},
|
||||
{
|
||||
"key": "alerts_geomap",
|
||||
"i18n": "details.alerts_geomap",
|
||||
"icon": "fas fa-map-marked-alt",
|
||||
"url": "/lua/pro/alerts_geomap.lua"
|
||||
},
|
||||
{
|
||||
"key": "alerts_analysis",
|
||||
"i18n": "details.alerts_analysis",
|
||||
"icon": "fas fa-microscope",
|
||||
"url": "/lua/pro/enterprise/alerts_analysis.lua"
|
||||
},
|
||||
{
|
||||
"key": "divider",
|
||||
"i18n": "menu_group.notifications"
|
||||
},
|
||||
{
|
||||
"key": "notifications",
|
||||
"i18n": "endpoint_notifications.notifications",
|
||||
"icon": "fas fa-bell",
|
||||
"url": "/lua/admin/endpoint_notifications_list.lua"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "flows",
|
||||
"i18n": "flows",
|
||||
"icon": "fas fa-stream",
|
||||
"entries": [
|
||||
{
|
||||
"key": "active_flows",
|
||||
"i18n": "active_flows",
|
||||
"icon": "fas fa-water",
|
||||
"url": "/lua/flows_stats.lua"
|
||||
},
|
||||
{
|
||||
"key": "db_explorer",
|
||||
"i18n": "historical_flows",
|
||||
"icon": "fas fa-history",
|
||||
"url": "/lua/pro/db_search.lua"
|
||||
},
|
||||
{
|
||||
"key": "server_ports",
|
||||
"i18n": "server_ports.server_ports",
|
||||
"icon": "fas fa-plug",
|
||||
"url": "/lua/server_ports.lua"
|
||||
},
|
||||
{
|
||||
"key": "divider",
|
||||
"i18n": "menu_group.routing"
|
||||
},
|
||||
{
|
||||
"key": "bgp_looking_glass",
|
||||
"i18n": "bgp_looking_glass",
|
||||
"icon": "fas fa-route",
|
||||
"url": "/lua/bgp_looking_glass.lua"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "nanalyst",
|
||||
"i18n": "nanalyst",
|
||||
"icon": "fas fa-robot",
|
||||
"entries": [
|
||||
{
|
||||
"key": "nanalyst",
|
||||
"i18n": "nanalyst",
|
||||
"icon": "fas fa-brain",
|
||||
"url": "/lua/pro/nanalyst.lua"
|
||||
},
|
||||
{
|
||||
"key": "ai_policy",
|
||||
"i18n": "ai_policy",
|
||||
"icon": "fas fa-file-contract",
|
||||
"url": "/lua/pro/ai_policy.lua"
|
||||
},
|
||||
{
|
||||
"key": "analyst_pipeline",
|
||||
"i18n": "analyst_pipeline",
|
||||
"icon": "fas fa-sitemap",
|
||||
"url": "/lua/pro/analyst_pipeline.lua"
|
||||
},
|
||||
{
|
||||
"key": "divider",
|
||||
"i18n": "menu_group.stats"
|
||||
},
|
||||
{
|
||||
"key": "ai_usage_stats",
|
||||
"i18n": "ai_usage_stats",
|
||||
"icon": "fas fa-chart-pie",
|
||||
"url": "/lua/pro/ai_stats.lua"
|
||||
},
|
||||
{
|
||||
"key": "ai_audit",
|
||||
"i18n": "ai_audit",
|
||||
"icon": "fas fa-clipboard-list",
|
||||
"url": "/lua/pro/ai_audit.lua"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "views",
|
||||
"i18n": "views",
|
||||
"icon": "fas fa-bars",
|
||||
"entries": [
|
||||
{
|
||||
"key": "nedge_flows",
|
||||
"i18n": "flows",
|
||||
"icon": "fas fa-stream",
|
||||
"url": "/lua/flows_stats.lua"
|
||||
},
|
||||
{
|
||||
"key": "nedge_hosts",
|
||||
"i18n": "hosts",
|
||||
"icon": "fas fa-laptop",
|
||||
"url": "/lua/hosts_stats.lua"
|
||||
},
|
||||
{
|
||||
"key": "nedge_devices",
|
||||
"i18n": "mac_stats.devices",
|
||||
"icon": "fas fa-hdd",
|
||||
"url": "/lua/macs_stats.lua?devices_mode=source_macs_only"
|
||||
},
|
||||
{
|
||||
"key": "nedge_db_explorer",
|
||||
"i18n": "historical_flows",
|
||||
"icon": "fas fa-history",
|
||||
"url": "/lua/pro/db_search.lua"
|
||||
},
|
||||
{
|
||||
"key": "nedge_users",
|
||||
"i18n": "users",
|
||||
"icon": "fas fa-users",
|
||||
"url": "/lua/pool_stats.lua"
|
||||
},
|
||||
{
|
||||
"key": "nedge_vlans",
|
||||
"i18n": "vlan_stats.vlan_list",
|
||||
"icon": "fas fa-network-wired",
|
||||
"url": "/lua/vlan_stats.lua"
|
||||
},
|
||||
{
|
||||
"key": "nedge_geo_map",
|
||||
"i18n": "geo_map",
|
||||
"icon": "fas fa-map",
|
||||
"url": "/lua/hosts_geomap.lua"
|
||||
},
|
||||
{
|
||||
"key": "divider",
|
||||
"i18n": "menu_group.asn_mode"
|
||||
},
|
||||
{
|
||||
"key": "hosts_asn_mode",
|
||||
"i18n": "hosts",
|
||||
"icon": "fas fa-laptop",
|
||||
"url": "/lua/hosts_stats.lua"
|
||||
},
|
||||
{
|
||||
"key": "active_flows_asn_mode",
|
||||
"i18n": "active_flows",
|
||||
"icon": "fas fa-water",
|
||||
"url": "/lua/flows_stats.lua"
|
||||
},
|
||||
{
|
||||
"key": "db_explorer_asn_mode",
|
||||
"i18n": "historical_flows",
|
||||
"icon": "fas fa-history",
|
||||
"url": "/lua/pro/db_search.lua"
|
||||
},
|
||||
{
|
||||
"key": "server_ports_asn_mode",
|
||||
"i18n": "server_ports.server_ports",
|
||||
"icon": "fas fa-plug",
|
||||
"url": "/lua/server_ports.lua"
|
||||
},
|
||||
{
|
||||
"key": "divider",
|
||||
"i18n": "menu_group.routing"
|
||||
},
|
||||
{
|
||||
"key": "bgp_looking_glass_asn",
|
||||
"i18n": "bgp_looking_glass",
|
||||
"icon": "fas fa-route",
|
||||
"url": "/lua/bgp_looking_glass.lua"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "hosts",
|
||||
"i18n": "hosts",
|
||||
"icon": "fas fa-laptop",
|
||||
"entries": [
|
||||
{
|
||||
"key": "hosts",
|
||||
"i18n": "hosts",
|
||||
"icon": "fas fa-laptop",
|
||||
"url": "/lua/hosts_stats.lua"
|
||||
},
|
||||
{
|
||||
"key": "devices",
|
||||
"i18n": "layer_2",
|
||||
"icon": "fas fa-hdd",
|
||||
"url": "/lua/macs_stats.lua"
|
||||
},
|
||||
{
|
||||
"key": "divider",
|
||||
"i18n": "menu_group.inventory"
|
||||
},
|
||||
{
|
||||
"key": "assets",
|
||||
"i18n": "assets",
|
||||
"icon": "fas fa-boxes",
|
||||
"url": "/lua/pro/assets.lua"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "collection",
|
||||
"i18n": "flow_devices.exporters",
|
||||
"icon": "fas fa-sitemap",
|
||||
"entries": [
|
||||
{
|
||||
"key": "sflow_exporters",
|
||||
"i18n": "flows_page.sflow_devices",
|
||||
"icon": "fas fa-server",
|
||||
"url": "/lua/pro/enterprise/sflowdevices_stats.lua"
|
||||
},
|
||||
{
|
||||
"key": "nprobe",
|
||||
"i18n": "flow_devices.nprobe_instances",
|
||||
"icon": "fas fa-satellite-dish",
|
||||
"url": "/lua/pro/enterprise/nprobe.lua"
|
||||
},
|
||||
{
|
||||
"key": "exporters_interfaces_stats",
|
||||
"i18n": "flow_devices.exporters_interfaces_stats",
|
||||
"icon": "fas fa-chart-line",
|
||||
"url": "/lua/pro/exporters_interfaces_stats.lua"
|
||||
},
|
||||
{
|
||||
"key": "observation_points",
|
||||
"i18n": "flow_devices.observation_points",
|
||||
"icon": "fas fa-eye",
|
||||
"url": "/lua/pro/enterprise/observation_points.lua"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "maps",
|
||||
"i18n": "maps",
|
||||
"icon": "fas fa-map",
|
||||
"entries": [
|
||||
{
|
||||
"key": "analysis_map",
|
||||
"i18n": "analysis",
|
||||
"icon": "fas fa-project-diagram",
|
||||
"url": "/lua/pro/enterprise/network_maps.lua?map=service_map"
|
||||
},
|
||||
{
|
||||
"key": "geo_map",
|
||||
"i18n": "geo_map.geo_map",
|
||||
"icon": "fas fa-globe",
|
||||
"url": "/lua/hosts_geomap.lua"
|
||||
},
|
||||
{
|
||||
"key": "hosts_map",
|
||||
"i18n": "flows_page.hosts",
|
||||
"icon": "fas fa-map-marked-alt",
|
||||
"url": "/lua/pro/enterprise/hosts_map.lua"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "if_stats",
|
||||
"i18n": "interface",
|
||||
"icon": "fas fa-ethernet",
|
||||
"entries": [
|
||||
{
|
||||
"key": "interface",
|
||||
"i18n": "interface_details",
|
||||
"icon": "fas fa-info-circle",
|
||||
"url": "/lua/if_stats.lua"
|
||||
},
|
||||
{
|
||||
"key": "divider",
|
||||
"i18n": "menu_group.segments"
|
||||
},
|
||||
{
|
||||
"key": "networks",
|
||||
"i18n": "networks",
|
||||
"icon": "fas fa-network-wired",
|
||||
"url": "/lua/network_stats.lua"
|
||||
},
|
||||
{
|
||||
"key": "host_pools",
|
||||
"i18n": "host_pools.host_pools",
|
||||
"icon": "fas fa-layer-group",
|
||||
"url": "/lua/pool_stats.lua"
|
||||
},
|
||||
{
|
||||
"key": "autonomous_systems",
|
||||
"i18n": "as_stats.autonomous_systems",
|
||||
"icon": "fas fa-globe",
|
||||
"url": "/lua/as_stats.lua"
|
||||
},
|
||||
{
|
||||
"key": "countries",
|
||||
"i18n": "countries",
|
||||
"icon": "fas fa-flag",
|
||||
"url": "/lua/country_stats.lua"
|
||||
},
|
||||
{
|
||||
"key": "vlans",
|
||||
"i18n": "vlan_stats.vlans",
|
||||
"icon": "fas fa-tags",
|
||||
"url": "/lua/vlan_stats.lua"
|
||||
},
|
||||
{
|
||||
"key": "divider",
|
||||
"i18n": "menu_group.containers"
|
||||
},
|
||||
{
|
||||
"key": "pods",
|
||||
"i18n": "pods",
|
||||
"icon": "fab fa-docker",
|
||||
"url": "/lua/pods_stats.lua"
|
||||
},
|
||||
{
|
||||
"key": "containers",
|
||||
"i18n": "containers",
|
||||
"icon": "fas fa-cube",
|
||||
"url": "/lua/containers_stats.lua"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "health",
|
||||
"i18n": "health",
|
||||
"icon": "fas fa-heartbeat",
|
||||
"entries": [
|
||||
{
|
||||
"key": "system_status",
|
||||
"i18n": "system_status",
|
||||
"icon": "fas fa-server",
|
||||
"url": "/lua/system_stats.lua"
|
||||
},
|
||||
{
|
||||
"key": "interfaces_status",
|
||||
"i18n": "system_interfaces_status",
|
||||
"icon": "fas fa-ethernet",
|
||||
"url": "/lua/system_interfaces_stats.lua"
|
||||
},
|
||||
{
|
||||
"key": "divider",
|
||||
"i18n": "menu_group.storage"
|
||||
},
|
||||
{
|
||||
"key": "influxdb_status",
|
||||
"i18n": "InfluxDB",
|
||||
"icon": "fas fa-database",
|
||||
"url": "/lua/monitor/influxdb_monitor.lua"
|
||||
},
|
||||
{
|
||||
"key": "redis_status",
|
||||
"i18n": "Redis",
|
||||
"icon": "fas fa-memory",
|
||||
"url": "/lua/monitor/redis_monitor.lua"
|
||||
},
|
||||
{
|
||||
"key": "clickhouse_status",
|
||||
"i18n": "ClickHouse",
|
||||
"icon": "fas fa-table",
|
||||
"url": "/lua/pro/enterprise/monitor/clickhouse_monitor.lua"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "pollers",
|
||||
"i18n": "pollers",
|
||||
"icon": "fas fa-satellite-dish",
|
||||
"entries": [
|
||||
{
|
||||
"key": "assets_snmp",
|
||||
"i18n": "assets_snmp",
|
||||
"icon": "fas fa-boxes",
|
||||
"url": "/lua/pro/assets.lua"
|
||||
},
|
||||
{
|
||||
"key": "snmp",
|
||||
"i18n": "prefs.snmp",
|
||||
"icon": "fas fa-network-wired",
|
||||
"url": "/lua/pro/enterprise/snmpdevices_stats.lua"
|
||||
},
|
||||
{
|
||||
"key": "active_monitoring_system",
|
||||
"i18n": "active_monitoring_stats.active_monitoring",
|
||||
"icon": "fas fa-heartbeat",
|
||||
"url": "/lua/active_monitoring.lua"
|
||||
},
|
||||
{
|
||||
"key": "infrastructure_dashboard_system",
|
||||
"i18n": "infrastructure_dashboard.infrastructure_dashboard",
|
||||
"icon": "fas fa-project-diagram",
|
||||
"url": "/lua/pro/enterprise/infrastructure_config.lua"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "notifications",
|
||||
"i18n": "endpoint_notifications.notifications",
|
||||
"icon": "fas fa-bell",
|
||||
"url": "/lua/admin/endpoint_notifications_list.lua"
|
||||
},
|
||||
{
|
||||
"key": "policies",
|
||||
"i18n": "policies",
|
||||
"icon": "fas fa-shield-alt",
|
||||
"entries": [
|
||||
{
|
||||
"key": "divider",
|
||||
"i18n": "menu_group.access"
|
||||
},
|
||||
{
|
||||
"key": "access_control_list",
|
||||
"i18n": "access_control_list",
|
||||
"icon": "fas fa-list-ul",
|
||||
"url": "/lua/pro/admin/access_control_list.lua"
|
||||
},
|
||||
{
|
||||
"key": "device_protocols",
|
||||
"i18n": "device_protocols.device_protocols",
|
||||
"icon": "fas fa-sliders-h",
|
||||
"url": "/lua/admin/edit_device_protocols.lua"
|
||||
},
|
||||
{
|
||||
"key": "device_exclusions",
|
||||
"i18n": "edit_check.device_exclusion",
|
||||
"icon": "fas fa-ban",
|
||||
"url": "/lua/pro/admin/edit_device_exclusions.lua"
|
||||
},
|
||||
{
|
||||
"key": "network_config",
|
||||
"i18n": "checks.network_configuration",
|
||||
"icon": "fas fa-network-wired",
|
||||
"url": "/lua/admin/network_configuration.lua"
|
||||
},
|
||||
{
|
||||
"key": "traffic_rules",
|
||||
"i18n": "if_stats_config.traffic_rules",
|
||||
"icon": "fas fa-traffic-light",
|
||||
"url": "/lua/pro/traffic_rules.lua"
|
||||
},
|
||||
{
|
||||
"key": "divider",
|
||||
"i18n": "menu_group.checks"
|
||||
},
|
||||
{
|
||||
"key": "scripts_config",
|
||||
"i18n": "about.checks",
|
||||
"icon": "fas fa-check-double",
|
||||
"url_dynamic": "scripts_config_url"
|
||||
},
|
||||
{
|
||||
"key": "alert_exclusions",
|
||||
"i18n": "edit_check.exclusion_list",
|
||||
"icon": "fas fa-filter",
|
||||
"url": "/lua/pro/admin/edit_alert_exclusions.lua?subdir=host"
|
||||
},
|
||||
{
|
||||
"key": "divider",
|
||||
"i18n": "menu_group.profiles"
|
||||
},
|
||||
{
|
||||
"key": "profiles",
|
||||
"i18n": "traffic_profiles.traffic_profiles",
|
||||
"icon": "fas fa-tags",
|
||||
"url": "/lua/pro/admin/edit_profiles.lua"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "admin",
|
||||
"i18n": "settings",
|
||||
"icon": "fas fa-cog",
|
||||
"entries": [
|
||||
{
|
||||
"key": "divider",
|
||||
"i18n": "menu_group.users"
|
||||
},
|
||||
{
|
||||
"key": "nedge_users",
|
||||
"i18n": "nedge.users",
|
||||
"icon": "fas fa-users",
|
||||
"url": "/lua/pro/nedge/admin/nf_list_users.lua"
|
||||
},
|
||||
{
|
||||
"key": "manage_users",
|
||||
"i18n": "manage_users.manage_users",
|
||||
"icon": "fas fa-user-cog",
|
||||
"url": "/lua/admin/users.lua"
|
||||
},
|
||||
{
|
||||
"key": "divider",
|
||||
"i18n": "menu_group.configuration"
|
||||
},
|
||||
{
|
||||
"key": "preferences",
|
||||
"i18n": "prefs.preferences",
|
||||
"icon": "fas fa-sliders-h",
|
||||
"url": "/lua/admin/prefs.lua"
|
||||
},
|
||||
{
|
||||
"key": "tags",
|
||||
"i18n": "tags_page.tags",
|
||||
"icon": "fas fa-tag",
|
||||
"url": "/lua/tags.lua"
|
||||
},
|
||||
{
|
||||
"key": "category_lists",
|
||||
"i18n": "category_lists.category_lists",
|
||||
"icon": "fas fa-list",
|
||||
"url": "/lua/admin/blacklists.lua?enabled_status=enabled"
|
||||
},
|
||||
{
|
||||
"key": "manage_configurations",
|
||||
"i18n": "manage_configurations.manage_configurations",
|
||||
"icon": "fas fa-file-export",
|
||||
"url": "/lua/admin/manage_configurations.lua"
|
||||
},
|
||||
{
|
||||
"key": "divider",
|
||||
"i18n": "menu_group.customization"
|
||||
},
|
||||
{
|
||||
"key": "categories",
|
||||
"i18n": "custom_categories.apps_and_categories",
|
||||
"icon": "fas fa-th-large",
|
||||
"url": "/lua/admin/edit_categories.lua"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "dev",
|
||||
"i18n": "developer",
|
||||
"icon": "fas fa-code",
|
||||
"entries": [
|
||||
{
|
||||
"key": "rest_api",
|
||||
"i18n": "swagger_api",
|
||||
"icon": "fas fa-plug",
|
||||
"url": "/lua/swagger.lua"
|
||||
},
|
||||
{
|
||||
"key": "analyze_pcap",
|
||||
"i18n": "upload_pcap",
|
||||
"icon": "fas fa-file-upload",
|
||||
"url": "/lua/upload_pcap.lua"
|
||||
},
|
||||
{
|
||||
"key": "manage_data",
|
||||
"i18n": "manage_data.manage_data",
|
||||
"icon": "fas fa-database",
|
||||
"url": "/lua/manage_data.lua"
|
||||
},
|
||||
{
|
||||
"key": "divider",
|
||||
"i18n": "menu_group.internals"
|
||||
},
|
||||
{
|
||||
"key": "checks_dev",
|
||||
"i18n": "about.checks",
|
||||
"icon": "fas fa-check-square",
|
||||
"url": "/lua/checks_overview.lua"
|
||||
},
|
||||
{
|
||||
"key": "alert_definitions",
|
||||
"i18n": "about.alert_defines",
|
||||
"icon": "fas fa-exclamation-circle",
|
||||
"url": "/lua/defs_overview.lua"
|
||||
},
|
||||
{
|
||||
"key": "ts_definitions",
|
||||
"i18n": "about.ts_definitions",
|
||||
"icon": "fas fa-chart-line",
|
||||
"url": "/lua/ts_overview.lua"
|
||||
},
|
||||
{
|
||||
"key": "directories",
|
||||
"i18n": "about.directories",
|
||||
"icon": "fas fa-folder-open",
|
||||
"url": "/lua/directories.lua"
|
||||
},
|
||||
{
|
||||
"key": "divider",
|
||||
"i18n": "menu_group.documentation"
|
||||
},
|
||||
{
|
||||
"key": "api",
|
||||
"i18n": "about.api_reference",
|
||||
"icon": "fas fa-book-open",
|
||||
"url": "https://www.ntop.org/guides/ntopng/api/",
|
||||
"is_external": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "system_stats",
|
||||
"i18n": "system",
|
||||
"icon": "fas fa-server",
|
||||
"entries": []
|
||||
},
|
||||
{
|
||||
"key": "about",
|
||||
"i18n": "help",
|
||||
"icon": "fas fa-info-circle",
|
||||
"entries": [
|
||||
{
|
||||
"key": "about",
|
||||
"i18n": "about.about",
|
||||
"icon": "fas fa-info",
|
||||
"url": "/lua/about.lua"
|
||||
},
|
||||
{
|
||||
"key": "license",
|
||||
"i18n": "license_page.license",
|
||||
"icon": "fas fa-id-card",
|
||||
"url": "/lua/license.lua"
|
||||
},
|
||||
{
|
||||
"key": "limits",
|
||||
"i18n": "limits_page.limits",
|
||||
"icon": "fas fa-tachometer-alt",
|
||||
"url": "/lua/limits.lua"
|
||||
},
|
||||
{
|
||||
"key": "divider",
|
||||
"i18n": "menu_group.community"
|
||||
},
|
||||
{
|
||||
"key": "blog",
|
||||
"i18n": "about.ntop_blog",
|
||||
"icon": "fas fa-rss",
|
||||
"url": "http://blog.ntop.org/",
|
||||
"is_external": true
|
||||
},
|
||||
{
|
||||
"key": "telegram",
|
||||
"i18n": "about.telegram",
|
||||
"icon": "fab fa-telegram-plane",
|
||||
"url": "https://t.me/ntop_community",
|
||||
"is_external": true
|
||||
},
|
||||
{
|
||||
"key": "manual",
|
||||
"i18n": "about.user_manual",
|
||||
"icon": "fas fa-book",
|
||||
"url": "https://www.ntop.org/guides/ntopng/",
|
||||
"is_external": true
|
||||
},
|
||||
{
|
||||
"key": "divider",
|
||||
"i18n": "menu_group.support"
|
||||
},
|
||||
{
|
||||
"key": "report_issue",
|
||||
"i18n": "about.report_issue",
|
||||
"icon": "fas fa-bug",
|
||||
"url": "https://github.com/ntop/ntopng/issues",
|
||||
"is_external": true
|
||||
},
|
||||
{
|
||||
"key": "suggest_feature",
|
||||
"i18n": "about.suggest_feature",
|
||||
"icon": "fas fa-lightbulb",
|
||||
"url": "https://www.ntop.org/support/need-help-2/contact-us/",
|
||||
"is_external": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -46,16 +46,17 @@
|
|||
"stylelint": "^14.5.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@cyclonedx/cyclonedx-npm": "^5.0.0",
|
||||
"@fortawesome/fontawesome-free": "^6.5.1",
|
||||
"@popperjs/core": "^2.11.2",
|
||||
"@rollup/plugin-inject": "^5.0.5",
|
||||
"@vitejs/plugin-vue": "^5.2.4",
|
||||
"@vue/compiler-sfc": "^3.5.35",
|
||||
"@vueform/slider": "^2.1.10",
|
||||
"@yaireo/tagify": "^4.35.3",
|
||||
"apexcharts": "^3.33.1",
|
||||
"bootstrap": "^5.3.0",
|
||||
"bootstrap-icons": "^1.13.1",
|
||||
"d3": "^3.5.17",
|
||||
"d3-array": "^3.1.1",
|
||||
"d3-chord": "^3.0.1",
|
||||
"d3-collection": "^1.0.7",
|
||||
|
|
@ -88,7 +89,7 @@
|
|||
"uuid": "^11.1.0",
|
||||
"vis-network": "^9.1.6",
|
||||
"vite": "^6.3.5",
|
||||
"vue": "3.2.37",
|
||||
"vue": "^3.5.35",
|
||||
"world-atlas": "^2.0.2"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1109,6 +1109,9 @@ local lang = {
|
|||
["component_versions"] = "Component Versions",
|
||||
["startup_line"] = "Startup Line",
|
||||
["suggest_feature"] = "Suggest a Feature",
|
||||
["user_manual"] = "User Manual",
|
||||
["ts_definitions"] = "Time Series",
|
||||
["api_reference"] = "API Reference",
|
||||
["system"] = "System",
|
||||
["system_id"] = "System Id",
|
||||
["system_info"] = "System Information",
|
||||
|
|
@ -9982,6 +9985,26 @@ local lang = {
|
|||
["abort_edit"] = "Abort edit of a Widget?",
|
||||
},
|
||||
},
|
||||
["menu_group"] = {
|
||||
["notifications"] = "Notifications",
|
||||
["routing"] = "Routing",
|
||||
["stats"] = "Stats",
|
||||
["asn_mode"] = "ASN Mode",
|
||||
["inventory"] = "Inventory",
|
||||
["segments"] = "Segments",
|
||||
["containers"] = "Containers",
|
||||
["storage"] = "Storage",
|
||||
["access"] = "Access",
|
||||
["checks"] = "Checks",
|
||||
["profiles"] = "Profiles",
|
||||
["users"] = "Users",
|
||||
["configuration"] = "Configuration",
|
||||
["customization"] = "Customization",
|
||||
["internals"] = "Internals",
|
||||
["documentation"] = "Documentation",
|
||||
["community"] = "Community",
|
||||
["support"] = "Support",
|
||||
},
|
||||
}
|
||||
|
||||
return lang
|
||||
|
|
|
|||
|
|
@ -2438,7 +2438,7 @@ if isEmptyString(page) or page == "overview" then
|
|||
}
|
||||
},
|
||||
};
|
||||
const vue = ntopVue.Vue.createApp(vue_options);
|
||||
const vue = ntopVue.createApp(vue_options);
|
||||
const vue_app = vue.mount("#vue-modals");
|
||||
return vue_app;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,874 +1,60 @@
|
|||
--
|
||||
-- (C) 2013-26 - ntop.org
|
||||
--
|
||||
require "os"
|
||||
-- Thin shell: mounts AppFooter Vue component, then closes the page.
|
||||
-- All footer logic (updates, ext_link_dialog, nEdge modals, 403 handler)
|
||||
-- lives in http_src/vue/app-footer.vue.
|
||||
--
|
||||
|
||||
local dirs = ntop.getDirs()
|
||||
package.path = dirs.installdir .. "/scripts/lua/modules/?.lua;" .. package.path
|
||||
package.path = dirs.installdir .. "/scripts/lua/modules/toasts/?.lua;" .. package.path
|
||||
|
||||
require "lua_utils"
|
||||
|
||||
local ts_utils = require("ts_utils_core")
|
||||
local template_utils = require "template_utils"
|
||||
local json = require "dkjson"
|
||||
local ts_utils = require "ts_utils_core"
|
||||
|
||||
local template = require "template_utils"
|
||||
local stats_utils = require("stats_utils")
|
||||
local page_utils = require "page_utils"
|
||||
local have_nedge = ntop.isnEdge()
|
||||
local info = ntop.getInfo(true)
|
||||
local is_admin = isAdministrator()
|
||||
local maxSpeed
|
||||
|
||||
local ifid = interface.getId()
|
||||
local _ifstats = interface.getStats()
|
||||
local is_admin = isAdministrator()
|
||||
local have_nedge = ntop.isnEdge()
|
||||
local info = ntop.getInfo(true)
|
||||
local http_prefix = ntop.getHttpPrefix()
|
||||
local random_csrf = ntop.getRandomCSRFValue()
|
||||
local is_pcap_dump_iface = interface.isPcapDumpInterface()
|
||||
|
||||
if not is_pcap_dump_iface and not have_nedge then
|
||||
-- if the speed in not custom we try to read the speed from the interface
|
||||
-- and, as a final resort, we use 1Gbps
|
||||
if tonumber(_ifstats.speed) ~= nil then
|
||||
maxSpeed = tonumber(_ifstats.speed) * 1e6
|
||||
else
|
||||
maxSpeed = 1000000000 -- 1 Gbit
|
||||
end
|
||||
end -- closes is_pcap_dump_iface == false
|
||||
|
||||
if not info.oem then
|
||||
|
||||
-- print ([[
|
||||
-- <hr>
|
||||
-- <footer id="n-footer">
|
||||
-- <div class="container-fluid">
|
||||
-- <div class="row mt-2">
|
||||
-- <div class="col-12 col-md-4 pl-md-0 text-center text-md-start">
|
||||
-- <small>
|
||||
-- <a href="https://www.ntop.org/products/traffic-analysis/ntop/" target="_blank">
|
||||
-- ]] .. getNtopngRelease(info) ..[[
|
||||
-- </a>
|
||||
-- </small>
|
||||
-- </div>
|
||||
-- <div class="col-12 col-md-4 text-center">
|
||||
-- <small>]].. ntop.getInfo()["copyright"] ..[[</small>
|
||||
-- ]])
|
||||
-- print [[
|
||||
-- </div>
|
||||
-- <div class="col-12 col-md-4 text-center text-md-end pr-md-0">
|
||||
-- <small>
|
||||
-- <i class="fas fa-clock" title="]] print(i18n("about.server_time")) print[["></i> <div class="d-inline-block" id='network-clock'></div> ]] if(info.tzname ~= nil) then print(info.tzname) end print(" | ") print(i18n("about.uptime")) print[[: <div class="d-inline-block" id='network-uptime'></div>
|
||||
-- </small>
|
||||
-- </div>
|
||||
-- </div>
|
||||
-- </div>
|
||||
-- </footer>
|
||||
-- ]]
|
||||
|
||||
-- else -- info.oem
|
||||
-- print[[<div class="col-12 text-end">
|
||||
-- <small>
|
||||
-- <i class="fas fa-clock"></i> <div class="d-inline-block" id='network-clock' title="]] print(i18n("about.server_time")) print[["></div> | ]] print(i18n("about.uptime")) print[[: <div class="d-inline-block" id='network-uptime'></div>
|
||||
-- </small>
|
||||
-- </div>]]
|
||||
end
|
||||
|
||||
local traffic_peity_width = "96"
|
||||
|
||||
-- Show InfluxDB error immediately if one is cached
|
||||
if ts_utils.getDriverName() == "influxdb" then
|
||||
|
||||
local msg = ntop.getCache("ntopng.cache.influxdb.last_error")
|
||||
if not isEmptyString(msg) then
|
||||
print([[
|
||||
<script type="text/javascript">
|
||||
$("#influxdb-error-msg-text").html("]] .. (msg:gsub('"', '\\"')) .. [[");
|
||||
$("#influxdb-error-msg").show();
|
||||
</script>
|
||||
]])
|
||||
end
|
||||
local msg = ntop.getCache("ntopng.cache.influxdb.last_error")
|
||||
if not isEmptyString(msg) then
|
||||
msg = msg:gsub('"', '\\"')
|
||||
print([[<script type="text/javascript">
|
||||
document.getElementById("influxdb-error-msg-text").innerHTML = "]] .. msg .. [[";
|
||||
document.getElementById("influxdb-error-msg").style.display = "";
|
||||
</script>]])
|
||||
end
|
||||
end
|
||||
|
||||
-- Dismiss Notification Code and Toggle Dark theme
|
||||
print([[
|
||||
<script type='text/javascript'>
|
||||
$(document).ready(function() {
|
||||
|
||||
$(`.notification button.dismiss`).click(function() {
|
||||
const $toast = $(this).parents('.notification');
|
||||
const id = $toast.data("toastId");
|
||||
ToastUtils.dismissToast(id, "]] .. random_csrf ..
|
||||
[[", (data) =>{
|
||||
if (data.success) $toast.toast('hide');
|
||||
});
|
||||
});
|
||||
|
||||
$(`.toggle-dark-theme`).click(function() {
|
||||
const request = $.post(`]] .. http_prefix ..
|
||||
[[/lua/update_prefs.lua`, {
|
||||
action: 'toggle_theme', toggle_dark_theme: ]] ..
|
||||
tostring(not page_utils.is_dark_mode_enabled()) .. [[,
|
||||
csrf: "]] .. random_csrf .. [["
|
||||
});
|
||||
request.done(function(res) {
|
||||
if (res.success) location.reload();
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
]])
|
||||
|
||||
-- Restart product code
|
||||
if (is_admin and ntop.isPackage() and not ntop.isWindows()) then
|
||||
|
||||
print(template.gen("modal_confirm_dialog.html", {
|
||||
dialog = {
|
||||
id = 'restart-modal',
|
||||
action = 'restartService()',
|
||||
title = i18n("restart.restart_product", {product = info.product}),
|
||||
message = i18n("restart.confirm", {product = info.product}),
|
||||
custom_alert_class = 'alert alert-danger',
|
||||
confirm = i18n('restart.restart'),
|
||||
confirm_button = 'btn-danger'
|
||||
}
|
||||
}))
|
||||
|
||||
print [[
|
||||
<script type="text/javascript">
|
||||
|
||||
const restartCSRF = ']]
|
||||
print(random_csrf)
|
||||
print [[';
|
||||
const restartService = function() {
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: ']]
|
||||
print(http_prefix)
|
||||
print [[/lua/admin/service_restart.lua',
|
||||
data: {
|
||||
csrf: restartCSRF
|
||||
},
|
||||
success: function(rsp) {
|
||||
alert("]]
|
||||
print(i18n("restart.restarting", {product = info.product}))
|
||||
print [[");
|
||||
$('#restart-modal').modal('hide');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$('.restart-service').click(() => {
|
||||
$('#restart-modal').modal('show');
|
||||
});
|
||||
|
||||
</script>
|
||||
]]
|
||||
end
|
||||
|
||||
-- render switchable system view
|
||||
print([[
|
||||
<script type="text/javascript">
|
||||
|
||||
$(document).ready(function() {
|
||||
|
||||
// ignore scientific numbers input
|
||||
$(`.ignore-scientific`).keypress(function(e) {
|
||||
if (e.which != 8 && e.which != 0 && e.which < 48 || e.which > 57) {
|
||||
e.preventDefault();
|
||||
}
|
||||
})
|
||||
|
||||
ToastUtils.initToasts();
|
||||
});
|
||||
|
||||
const toggleSystemInterface = ($form = null) => {
|
||||
if($form != null) {
|
||||
$form.submit();
|
||||
}
|
||||
else {
|
||||
console.error("An error has occurred when switching interface!");
|
||||
}
|
||||
}
|
||||
]])
|
||||
print([[
|
||||
</script>
|
||||
]])
|
||||
|
||||
print [[
|
||||
<script type="text/javascript">
|
||||
]]
|
||||
|
||||
print [[
|
||||
var is_historical = false;
|
||||
let updatingChart_uploads = [
|
||||
$("#n-navbar .network-load-chart-upload").show().peity("line", { width: ]]
|
||||
print(traffic_peity_width)
|
||||
print [[, max: null }),
|
||||
$(".mobile-menu-stats .network-load-chart-upload").show().peity("line", { width: ]]
|
||||
print(traffic_peity_width)
|
||||
print [[, max: null }),
|
||||
];
|
||||
let updatingChart_downloads = [
|
||||
$("#n-navbar .network-load-chart-download").show().peity("line", { width: ]]
|
||||
print(traffic_peity_width)
|
||||
print [[, max: null, fill: "lightgreen"}),
|
||||
$(".mobile-menu-stats .network-load-chart-download").show().peity("line", { width: ]]
|
||||
print(traffic_peity_width)
|
||||
print [[, max: null, fill: "lightgreen"})
|
||||
];
|
||||
let updatingChart_totals = [
|
||||
$("#n-navbar .network-load-chart-total").show().peity("line", { width: ]]
|
||||
print(traffic_peity_width)
|
||||
print [[, max: null}),
|
||||
$(".mobile-menu-stats .network-load-chart-total").show().peity("line", { width: ]]
|
||||
print(traffic_peity_width)
|
||||
print [[, max: null})
|
||||
];
|
||||
|
||||
$(`.copy-http-url`).on('click', function() {
|
||||
let sampleTextarea = document.createElement("textarea");
|
||||
document.body.appendChild(sampleTextarea);
|
||||
sampleTextarea.value = $(this).attr('data-to-copy');
|
||||
sampleTextarea.select(); //select textarea content
|
||||
document.execCommand("copy");
|
||||
document.body.removeChild(sampleTextarea);
|
||||
-- AppFooter boot context
|
||||
local footer_context = json.encode({
|
||||
csrf = random_csrf,
|
||||
http_prefix = http_prefix,
|
||||
ifid = tostring(interface.getId()),
|
||||
is_admin = is_admin,
|
||||
is_nedge = have_nedge,
|
||||
has_updates_support = (hasSoftwareUpdatesSupport() == true),
|
||||
is_package = (ntop.isPackage() == true),
|
||||
is_windows = ntop.isWindows(),
|
||||
product = info.product or "",
|
||||
maintenance_expired = (info["pro.license_days_left"] ~= nil and
|
||||
tonumber(info["pro.license_days_left"]) <= 0),
|
||||
})
|
||||
|
||||
let isFooterRefreshInProcess = false;
|
||||
const footerRefresh = function() {
|
||||
if (isFooterRefreshInProcess == true) { return; }
|
||||
isFooterRefreshInProcess = true;
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url: ']]
|
||||
print(http_prefix)
|
||||
print [[/lua/rest/v2/get/interface/data.lua',
|
||||
data: { ifid: ]]
|
||||
print(tostring(ifid))
|
||||
print [[, type: 'summary' },
|
||||
success: function(content) {
|
||||
isFooterRefreshInProcess = false;
|
||||
if(content["rc_str"] != "OK") {
|
||||
return;
|
||||
}
|
||||
|
||||
const rsp = content["rsp"];
|
||||
|
||||
try {
|
||||
ntopng_events_manager.emit_custom_event(ntopng_custom_events.GET_INTERFACE_DATA, rsp);
|
||||
let bps_upload = rsp.throughput.upload * 8;
|
||||
let bps_download = rsp.throughput.download * 8;
|
||||
|
||||
/* Upload chart */
|
||||
let values = updatingChart_uploads[0].text().split(",")
|
||||
values.shift();
|
||||
values.push(bps_upload.toString());
|
||||
updatingChart_uploads[0].text(values.join(",")).change();
|
||||
updatingChart_uploads[1].text(values.join(",")).change();
|
||||
$('.chart-upload-text:visible').html(NtopUtils.bitsToSize(bps_upload, 1000));
|
||||
|
||||
/* Download chart */
|
||||
values = updatingChart_downloads[0].text().split(",")
|
||||
values.shift();
|
||||
values.push((-bps_download).toString());
|
||||
updatingChart_downloads[0].text(values.join(",")).change();
|
||||
updatingChart_downloads[1].text(values.join(",")).change();
|
||||
$('.chart-download-text:visible').html(NtopUtils.bitsToSize(bps_download, 1000));
|
||||
|
||||
/* Disaggregate interface chart */
|
||||
values = updatingChart_totals[0].text().split(",")
|
||||
values.shift();
|
||||
values.push(rsp.throughput_bps * 8);
|
||||
updatingChart_totals[0].text(values.join(",")).change();
|
||||
updatingChart_totals[1].text(values.join(",")).change();
|
||||
]]
|
||||
|
||||
if (is_pcap_dump_iface == false) and (not have_nedge) then
|
||||
print [[
|
||||
const v = Math.round(Math.min((rsp.throughput_bps * 8 *100)/]]
|
||||
print(string.format("%u", maxSpeed))
|
||||
print [[, 100));
|
||||
$('.network-load').html(v+"%");
|
||||
]]
|
||||
end
|
||||
|
||||
-- systemInterfaceEnabled is defined inside menu.lua
|
||||
print [[
|
||||
//$('#network-clock').html(`${rsp.localtime}`);
|
||||
//$('#network-uptime').html(`${rsp.uptime}`);
|
||||
|
||||
let msg = `<div class='m-2'><div class='d-flex flex-wrap navbar-main-badges'>`;
|
||||
|
||||
if(rsp.out_of_maintenance) {
|
||||
msg += "<a href='https://www.ntop.org/support/faq/how-can-i-renew-maintenance-for-commercial-products/' target='_blank'><span class='badge bg-warning'>]]
|
||||
print(i18n("about.maintenance_expired", {product = info["product"]}))
|
||||
print [[ <i class=\"fas fa-external-link-alt\"></i></span></a> ";
|
||||
}
|
||||
|
||||
if(rsp.degraded_performance) {
|
||||
msg += "<a href=']]
|
||||
print(http_prefix)
|
||||
print [[/lua/system_interfaces_stats.lua?page=internals&tab=periodic_activities&periodic_script_issue=any_issue'>"
|
||||
msg += "<span class='badge bg-warning'><i class='fas fa-exclamation-triangle data-bs-toggle='tooltip' data-bs-placement='bottom' title=']]
|
||||
print(i18n("internals.degraded_performance"))
|
||||
print [['></i></span></a>";
|
||||
}
|
||||
|
||||
if ((rsp.engaged_alerts > 0 || rsp.alerted_flows > 0) && ]]
|
||||
print(ternary(hasAllowedNetworksSet(), "false", "true"))
|
||||
print [[) {
|
||||
|
||||
var error_color = "#B94A48";
|
||||
|
||||
if(rsp.engaged_alerts > 0) {
|
||||
let alerts_badge = "bg-info";
|
||||
|
||||
if(rsp.engaged_alerts_error > 0) alerts_badge = "bg-danger";
|
||||
else if(rsp.engaged_alerts_warning > 0) alerts_badge = "bg-warning";
|
||||
|
||||
msg += "<a href=']]
|
||||
print(http_prefix)
|
||||
print [[/lua/alert_stats.lua?ifid=]]
|
||||
print(tostring(ifid))
|
||||
print [[&status=engaged'>"
|
||||
msg += "<span class=\"badge " + alerts_badge + "\" data-bs-toggle='tooltip' data-bs-placement='bottom' title=']] print(i18n('graphs.engaged_alerts')) print[['><i class=\"fas fa-exclamation-triangle\"></i> "+NtopUtils.formatValue(rsp.engaged_alerts, 1)+"</span></a>";
|
||||
}
|
||||
|
||||
if(rsp.alerted_flows_warning > 0 && !(systemInterfaceEnabled)) {
|
||||
msg += "<a href=']]
|
||||
print(http_prefix)
|
||||
print [[/lua/flows_stats.lua?status=warning'>"
|
||||
msg += "<span class=\"badge bg-warning\" data-bs-toggle='tooltip' data-bs-placement='bottom' title=']]
|
||||
print(i18n("flow_details.alerted_flows"))
|
||||
print [['>"+NtopUtils.formatValue(rsp.alerted_flows_warning, 1)+ " <i class=\"fas fa-stream\"></i> ]]
|
||||
print [[ <i class=\"fas fa-exclamation-triangle\"></i></span></a>";
|
||||
}
|
||||
|
||||
if(rsp.alerted_flows_error > 0 && !(systemInterfaceEnabled)) {
|
||||
msg += "<a href=']]
|
||||
print(http_prefix)
|
||||
print [[/lua/flows_stats.lua?status=error'>"
|
||||
msg += "<span class=\"badge bg-danger\" data-bs-toggle='tooltip' data-bs-placement='bottom' title=']]
|
||||
print(i18n("flow_details.dangerous_flows"))
|
||||
print [['>"+NtopUtils.formatValue(rsp.alerted_flows_error, 1)+ " <i class=\"fas fa-stream\"></i> ]]
|
||||
print [[ <i class=\"fas fa-exclamation-triangle\"></i></span></a>";
|
||||
}
|
||||
|
||||
if(rsp.active_discovery_active === true) {
|
||||
msg += "<a href=']]
|
||||
print(http_prefix)
|
||||
print [[/lua/discover.lua'>"
|
||||
msg += "<span class=\"badge bg-warning\" data-bs-toggle='tooltip' data-bs-placement='bottom' title=']]
|
||||
print(i18n("prefs.network_discovery_running"))
|
||||
print [['><i class=\"fas fa-project-diagram\"></i></span></a>";
|
||||
}
|
||||
}
|
||||
|
||||
if((rsp.engaged_alerts > 0 || rsp.alerted_flows > 0) && $("#alerts-id").is(":visible") == false) {
|
||||
$("#alerts-id").show();
|
||||
}
|
||||
|
||||
if(rsp.ts_alerts && rsp.ts_alerts.influxdb && (!systemInterfaceEnabled)) {
|
||||
msg += "<a href=']]
|
||||
print(http_prefix)
|
||||
print [[/lua/monitor/influxdb_monitor.lua?ifid=]]
|
||||
print(tostring(ifid))
|
||||
print [[&page=alerts#tab-table-engaged-alerts'>"
|
||||
msg += "<span class=\"badge bg-danger\" data-bs-toggle='tooltip' data-bs-placement='bottom' title=']] print(i18n('alerts_dashboard.influxdb_error')) print[['><i class=\"fas fa-database\"></i></span></a>";
|
||||
}
|
||||
|
||||
var alarm_threshold_low = 60; /* 60% */
|
||||
var alarm_threshold_high = 90; /* 90% */
|
||||
var alert = 0;
|
||||
|
||||
if(rsp.num_local_hosts > 0 && (!systemInterfaceEnabled)) {
|
||||
msg += "<a href=']]
|
||||
print(http_prefix)
|
||||
print [[/lua/hosts_stats.lua?mode=local'>";
|
||||
msg += "<span data-bs-toggle='tooltip' data-bs-placement='bottom' title=\"]]
|
||||
print(i18n("local_hosts"))
|
||||
print [[\" class=\"badge bg-success\">";
|
||||
msg += NtopUtils.formatValue(rsp.num_local_hosts, 1);
|
||||
if(rsp.num_local_rcvd_only_hosts > 0) msg += " ("+NtopUtils.formatValue(rsp.num_local_rcvd_only_hosts, 1)+")";
|
||||
msg += " <i class=\"fas fa-laptop\" aria-hidden=\"true\"></i></span></a>";
|
||||
}
|
||||
|
||||
const num_remote_hosts = rsp.num_hosts - rsp.num_local_hosts;
|
||||
if(num_remote_hosts > 0 && (!systemInterfaceEnabled)) {
|
||||
msg += "<a href=']]
|
||||
print(http_prefix)
|
||||
print [[/lua/hosts_stats.lua?mode=remote'>";
|
||||
var remote_hosts_label = "]]
|
||||
print(i18n("remote_hosts"))
|
||||
print [[";
|
||||
|
||||
if (rsp.hosts_pctg < alarm_threshold_low && !systemInterfaceEnabled) {
|
||||
msg += "<span data-bs-toggle='tooltip' data-bs-placement='bottom' title=\"" + remote_hosts_label +"\" class=\"badge bg-secondary\">";
|
||||
} else if (rsp.hosts_pctg < alarm_threshold_high && !systemInterfaceEnabled) {
|
||||
alert = 1;
|
||||
msg += "<span data-bs-toggle='tooltip' data-bs-placement='bottom' title=\"" + remote_hosts_label +"\" class=\"badge bg-warning\">";
|
||||
} else {
|
||||
alert = 1;
|
||||
msg += "<span data-bs-toggle='tooltip' data-bs-placement='bottom' title=\"" + remote_hosts_label +"\" class=\"badge bg-danger\">";
|
||||
}
|
||||
|
||||
msg += NtopUtils.formatValue(num_remote_hosts, 1);
|
||||
num_remote_rcvd_only_hosts = rsp.num_rcvd_only_hosts - rsp.num_local_rcvd_only_hosts;
|
||||
if(num_remote_rcvd_only_hosts > 0) msg += " ("+NtopUtils.formatValue(num_remote_rcvd_only_hosts, 1)+")";
|
||||
msg += " <i class=\"fas fa-laptop\" aria-hidden=\"true\"></i></span></a>";
|
||||
}
|
||||
|
||||
if(rsp.num_devices > 0 && (!systemInterfaceEnabled)) {
|
||||
var macs_label = "]]
|
||||
print(i18n("mac_stats.layer_2_source_devices", {device_type = ""}))
|
||||
print [[";
|
||||
msg += "<a href=']]
|
||||
print(http_prefix)
|
||||
print [[/lua/macs_stats.lua?devices_mode=source_macs_only'>";
|
||||
|
||||
if (rsp.macs_pctg < alarm_threshold_low) {
|
||||
msg += "<span data-bs-toggle='tooltip' data-bs-placement='bottom' title=\"" + macs_label +"\" class=\"badge bg-secondary\">";
|
||||
} else if(rsp.macs_pctg < alarm_threshold_high) {
|
||||
alert = 1;
|
||||
msg += "<span data-bs-toggle='tooltip' data-bs-placement='bottom' title=\"" + macs_label +"\" class=\"badge bg-warning\">";
|
||||
} else {
|
||||
alert = 1;
|
||||
msg += "<span data-bs-toggle='tooltip' data-bs-placement='bottom' title=\"" + macs_label +"\" class=\"badge bg-danger\">";
|
||||
}
|
||||
|
||||
msg += NtopUtils.formatValue(rsp.num_devices, 1)+" <i class=\"fas fa-ethernet\"></i></span></a>";
|
||||
}
|
||||
|
||||
if(rsp.num_flows > 0 && (!systemInterfaceEnabled)) {
|
||||
msg += "<a href=']]
|
||||
print(http_prefix)
|
||||
print [[/lua/flows_stats.lua'>";
|
||||
const flows_label = "]]
|
||||
print(i18n("live_flows"))
|
||||
print [["
|
||||
if (rsp.flows_pctg < alarm_threshold_low) {
|
||||
msg += "<span data-bs-toggle='tooltip' data-bs-placement='bottom' title=\"" + flows_label +"\" class=\"badge bg-secondary\">";
|
||||
} else if(rsp.flows_pctg < alarm_threshold_high) {
|
||||
alert = 1;
|
||||
msg += "<span data-bs-toggle='tooltip' data-bs-placement='bottom' title=\"" + flows_label +"\" class=\"badge bg-warning\">";
|
||||
} else {
|
||||
alert = 1;
|
||||
msg += "<span data-bs-toggle='tooltip' data-bs-placement='bottom' title=\"" + flows_label +"\" class=\"badge bg-danger\">";
|
||||
}
|
||||
|
||||
msg += NtopUtils.formatValue(rsp.num_flows, 1)+" <i class=\"fas fa-stream\"></i> </span> </a>";
|
||||
|
||||
if (rsp.db && rsp.db.flow_export_drops > 0) {
|
||||
const export_pctg = rsp.db.flow_export_drops / (rsp.db.flow_export_count + rsp.db.flow_export_drops + 1);
|
||||
if (export_pctg > ]]
|
||||
print(stats_utils.UPPER_BOUND_INFO_EXPORTS)
|
||||
print [[) {
|
||||
const badge_class = (export_pctg <= ]]
|
||||
print(stats_utils.UPPER_BOUND_WARNING_EXPORTS)
|
||||
print [[) ? 'warning' : 'danger';
|
||||
msg += "<a href=']]
|
||||
print(http_prefix)
|
||||
print [[/lua/if_stats.lua'><span class=\"badge bg-"+badge_class+"\" data-bs-toggle='tooltip' data-bs-placement='bottom' title=\"]] print(i18n('flow_export_drops')) print[[\"><i class=\"fas fa-exclamation-triangle\" style=\"color: #FFFFFF;\"></i> "+NtopUtils.formatValue(rsp.db.flow_export_drops, 1)+" DB Export drop";
|
||||
if(rsp.db.flow_export_drops > 1) msg += "s";
|
||||
msg += "</span></a>";
|
||||
}
|
||||
}
|
||||
if (rsp.dropped_zmq_msg > 0) {
|
||||
msg += "<a href=']]
|
||||
print(http_prefix)
|
||||
print [[/lua/if_stats.lua'><span class=\"badge bg-warning\"><i class=\"fas fa-tint\" style=\"color: #FFFFFF;\" data-bs-toggle='tooltip' data-bs-placement='bottom' title=\"]] print(i18n('dropping_zmq_msg')) print[[\"></i> "+NtopUtils.formatValue(rsp.dropped_zmq_msg, 1)+" ZMQ Drops</span></a>";
|
||||
}
|
||||
if (rsp.dropped_flows > 0) {
|
||||
msg += "<a href=']]
|
||||
print(http_prefix)
|
||||
print [[/lua/if_stats.lua'><span class=\"badge bg-warning\"><i class=\"fas fa-tint\" style=\"color: #FFFFFF;\" data-bs-toggle='tooltip' data-bs-placement='bottom' title=\"]] print(i18n('dropping_flows')) print[[\"></i> "+NtopUtils.formatValue(rsp.dropped_flows, 1)+" Flows Drops</span></a>";
|
||||
}
|
||||
}
|
||||
|
||||
if ((rsp.num_live_captures != undefined) && (rsp.num_live_captures > 0) && (!systemInterfaceEnabled)) {
|
||||
msg += "<a href=']]
|
||||
print(http_prefix)
|
||||
print [[/lua/live_capture_stats.lua'>";
|
||||
msg += "<span class=\"badge bg-primary\" data-bs-toggle='tooltip' data-bs-placement='bottom' title=\"]] print(i18n('live_capture.active_live_captures')) print[[\">";
|
||||
msg += NtopUtils.addCommas(rsp.num_live_captures)+" <i class=\"fas fa-download fa-lg\"></i></span></a>";
|
||||
}
|
||||
|
||||
if (rsp.traffic_recording != undefined && (!systemInterfaceEnabled)) {
|
||||
var status_label="primary";
|
||||
var status_title="]]
|
||||
print(i18n("traffic_recording.recording"))
|
||||
print [[";
|
||||
|
||||
if (rsp.traffic_recording != "recording") {
|
||||
status_label = "danger";
|
||||
status_title = "]]
|
||||
print(i18n("traffic_recording.failure"))
|
||||
print [[";
|
||||
}
|
||||
|
||||
msg += "<a href=']]
|
||||
print(http_prefix)
|
||||
print [[/lua/if_stats.lua?ifid=]]
|
||||
print(tostring(ifid))
|
||||
print [[&page=traffic_recording&tab=status'>";
|
||||
msg += "<span class=\"badge bg-"+status_label+"\" data-bs-toggle='tooltip' data-bs-placement='bottom' title=\""+NtopUtils.addCommas(status_title)+"\">";
|
||||
msg += "<i class=\"fas fa-hdd fa-lg\"></i></span></a>";
|
||||
}
|
||||
|
||||
if (rsp.traffic_extraction != undefined && (!systemInterfaceEnabled)) {
|
||||
var status_title="]]
|
||||
print(i18n("traffic_recording.traffic_extraction_jobs"))
|
||||
print [[";
|
||||
var status_label = "secondary";
|
||||
|
||||
if (rsp.traffic_extraction == "ready") status_label="primary";
|
||||
|
||||
msg += "<a href=']]
|
||||
print(http_prefix)
|
||||
print [[/lua/if_stats.lua?ifid=]]
|
||||
print(tostring(ifid))
|
||||
print [[&page=traffic_recording&tab=jobs'>";
|
||||
msg += "<span class=\"badge bg-"+status_label+"\" data-bs-toggle='tooltip' data-bs-placement='bottom' title=\""+NtopUtils.addCommas(status_title)+"\">";
|
||||
msg += rsp.traffic_extraction_num_tasks+" <i class=\"fas fa-tasks fa-lg\"></i></span></a>";
|
||||
}
|
||||
|
||||
if (rsp.vs_in_progress != undefined && rsp.vs_in_progress > 0 && (!systemInterfaceEnabled)) {
|
||||
msg += "<a href=']]
|
||||
print(http_prefix)
|
||||
print [[/lua/vulnerability_scan.lua'>";
|
||||
msg += "<span class=\"badge bg-primary\" data-bs-toggle='tooltip' data-bs-placement='bottom' title=\"]] print(i18n('vulnerability_scan.vulnerability_scan_in_progress')) print[[\">";
|
||||
msg += NtopUtils.addCommas(rsp.vs_in_progress) +" <i class=\"fas fa-satellite-dish\"></i></span></a>";
|
||||
}
|
||||
|
||||
if(rsp.is_loading == true) {
|
||||
msg += "<blink><span data-bs-toggle='tooltip' data-bs-placement='bottom' title=\"]] print(i18n('loading')) print[[\" class=\"badge bg-primary\"><i class=\"fas fa-spinner\"></i> ]]
|
||||
print(i18n("loading"))
|
||||
print [[</span></blink>";
|
||||
}
|
||||
]]
|
||||
|
||||
if ntop.isOffline() then
|
||||
print [[
|
||||
msg += "<a href=\"#\" style=\"cursor: default\"><span data-bs-toggle='tooltip' data-bs-placement='bottom' title=\"]]
|
||||
print(i18n("offline"))
|
||||
print [[\" class=\"badge bg-secondary\"><i class=\"fas fa-plane\"></i></span></a>";
|
||||
]]
|
||||
end
|
||||
|
||||
print [[
|
||||
msg += '</div></div>';
|
||||
// append the message inside the network-load element
|
||||
const $msg = $(msg);
|
||||
// resize element's font size to fit better
|
||||
if ($msg.width() > $msg.css('max-width')) {
|
||||
$msg.find('span').css('font-size', '0.748rem');
|
||||
}
|
||||
|
||||
$('.network-load').html($msg);
|
||||
|
||||
NtopUtils.reloadBSTooltips();
|
||||
|
||||
} catch(e) {
|
||||
console.warn(e);
|
||||
/* alert("JSON Error (session expired?): logging out"); window.location.replace("]]
|
||||
print(http_prefix)
|
||||
print [[/lua/logout.lua"); */
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
isFooterRefreshInProcess = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$(document).ajaxError(function(err, response, ajaxSettings, thrownError) {
|
||||
if((response.status == 403) && (response.responseText == "Login Required"))
|
||||
window.location.href = "]]
|
||||
print(http_prefix .. "/lua/login.lua")
|
||||
print [[";
|
||||
});
|
||||
|
||||
footerRefresh(); /* call immediately to give the UI a more responsive look */
|
||||
|
||||
setInterval(footerRefresh, 7000); /* re-schedule every [interface-rate] seconds */
|
||||
|
||||
//Automatically open dropdown-menu
|
||||
$(document).ready(function(){
|
||||
$('ul.nav li.dropdown').hover(function() {
|
||||
$(this).find('.dropdown-menu').stop(true, true).delay(150).fadeIn(100);
|
||||
}, function() {
|
||||
$(this).find('.dropdown-menu').stop(true, true).delay(150).fadeOut(100);
|
||||
});
|
||||
$('.collapse')
|
||||
.on('shown.bs.collapse', function(){
|
||||
$(this).parent().find(".fa-caret-down").removeClass("fa-caret-down").addClass("fa-caret-up");
|
||||
})
|
||||
.on('hidden.bs.collapse', function(){
|
||||
$(this).parent().find(".fa-caret-up").removeClass("fa-caret-up").addClass("fa-caret-down");
|
||||
});
|
||||
});
|
||||
|
||||
]]
|
||||
|
||||
-- This code rewrites the current page state after a POST request to avoid Document Expired errors
|
||||
if not table.empty(_POST) then
|
||||
print [[
|
||||
if ((typeof(history) === "object")
|
||||
&& (typeof(history).replaceState === "function")
|
||||
&& (typeof(window.location.href) === "string"))
|
||||
history.replaceState(history.state, "", window.location.href);
|
||||
]]
|
||||
end
|
||||
|
||||
print [[
|
||||
|
||||
// hide the possibly shown alerts icon in the header
|
||||
]]
|
||||
if not _ifstats.isView then
|
||||
print("$('#alerts-li').hide();")
|
||||
else
|
||||
print("$('#alerts-li').show();")
|
||||
end
|
||||
|
||||
print([[
|
||||
</script>
|
||||
]])
|
||||
|
||||
-- ######################################
|
||||
|
||||
if have_nedge then
|
||||
print [[<form id="powerOffForm" method="post">
|
||||
<input name="csrf" value="]]
|
||||
print(random_csrf)
|
||||
print [[" type="hidden" />
|
||||
<input name="poweroff" value="" type="hidden" />
|
||||
</form>
|
||||
<form id="rebootForm" method="post">
|
||||
<input name="csrf" value="]]
|
||||
print(random_csrf)
|
||||
print [[" type="hidden" />
|
||||
<input name="reboot" value="" type="hidden" />
|
||||
</form>]]
|
||||
|
||||
print(template.gen("modal_confirm_dialog.html", {
|
||||
dialog = {
|
||||
id = "poweroff_dialog",
|
||||
action = "$('#powerOffForm').submit()",
|
||||
title = i18n("nedge.power_off"),
|
||||
message = i18n("nedge.power_off_confirm"),
|
||||
confirm = i18n("nedge.power_off")
|
||||
}
|
||||
}))
|
||||
|
||||
print(template.gen("modal_confirm_dialog.html", {
|
||||
dialog = {
|
||||
id = "reboot_dialog",
|
||||
action = "$('#rebootForm').submit()",
|
||||
title = i18n("nedge.reboot"),
|
||||
message = i18n("nedge.reboot_corfirm"),
|
||||
confirm = i18n("nedge.reboot")
|
||||
}
|
||||
}))
|
||||
|
||||
end
|
||||
|
||||
print(template.gen("modal_confirm_dialog.html", {
|
||||
dialog = {
|
||||
id = "ext_link_dialog",
|
||||
title = i18n("external_link"),
|
||||
message = i18n("show_alerts.confirm_external_link"),
|
||||
confirm = i18n("redirect")
|
||||
}
|
||||
}))
|
||||
|
||||
print [[
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function(){
|
||||
$(document).on('click','a.ntopng-external-link',function(event){
|
||||
event.preventDefault();
|
||||
const url=$(this)[0].href;
|
||||
$("#url_ext_link_dialog").html(url+"<br/>]]
|
||||
print(i18n("are_you_sure"))
|
||||
print [[");
|
||||
$("#btn-confirm-action_ext_link_dialog").attr('href',url);
|
||||
$('#ext_link_dialog').modal('show');
|
||||
});
|
||||
});
|
||||
</script>
|
||||
]]
|
||||
|
||||
-- Updates submenu
|
||||
if hasSoftwareUpdatesSupport() then
|
||||
|
||||
-- Updates check
|
||||
print [[
|
||||
<script type='text/javascript'>
|
||||
$('#updates-info-li').html(']]
|
||||
print(i18n("updates.checking"))
|
||||
print [[');
|
||||
$('#updates-install-li').hide();
|
||||
|
||||
const updates_csrf = ']]
|
||||
print(random_csrf)
|
||||
print [[';
|
||||
|
||||
/* Updates status */
|
||||
var updatesStatus = '';
|
||||
var updatesLastCheck = 0;
|
||||
|
||||
/* Install latest update */
|
||||
var installUpdate = function() {
|
||||
if (confirm(']]
|
||||
print(i18n("updates.install_confirm"))
|
||||
if info["pro.license_days_left"] ~= nil and info["pro.license_days_left"] <=
|
||||
0 then
|
||||
-- License is valid, however maintenance is expired: warning the user
|
||||
print(" " .. i18n("updates.maintenance_expired"))
|
||||
end
|
||||
print [[')) {
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: ']]
|
||||
print(http_prefix)
|
||||
print [[/lua/install_update.lua',
|
||||
data: {
|
||||
csrf: updates_csrf
|
||||
},
|
||||
success: function(rsp) {
|
||||
$('#updates-info-li').html(']]
|
||||
print(i18n("updates.installing"))
|
||||
print [[')
|
||||
$('#updates-info-li').attr('title', '');
|
||||
$('#updates-install-li').hide();
|
||||
$('#admin-badge').hide();
|
||||
updatesStatus = 'installing';
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for new updates */
|
||||
var checkForUpdates = function() {
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: ']]
|
||||
print(http_prefix)
|
||||
print [[/lua/check_update.lua',
|
||||
data: {
|
||||
csrf: updates_csrf,
|
||||
search: 'true'
|
||||
},
|
||||
success: function(rsp) {
|
||||
$('#updates-info-li').html(']]
|
||||
print(i18n("updates.checking"))
|
||||
print [[');
|
||||
$('#updates-info-li').attr('title', '');
|
||||
$('#updates-install-li').hide();
|
||||
$('#admin-badge').hide();
|
||||
updatesStatus = 'checking';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* Update the menu with the current updates status */
|
||||
var updatesRefresh = function() {
|
||||
const now = Date.now()/1000;
|
||||
let check_time_sec = 10;
|
||||
|
||||
if (updatesStatus == 'installing' || updatesStatus == 'checking') {
|
||||
/* Go ahead (frequent update) */
|
||||
} else if (updatesStatus == 'update-avail' || updatesStatus == 'upgrade-failure') {
|
||||
return; /* no need to check again */
|
||||
} else { /* updatesStatus == 'not-avail' || updatesStatus == 'update-failure' || updatesStatus == <other errors> || updatesStatus == '' */
|
||||
check_time_sec = 300;
|
||||
}
|
||||
|
||||
if (now < updatesLastCheck + check_time_sec) return; /* check with low freq */
|
||||
updatesLastCheck = now;
|
||||
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url: ']]
|
||||
print(http_prefix)
|
||||
print [[/lua/check_update.lua',
|
||||
data: {},
|
||||
success: function(rsp) {
|
||||
if(rsp && rsp.status) {
|
||||
|
||||
updatesStatus = rsp.status;
|
||||
|
||||
if (rsp.status == 'installing') {
|
||||
$('#updates-info-li').html(']]
|
||||
print(i18n("updates.installing"))
|
||||
print [[')
|
||||
$('#updates-info-li').attr('title', '');
|
||||
$('#updates-install-li').hide();
|
||||
$('#admin-badge').hide();
|
||||
|
||||
} else if (rsp.status == 'checking') {
|
||||
$('#updates-info-li').html(']]
|
||||
print(i18n("updates.checking"))
|
||||
print [[');
|
||||
$('#updates-info-li').attr('title', '');
|
||||
$('#updates-install-li').hide();
|
||||
$('#admin-badge').hide();
|
||||
|
||||
} else if (rsp.status == 'update-avail' || rsp.status == 'upgrade-failure') {
|
||||
|
||||
$('#updates-info-li').html('<span class="badge bg-pill bg-danger">]]
|
||||
print(i18n("updates.available"))
|
||||
print [[</span> ]]
|
||||
print(info["product"])
|
||||
print [[ ' + rsp.version);
|
||||
$('#updates-info-li').attr('title', '');
|
||||
|
||||
var icon = '<i class="fas fa-download"></i>';
|
||||
$('#updates-install-li').attr('title', '');
|
||||
if (rsp.status !== 'update-avail') {
|
||||
icon = '<i class="fas fa-exclamation-triangle text-danger"></i>';
|
||||
$('#updates-install-li').attr('title', "]]
|
||||
print(i18n("updates.update_failure_message"))
|
||||
print [[: " + rsp.status);
|
||||
}
|
||||
$('#updates-install-li').html(icon + " ]]
|
||||
print(i18n("updates.install"))
|
||||
print [[");
|
||||
$('#updates-install-li').show();
|
||||
$('#updates-install-li').off("click");
|
||||
$('#updates-install-li').click(installUpdate);
|
||||
|
||||
if (rsp.status !== 'update-avail') $('#admin-badge').html('!');
|
||||
else $('#admin-badge').html('1');
|
||||
$('#admin-badge').show();
|
||||
|
||||
} else /* (rsp.status == 'not-avail' || rsp.status == 'update-failure' || rsp.status == <other errors>) */ {
|
||||
|
||||
var icon = '';
|
||||
$('#updates-info-li').attr('title', '');
|
||||
if (rsp.status !== 'not-avail') {
|
||||
icon = '<i class="fas fa-exclamation-triangle text-danger"></i> ';
|
||||
$('#updates-info-li').attr('title', "]]
|
||||
print(i18n("updates.update_failure_message"))
|
||||
print [[: " + rsp.status);
|
||||
}
|
||||
$('#updates-info-li').html(icon + ']]
|
||||
print(i18n("updates.no_updates"))
|
||||
print [[');
|
||||
|
||||
$('#updates-install-li').html("<i class='fas fa-sync'></i> ]]
|
||||
print(i18n("updates.check"))
|
||||
print [[");
|
||||
$('#updates-install-li').show();
|
||||
$('#updates-install-li').off("click");
|
||||
$('#updates-install-li').click(checkForUpdates);
|
||||
|
||||
$('#admin-badge').hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
setInterval(updatesRefresh, 1000);
|
||||
</script>
|
||||
]]
|
||||
end
|
||||
|
||||
-- close wrapper
|
||||
print [[
|
||||
</main>
|
||||
</div>
|
||||
</body>
|
||||
</html> ]]
|
||||
template_utils.render("pages/vue_page.template", {
|
||||
vue_page_name = "AppFooter",
|
||||
page_context = footer_context,
|
||||
})
|
||||
|
||||
print("</main>")
|
||||
print("</div>")
|
||||
print("</body>")
|
||||
print("</html>")
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
284
scripts/lua/modules/ntopng_menu_visibility.lua
Normal file
284
scripts/lua/modules/ntopng_menu_visibility.lua
Normal file
|
|
@ -0,0 +1,284 @@
|
|||
--
|
||||
-- (C) 2013-26 - ntop.org
|
||||
--
|
||||
|
||||
--
|
||||
-- Exports two functions:
|
||||
-- get_flags() -> flat table of named boolean flags used by entry_hidden checks
|
||||
-- get_dynamic_entries(section_key, flags, page_utils, http_prefix)
|
||||
-- -> array of extra {key,label,url,is_divider} rows injected by
|
||||
-- page_utils.scripts_menu, nedge, appliance, etc.
|
||||
--
|
||||
|
||||
local ntopng_menu_visibility = {}
|
||||
|
||||
function ntopng_menu_visibility.get_flags()
|
||||
local page_utils = require "page_utils"
|
||||
local auth = require "auth"
|
||||
local behavior_utils = require "behavior_utils"
|
||||
local vs_utils = require "vs_utils"
|
||||
|
||||
local prefs = ntop.getPrefs()
|
||||
local info = ntop.getInfo(true)
|
||||
local ifid_stats = interface.getStats()
|
||||
local current_ifid = interface.getId()
|
||||
local is_admin = isAdministrator()
|
||||
local http_prefix = ntop.getHttpPrefix()
|
||||
|
||||
local is_system_interface = toboolean(page_utils.is_system_view())
|
||||
local system_ifid = getSystemInterfaceId()
|
||||
local is_nedge = ntop.isnEdge()
|
||||
local is_nedge_enterprise = ntop.isnEdgeEnterprise()
|
||||
local is_routing_mode = is_nedge and ntop.isRoutingMode() or false
|
||||
local is_enterprise = ntop.isEnterprise()
|
||||
local is_enterprise_m = ntop.isEnterpriseM()
|
||||
local is_enterprise_l = ntop.isEnterpriseL()
|
||||
local is_enterprise_xl = ntop.isEnterpriseXL()
|
||||
local is_pro = ntop.isPro()
|
||||
local is_appliance = ntop.isAppliance()
|
||||
local is_windows = ntop.isWindows()
|
||||
local is_oem = (info.oem == true)
|
||||
|
||||
local has_ch_support = hasClickHouseSupport()
|
||||
local is_influxdb = (ntop.getPref("ntopng.prefs.timeseries_driver") == "influxdb")
|
||||
local asset_inventory = assetsInventoryEnabled()
|
||||
local is_geoip = ntop.hasGeoIP()
|
||||
local limit_resources = ntop.limitResourcesUsage()
|
||||
local has_dump_cache = ntop.hasDumpCache()
|
||||
local has_local_auth = (ntop.getPref("ntopng.prefs.local.auth_enabled") ~= "0")
|
||||
local has_nanalyst = page_utils.has_nanalyst and page_utils.has_nanalyst()
|
||||
local has_developer_menu = (ntop.getPref("ntopng.prefs.menu_entries.developer") ~= "0")
|
||||
local has_help_menu = (ntop.getPref("ntopng.prefs.menu_entries.help") ~= "0")
|
||||
local is_asn_mode = isASNModeEnabled()
|
||||
|
||||
local is_pcap_dump = interface.isPcapDumpInterface()
|
||||
local is_db_view = interface.isDatabaseViewInterface()
|
||||
local is_viewed_interface = interface.isViewed()
|
||||
local is_zmq_interface = interface.isZMQInterface()
|
||||
local is_loopback = interface.isLoopback()
|
||||
local is_discoverable = interface.isDiscoverableInterface()
|
||||
local has_vlans = interface.hasVLANs()
|
||||
local is_viewed = (ifid_stats.isViewed == true)
|
||||
local is_db_type = (ifid_stats["type"] == "db")
|
||||
local has_hr_flows = (ifid_stats["has_hr_flows"] == true)
|
||||
local has_macs = (ifid_stats.has_macs == true)
|
||||
local has_seen_pods = (ifid_stats.has_seen_pods == true)
|
||||
local has_seen_containers = (ifid_stats.has_seen_containers == true)
|
||||
|
||||
local flowDevices = (interface.getFlowDevices and interface.getFlowDevices()) or {}
|
||||
local sFlowDevices = interface.getSFlowDevices() or {}
|
||||
local obsInfo = interface.getObsPointsInfo() or {}
|
||||
local num_obs_points = obsInfo.numObsPoints or 0
|
||||
|
||||
local infrastructure_view = false
|
||||
infrastructure_view, _ = isInfrastructureView()
|
||||
|
||||
-- capability shortcuts
|
||||
local cap_alerts = auth.has_capability(auth.capabilities.alerts)
|
||||
local cap_checks = auth.has_capability(auth.capabilities.checks)
|
||||
local cap_hist_flows = auth.has_capability(auth.capabilities.historical_flows)
|
||||
local cap_developer = auth.has_capability(auth.capabilities.developer)
|
||||
|
||||
-- computed compound flags
|
||||
local has_exporters = (ifid_stats.type == "zmq") or (ifid_stats.type == "custom") or
|
||||
(is_pro and (table.len(flowDevices) > 0))
|
||||
local service_map_available, _ = behavior_utils.mapsAvailable()
|
||||
local vs_available = vs_utils.is_available()
|
||||
local has_bgp_server = not (isEmptyString(ntop.getPref("ntopng.prefs.bgp_server.ip_address")) or
|
||||
isEmptyString(ntop.getPref("ntopng.prefs.bgp_server.port")))
|
||||
|
||||
local devices_exclusion_enabled = false
|
||||
local checks_config = require("checks").getConfigset()["config"]
|
||||
if checks_config and checks_config["interface"] and
|
||||
checks_config["interface"]["device_connection_disconnection"] and
|
||||
checks_config["interface"]["device_connection_disconnection"]["min"]["enabled"] then
|
||||
devices_exclusion_enabled = true
|
||||
end
|
||||
|
||||
local is_system_ifid = (tonumber(system_ifid) == tonumber(current_ifid))
|
||||
local is_allowed_sys_iface = isAllowedSystemInterface()
|
||||
|
||||
return {
|
||||
-- interface state
|
||||
is_pcap_dump = is_pcap_dump,
|
||||
is_system_interface = is_system_interface,
|
||||
no_system_interface = not is_system_interface,
|
||||
is_db_view_interface = is_db_view,
|
||||
is_viewed = is_viewed,
|
||||
is_viewed_interface = is_viewed_interface,
|
||||
is_zmq_interface = is_zmq_interface,
|
||||
is_loopback_interface = is_loopback,
|
||||
no_discoverable_interface = not is_discoverable,
|
||||
is_asn_mode_enabled = is_asn_mode,
|
||||
no_asn_mode = not is_asn_mode,
|
||||
infrastructure_view = infrastructure_view,
|
||||
is_db_type = is_db_type,
|
||||
no_vlans = not has_vlans,
|
||||
no_macs = not has_macs,
|
||||
no_pods = not has_seen_pods,
|
||||
no_containers = not has_seen_containers,
|
||||
no_obs_points = (num_obs_points == 0),
|
||||
no_sflow_devices = (table.len(sFlowDevices) == 0),
|
||||
no_exporters = not has_exporters,
|
||||
no_hr_flows = not has_hr_flows,
|
||||
no_bgp_server = not has_bgp_server,
|
||||
no_service_map = not service_map_available,
|
||||
no_vs_utils = not vs_available,
|
||||
|
||||
-- user/admin
|
||||
is_admin = is_admin,
|
||||
no_admin = not is_admin,
|
||||
no_local_auth_or_local_user = (not _SESSION["localuser"] and not has_local_auth),
|
||||
|
||||
-- features / capabilities
|
||||
alerts_disabled = not prefs.are_alerts_enabled,
|
||||
no_alerts_cap = not cap_alerts,
|
||||
no_checks_cap = not cap_checks,
|
||||
no_developer_cap = not cap_developer,
|
||||
|
||||
-- license / edition
|
||||
is_pro = is_pro,
|
||||
no_pro = not is_pro,
|
||||
is_nedge = is_nedge,
|
||||
is_nedge_enterprise = is_nedge_enterprise,
|
||||
is_routing_mode = is_routing_mode,
|
||||
is_oem = is_oem,
|
||||
is_windows = is_windows,
|
||||
is_appliance = is_appliance,
|
||||
is_allowed_sys_iface = is_allowed_sys_iface,
|
||||
limit_resource_usage = limit_resources,
|
||||
|
||||
-- enterprise tiers
|
||||
no_enterprise = not is_enterprise,
|
||||
no_enterprise_m = not is_enterprise_m,
|
||||
no_enterprise_l = not is_enterprise_l,
|
||||
no_enterprise_xl = not is_enterprise_xl,
|
||||
no_enterprise_l_or_nedge = (not is_enterprise_l and not is_nedge_enterprise),
|
||||
no_enterprise_m_or_nedge = (not is_enterprise_m and not is_nedge_enterprise),
|
||||
no_enterprise_m_no_windows = (not is_enterprise_m or is_windows),
|
||||
|
||||
-- compound conditions
|
||||
no_ch_support = not has_ch_support,
|
||||
no_influxdb = not is_influxdb,
|
||||
no_asset_inventory = not asset_inventory,
|
||||
no_geoip = not is_geoip,
|
||||
no_dump_cache = not has_dump_cache,
|
||||
no_nanalyst = not has_nanalyst,
|
||||
no_developer_menu = (not has_developer_menu) and is_enterprise_m,
|
||||
no_help_menu = (not has_help_menu) and is_enterprise_m,
|
||||
no_devices_exclusion = not devices_exclusion_enabled,
|
||||
is_system_ifid = is_system_ifid,
|
||||
pro_forced_community = (info["pro.forced_community"] == true),
|
||||
|
||||
-- complex compound
|
||||
no_enterprise_with_ch = not (is_enterprise and has_ch_support),
|
||||
no_enterprise_or_nedge_with_ch_hist = (not is_enterprise and not is_nedge_enterprise) or
|
||||
not cap_hist_flows or not has_ch_support,
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
-- get_dynamic_entries: returns plugin/nedge/appliance-injected menu rows
|
||||
-- for sections that can be extended at runtime.
|
||||
--
|
||||
-- Each returned entry is already resolved: {key, label, url, is_divider}
|
||||
-- Hidden entries are simply omitted.
|
||||
function ntopng_menu_visibility.get_dynamic_entries(section_key, flags, page_utils, http_prefix)
|
||||
local entries = {}
|
||||
|
||||
-- health
|
||||
if section_key == "health" then
|
||||
if page_utils.scripts_menu then
|
||||
for k, entry in pairsByField(page_utils.scripts_menu, "sort_order", rev) do
|
||||
if entry.menu_entry.section == page_utils.menu_sections.health.key then
|
||||
local label_raw = i18n(entry.menu_entry.i18n or entry.menu_entry.key)
|
||||
entries[#entries + 1] = {
|
||||
key = entry.menu_entry.key,
|
||||
label = (type(label_raw) == "string") and label_raw or entry.menu_entry.key,
|
||||
url = http_prefix .. entry.url,
|
||||
is_divider = false,
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- pollers
|
||||
elseif section_key == "pollers" then
|
||||
if page_utils.scripts_menu then
|
||||
for k, entry in pairsByField(page_utils.scripts_menu, "sort_order", rev) do
|
||||
if entry.menu_entry.section == page_utils.menu_sections.pollers.key then
|
||||
local label_raw = i18n(entry.menu_entry.i18n or entry.menu_entry.key)
|
||||
entries[#entries + 1] = {
|
||||
key = entry.menu_entry.key,
|
||||
label = (type(label_raw) == "string") and label_raw or entry.menu_entry.key,
|
||||
url = http_prefix .. entry.url,
|
||||
is_divider = false,
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- system_stats: nedge / appliance entries
|
||||
elseif section_key == "system_stats" then
|
||||
-- script-injected (skip pollers, those live under pollers section)
|
||||
if page_utils.scripts_menu then
|
||||
for k, entry in pairsByField(page_utils.scripts_menu, "sort_order", rev) do
|
||||
if entry.menu_entry.section ~= "pollers" then
|
||||
local label_raw = i18n(entry.menu_entry.i18n or entry.menu_entry.key)
|
||||
entries[#entries + 1] = {
|
||||
key = entry.menu_entry.key,
|
||||
label = (type(label_raw) == "string") and label_raw or entry.menu_entry.key,
|
||||
url = http_prefix .. entry.url,
|
||||
is_divider = false,
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- nedge entries
|
||||
if flags.is_nedge then
|
||||
if #entries > 0 and not flags.no_admin then
|
||||
entries[#entries + 1] = { key = "divider", is_divider = true }
|
||||
end
|
||||
local nedge_rows = {
|
||||
{ key = "system_setup", i18n_key = "nedge.system_setup", url = "/lua/system_setup_ui/interfaces.lua", hidden = flags.no_admin },
|
||||
{ key = "dhcp_static_leases", i18n_key = "nedge.dhcp_static_leases", url = "/lua/pro/nedge/admin/dhcp_leases.lua", hidden = flags.no_admin or not flags.is_routing_mode },
|
||||
{ key = "dhcp_active_leases", i18n_key = "nedge.dhcp_active_leases", url = "/lua/pro/nedge/admin/dhcp_active_leases.lua", hidden = flags.no_admin or not flags.is_routing_mode },
|
||||
{ key = "port_forwarding", i18n_key = "nedge.port_forwarding", url = "/lua/pro/nedge/admin/port_forwarding.lua", hidden = flags.no_admin or not flags.is_routing_mode },
|
||||
{ key = "rules_config", i18n_key = "nedge.rules_config", url = "/lua/pro/nedge/admin/rules_config.lua", hidden = flags.no_admin or not flags.is_routing_mode },
|
||||
{ key = "forwarders_config", i18n_key = "nedge.forwarders_config", url = "/lua/pro/nedge/admin/forwarders_config.lua", hidden = flags.no_admin or not flags.is_routing_mode },
|
||||
}
|
||||
for _, r in ipairs(nedge_rows) do
|
||||
if not r.hidden then
|
||||
local label_raw = i18n(r.i18n_key)
|
||||
entries[#entries + 1] = {
|
||||
key = r.key,
|
||||
label = (type(label_raw) == "string") and label_raw or r.key,
|
||||
url = http_prefix .. r.url,
|
||||
is_divider = false,
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- appliance entries
|
||||
if flags.is_appliance then
|
||||
if #entries > 0 and not flags.no_admin then
|
||||
entries[#entries + 1] = { key = "divider", is_divider = true }
|
||||
end
|
||||
if not flags.no_admin then
|
||||
local label_raw = i18n("nedge.system_setup")
|
||||
entries[#entries + 1] = {
|
||||
key = "system_setup",
|
||||
label = (type(label_raw) == "string") and label_raw or "system_setup",
|
||||
url = http_prefix .. "/lua/system_setup_ui/mode.lua",
|
||||
is_divider = false,
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return entries
|
||||
end
|
||||
|
||||
return ntopng_menu_visibility
|
||||
|
|
@ -929,7 +929,7 @@ end
|
|||
|
||||
-- NOTE: this function must be called after page_utils.print_header_and_set_active_menu_entry
|
||||
function page_utils.print_page_title(title, mini_title)
|
||||
local help_link = page_utils.menu_entries[active_entry].help_link or ""
|
||||
local help_link = (page_utils.menu_entries[active_entry] or {}).help_link or ""
|
||||
print("<header class='mb-3 d-flex align-items-center'>")
|
||||
print("<h2 class='d-inline-block'>" .. title .. "</h2>")
|
||||
if (not isEmptyString(help_link)) then
|
||||
|
|
@ -958,7 +958,8 @@ function page_utils.print_header_and_set_active_menu_entry(entry, i18n_params, a
|
|||
active_sub_entry = entry.subkey
|
||||
end
|
||||
|
||||
page_utils.print_header(alt_title or i18n(entry.i18n_title, i18n_params) or entry.i18n_title)
|
||||
local _title_key = entry.i18n_title
|
||||
page_utils.print_header(alt_title or (_title_key and i18n(_title_key, i18n_params)) or _title_key or entry.key or "")
|
||||
end
|
||||
|
||||
-- #################################
|
||||
|
|
@ -1063,15 +1064,14 @@ function page_utils.print_header(title, addLoginJS)
|
|||
print(http_prefix)
|
||||
print [[/dist/white-mode.css?]]
|
||||
print(static_file_epoch)
|
||||
print [[" rel="stylesheet">]]
|
||||
|
||||
if (dark_mode) then
|
||||
print [[<link href="]]
|
||||
print(http_prefix)
|
||||
print [[/dist/dark-mode.css?]]
|
||||
print(static_file_epoch)
|
||||
print [[" rel="stylesheet">]]
|
||||
end
|
||||
print [[" rel="stylesheet">
|
||||
<link id="dark-mode-css" href="]]
|
||||
print(http_prefix)
|
||||
print [[/dist/dark-mode.css?]]
|
||||
print(static_file_epoch)
|
||||
print [["]]
|
||||
if not dark_mode then print [[ disabled]] end
|
||||
print [[ rel="stylesheet">]]
|
||||
|
||||
if (ntop.isPro() or ntop.isnEdge()) and ntop.exists(dirs.installdir .. "/httpdocs/img/custom_favicon.ico") then
|
||||
favicon_path = http_prefix .. "/img/custom_favicon.ico"
|
||||
|
|
@ -1241,8 +1241,8 @@ end
|
|||
-- #################################
|
||||
|
||||
function page_utils.get_navbar_context(title, base_url, items_table, label_url, back_url)
|
||||
local help_link = page_utils.menu_entries[active_entry].help_link or nil
|
||||
local icon = page_utils.menu_sections[active_section].icon or ""
|
||||
local help_link = (page_utils.menu_entries[active_entry] or {}).help_link or nil
|
||||
local icon = (page_utils.menu_sections[active_section] or {}).icon or ""
|
||||
|
||||
local navbar = {
|
||||
main_icon = icon,
|
||||
|
|
@ -1259,8 +1259,8 @@ end
|
|||
-- #################################
|
||||
|
||||
function page_utils.get_new_navbar_context(title, base_url, items_table, label_url, back_url)
|
||||
local help_link = page_utils.menu_entries[active_entry].help_link or nil
|
||||
local icon = page_utils.menu_sections[active_section].icon or ""
|
||||
local help_link = (page_utils.menu_entries[active_entry] or {}).help_link or nil
|
||||
local icon = (page_utils.menu_sections[active_section] or {}).icon or ""
|
||||
|
||||
local navbar = {
|
||||
main_title = {
|
||||
|
|
@ -1278,8 +1278,8 @@ end
|
|||
-- #################################
|
||||
|
||||
function page_utils.print_navbar(title, base_url, items_table, label_url, back_url, end_items)
|
||||
local help_link = page_utils.menu_entries[active_entry].help_link or nil
|
||||
local icon = page_utils.menu_sections[active_section].icon or ""
|
||||
local help_link = (page_utils.menu_entries[active_entry] or {}).help_link or nil
|
||||
local icon = (page_utils.menu_sections[active_section] or {}).icon or ""
|
||||
|
||||
local context = {
|
||||
navbar = {
|
||||
|
|
@ -1295,272 +1295,6 @@ function page_utils.print_navbar(title, base_url, items_table, label_url, back_u
|
|||
print(template_utils.gen("pages/components/page-navbar.template", context))
|
||||
end
|
||||
|
||||
-- #################################
|
||||
local menubar_structure = {}
|
||||
|
||||
function page_utils.init_menubar()
|
||||
menubar_structure = {}
|
||||
end
|
||||
|
||||
-- #################################
|
||||
|
||||
function page_utils.add_menubar_section(section)
|
||||
menubar_structure[#menubar_structure + 1] = section
|
||||
end
|
||||
|
||||
-- #################################
|
||||
|
||||
local function print_submenu(section, container_list_name)
|
||||
local active_subpage = page_utils.get_active_entry()
|
||||
local active_subsubpage = page_utils.get_active_sub_entry()
|
||||
local section_key = section.section.key
|
||||
local section_id = section_key .. "-submenu"
|
||||
local list_name = section_id .. "-list"
|
||||
|
||||
print [[<div data-parent='#]]
|
||||
print(container_list_name)
|
||||
print [[' class='collapse side-collapse' id=']]
|
||||
print(section_id)
|
||||
print [['>
|
||||
<ul class='nav flex-column' id=']]
|
||||
print(list_name)
|
||||
print [['>
|
||||
]]
|
||||
|
||||
for _, section_entry in ipairs(section.entries) do
|
||||
if not section_entry.hidden then
|
||||
if section_entry.custom then
|
||||
print(section_entry.custom)
|
||||
elseif section_entry.entry.key == "divider" then
|
||||
print [[
|
||||
<li class="dropdown-divider"></li>
|
||||
]]
|
||||
else
|
||||
local external_link = false
|
||||
local section_has_submenu = section_entry.entries
|
||||
local active = false
|
||||
|
||||
if section_entry.entry and (section_entry.entry.key == active_subpage and
|
||||
(not section_entry.entry.subkey or section_entry.entry.subkey == active_subsubpage)) then
|
||||
active = true
|
||||
end
|
||||
|
||||
if section_entry.url:starts("http") then
|
||||
-- Absolute (external) url
|
||||
|
||||
external_link = true
|
||||
end
|
||||
print [[
|
||||
<li class=']]
|
||||
if active then
|
||||
print("active")
|
||||
end
|
||||
print [['>
|
||||
|
||||
<a class="]]
|
||||
if section_has_submenu then
|
||||
print [[submenu ]]
|
||||
end
|
||||
if active then
|
||||
print [[active ]]
|
||||
end
|
||||
if external_link == true then
|
||||
print [[ntopng-external-link ]]
|
||||
end
|
||||
print [["]]
|
||||
|
||||
if section_has_submenu then
|
||||
print [[ data-bs-toggle="collapse" ]]
|
||||
end
|
||||
print [[href="]]
|
||||
if section_has_submenu then
|
||||
local submenu_section_key = section_entry.section.key
|
||||
local submenu_section_id = submenu_section_key .. "-submenu"
|
||||
print("#" .. submenu_section_id)
|
||||
else
|
||||
if external_link then
|
||||
print(section_entry.url)
|
||||
else
|
||||
print(ntop.getHttpPrefix() .. section_entry.url)
|
||||
end
|
||||
end
|
||||
print [["]]
|
||||
|
||||
if section_entry.entry.is_modal then
|
||||
print(' data-bs-toggle="modal"')
|
||||
end
|
||||
|
||||
if external_link then
|
||||
-- Open in a new page
|
||||
print(' target="_blank"')
|
||||
end
|
||||
|
||||
print [[>]]
|
||||
print(i18n(section_entry.entry.i18n_title) or section_entry.entry.i18n_title)
|
||||
if section_entry.suffix then
|
||||
print(section_entry.suffix)
|
||||
end
|
||||
if external_link then
|
||||
print(" <i class='fas fa-external-link-alt'></i>")
|
||||
end
|
||||
|
||||
print [[</a>]]
|
||||
|
||||
if section_has_submenu then
|
||||
print_submenu(section_entry, list_name)
|
||||
end
|
||||
|
||||
print [[</li>
|
||||
]]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
print [[
|
||||
</ul>
|
||||
</div>
|
||||
]]
|
||||
end
|
||||
|
||||
-- #################################
|
||||
|
||||
local function print_section(section, list_name)
|
||||
local active_page = page_utils.get_active_section()
|
||||
local show_section = false
|
||||
local section_has_submenu = (section.entries and #section.entries > 0)
|
||||
|
||||
if (not section.hidden) then
|
||||
if not section_has_submenu then
|
||||
show_section = true
|
||||
else
|
||||
-- The section is shown only if at least one of its sub entries
|
||||
-- is shown
|
||||
for _, section_entry in pairs(section.entries or {}) do
|
||||
if not section_entry.hidden then
|
||||
show_section = true
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if show_section then
|
||||
local section_key = section.section.key
|
||||
local section_id = section_key .. "-submenu"
|
||||
|
||||
print [[
|
||||
<li class="nav-item ]]
|
||||
print(active_page == section_key and 'active' or '')
|
||||
print [[">
|
||||
<a class="]]
|
||||
|
||||
if section_has_submenu then
|
||||
print [[submenu ]]
|
||||
end
|
||||
|
||||
if active_page == section_key then
|
||||
print [[active ]]
|
||||
end
|
||||
|
||||
print [[" ]]
|
||||
|
||||
if section_has_submenu then
|
||||
print [[ data-bs-toggle="collapse" ]]
|
||||
end
|
||||
|
||||
print [[href="]]
|
||||
|
||||
if section.url then
|
||||
print(ntop.getHttpPrefix() .. section.url)
|
||||
else
|
||||
print("#" .. section_id)
|
||||
end
|
||||
|
||||
print [[">
|
||||
<span class="]]
|
||||
print(section.section.icon)
|
||||
print [["></span> ]]
|
||||
print(i18n(section.section.i18n_title))
|
||||
print [[
|
||||
</a>]]
|
||||
|
||||
if section_has_submenu then
|
||||
print_submenu(section, list_name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- #################################
|
||||
|
||||
function page_utils.print_menubar()
|
||||
local is_system_interface = page_utils.is_system_view()
|
||||
local logo_path = nil
|
||||
local list_name = "sidebar"
|
||||
|
||||
if (ntop.isPro() or ntop.isnEdge()) and ntop.exists(dirs.installdir .. "/httpdocs/img/custom_logo.png") then
|
||||
logo_path = ntop.getHttpPrefix() .. "/img/custom_logo.png"
|
||||
end
|
||||
|
||||
local navbar_style = _POST["toggle_theme"] or ntop.getPref("ntopng.user." .. _SESSION["user"] .. ".theme")
|
||||
|
||||
if ((navbar_style == nil) or (navbar_style == "white") or (navbar_style == "")) then
|
||||
navbar_style = "default"
|
||||
end
|
||||
|
||||
if (navbar_style == "default") then
|
||||
navbar_style = "dark"
|
||||
end
|
||||
|
||||
print('<nav id="n-sidebar" class="bg-' .. navbar_style .. ' py-0 px-2">')
|
||||
print([[
|
||||
<div class="mobile-menu-button d-flex">
|
||||
<form class='w-100' method='post' action="/?">
|
||||
<input hidden name='switch_interface' value='1' />
|
||||
<input hidden name='csrf' value=']] .. ntop.getRandomCSRFValue() .. [[' />
|
||||
]] .. template_utils.gen("pages/components/ifaces-select.template", {
|
||||
ifaces = page_utils.get_interface_list(),
|
||||
is_sys_iface = is_system_interface
|
||||
}) .. [[
|
||||
</form>
|
||||
<button data-bs-toggle="]] .. list_name .. [[" class='ms-5 my-auto btn btn-close'></button>
|
||||
</div>
|
||||
<div class="mobile-menu-stats">
|
||||
]])
|
||||
|
||||
-- the network load will not be displayed in system view mode
|
||||
if not is_system_interface then
|
||||
print([[<div class="network-load mb-2 w-100"></div>]])
|
||||
end
|
||||
|
||||
print([[
|
||||
<div class="info-stats w-100">]] .. page_utils.generate_info_stats() .. [[</div>
|
||||
</div>
|
||||
]])
|
||||
print("<h3 class='muted'><a href='" .. ntop.getHttpPrefix() .. "/'>")
|
||||
|
||||
if (logo_path ~= nil) then
|
||||
print("<img class=\"logo-brand\" height=\"52px\" src=\"" .. logo_path .. "\" alt='Custom Logo' />")
|
||||
else
|
||||
print(addLogoSvg())
|
||||
end
|
||||
|
||||
print([[
|
||||
</a>
|
||||
</h3>
|
||||
|
||||
<ul class="nav-side mb-4" id=']] .. list_name .. [['>
|
||||
]])
|
||||
|
||||
for _, section in ipairs(menubar_structure) do
|
||||
print_section(section, list_name)
|
||||
end
|
||||
|
||||
print([[
|
||||
</ul>
|
||||
</nav>
|
||||
]])
|
||||
end
|
||||
|
||||
-- ##############################################
|
||||
|
||||
function page_utils.get_interface_list()
|
||||
|
|
|
|||
|
|
@ -121,6 +121,7 @@ local function get_schema_info(schema_name)
|
|||
info.series_meta[series_id] = {
|
||||
label = smeta.label or series_id,
|
||||
invert_direction = smeta.invert_direction or false,
|
||||
color = smeta.color,
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
@ -224,6 +225,9 @@ if queries and type(queries) == "table" then
|
|||
if smeta then
|
||||
serie.label = smeta.label
|
||||
serie.invert_direction = smeta.invert_direction
|
||||
if smeta.color then
|
||||
serie.color = smeta.color
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue