From 6e6bb7287c81fce247f4eb42b0ecb79957ce3588 Mon Sep 17 00:00:00 2001 From: GabrieleDeri <33870399+DGabri@users.noreply.github.com> Date: Mon, 22 Jun 2026 18:19:15 +0200 Subject: [PATCH] Ported menu, footer and topbar to vuejs (#10480) * Ported menu, footer and topbar to vuejs * Update dist --- assets/third-party-npm.js | 3 +- attic/scripts/lua/inc/footer.lua | 874 ++++++++ attic/scripts/lua/inc/menu.lua | 1431 ++++++++++++ http_src/components/sidebar/sidebar.scss | 2 +- http_src/extensions/extensions.js | 2 +- .../views/private/clients/white-mode.scss | 2 +- http_src/vue/app-footer.vue | 316 +++ http_src/vue/app-shell.vue | 1967 +++++++++++++++++ http_src/vue/components/search-box.vue | 86 +- http_src/vue/ntop_vue.js | 12 +- httpdocs/dist | 2 +- httpdocs/misc/menu_definition.json | 774 +++++++ package.json | 5 +- scripts/locales/en.lua | 23 + scripts/lua/flow_details.lua | 2 +- scripts/lua/inc/footer.lua | 906 +------- scripts/lua/inc/menu.lua | 1307 +---------- .../lua/modules/ntopng_menu_visibility.lua | 284 +++ scripts/lua/modules/page_utils.lua | 300 +-- scripts/lua/rest/v2/get/timeseries/batch.lua | 4 + 20 files changed, 5859 insertions(+), 2443 deletions(-) create mode 100644 attic/scripts/lua/inc/footer.lua create mode 100644 attic/scripts/lua/inc/menu.lua create mode 100644 http_src/vue/app-footer.vue create mode 100644 http_src/vue/app-shell.vue create mode 100644 httpdocs/misc/menu_definition.json create mode 100644 scripts/lua/modules/ntopng_menu_visibility.lua diff --git a/assets/third-party-npm.js b/assets/third-party-npm.js index f7a9898516..4f9242a9e9 100644 --- a/assets/third-party-npm.js +++ b/assets/third-party-npm.js @@ -70,5 +70,4 @@ import * as d3v7 from "d3v7"; window.d3v7 = { ...d3v7 -}; - +}; \ No newline at end of file diff --git a/attic/scripts/lua/inc/footer.lua b/attic/scripts/lua/inc/footer.lua new file mode 100644 index 0000000000..4c4363db09 --- /dev/null +++ b/attic/scripts/lua/inc/footer.lua @@ -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 ([[ + --
+ -- + -- ]] + + -- else -- info.oem + -- print[[
+ -- + --
| ]] print(i18n("about.uptime")) print[[:
+ --
+ --
]] +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([[ + + ]]) + end +end + +-- Dismiss Notification Code and Toggle Dark theme +print([[ + +]]) + +-- 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 [[ + + ]] +end + +-- render switchable system view +print([[ + +]]) + +print [[ + +]]) + +-- ###################################### + +if have_nedge then + print [[
+ + +
+
+ + +
]] + + 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 [[ + + ]] + +-- Updates submenu +if hasSoftwareUpdatesSupport() then + + -- Updates check + print [[ + +]] +end + +-- close wrapper +print [[ + + + + ]] diff --git a/attic/scripts/lua/inc/menu.lua b/attic/scripts/lua/inc/menu.lua new file mode 100644 index 0000000000..1afc0787dd --- /dev/null +++ b/attic/scripts/lua/inc/menu.lua @@ -0,0 +1,1431 @@ +-- +-- (C) 2013-26 - ntop.org +-- +local dirs = ntop.getDirs() +package.path = dirs.installdir .. "/pro/scripts/lua/enterprise/modules/?.lua;" .. package.path +package.path = dirs.installdir .. "/scripts/lua/modules/?.lua;" .. package.path +package.path = dirs.installdir .. "/scripts/lua/modules/toasts/?.lua;" .. package.path +package.path = dirs.installdir .. "/scripts/lua/modules/vulnerability_scan/?.lua;" .. package.path + +if ((dirs.scriptdir ~= nil) and (dirs.scriptdir ~= "")) then + package.path = dirs.scriptdir .. "/lua/modules/?.lua;" .. package.path +end +require "lua_utils" +require "check_redis_prefs" + +local recording_utils = require "recording_utils" +local format_utils = require "format_utils" +local page_utils = require("page_utils") +local toasts_manager = require("toasts_manager") +local blog_utils = require("blog_utils") +local template_utils = require "template_utils" +local auth = require "auth" +local vs_utils = require "vs_utils" +local behavior_utils = require("behavior_utils") +local checks = require "checks" + +local has_local_auth = (ntop.getPref("ntopng.prefs.local.auth_enabled") ~= '0') +local has_help_enabled = (ntop.getPref("ntopng.prefs.menu_entries.help") ~= '0') +local has_developer_enabled = (ntop.getPref("ntopng.prefs.menu_entries.developer") ~= '0') + +-- ************************************ + +local prefs = ntop.getPrefs() + +local asset_inventory_enabled = assetsInventoryEnabled() + +local is_influxdb_enabled = ntop.getPref("ntopng.prefs.timeseries_driver") == "influxdb" +local has_ch_support = hasClickHouseSupport() + +-- user data +local is_admin = isAdministrator() +local session_user = _SESSION['user'] + +-- interface +local ifid_stats = interface.getStats() +local ifId = ifid_stats.id +local has_vlans = interface.hasVLANs() +local is_allowed_sys_interface = isAllowedSystemInterface() +local system_ifid = getSystemInterfaceId() +local interface_id = ifid_stats.id +local random_csrf = ntop.getRandomCSRFValue() +local is_system_interface = toboolean(page_utils.is_system_view()) +local is_pcap_dump = interface.isPcapDumpInterface() +local is_packet_interface = interface.isPacketInterface() +local is_db_view_interface = interface.isDatabaseViewInterface() +local is_viewed = ifid_stats.isViewed +local is_sub_interface = interface.isSubInterface() +local is_zmq_interface = interface.isZMQInterface() +local is_discoverable_interface = interface.isDiscoverableInterface() +local is_loopback_interface = interface.isLoopback() +local is_viewed_interface = interface.isViewed() + +local iface_names = interface.getIfNames() +local current_ifid = interface.getId() + +-- compute number of interfaces +num_ifaces = 0 +for k, v in pairs(iface_names) do + num_ifaces = num_ifaces + 1 +end + +-- nedge versions +local is_nedge = ntop.isnEdge() +-- for ntopng is always false +local is_routing_mode = false +if is_nedge then + is_routing_mode = ntop.isRoutingMode() +end +local is_nedge_enterprise = ntop.isnEdgeEnterprise() + +-- ntopng info/version +local info = ntop.getInfo() +local is_pro = ntop.isPro() +local is_enterprise_M = ntop.isEnterpriseM() +local is_enterprise = ntop.isEnterprise() +local is_enterprise_L = ntop.isEnterpriseL() +local is_enterprise_XL = ntop.isEnterpriseXL() +local is_appliance = ntop.isAppliance() +local is_windows = ntop.isWindows() + +-- dependencies / additional features +local is_geoip_enabled = ntop.hasGeoIP() +local limit_resource_usage = ntop.limitResourcesUsage() +local is_vs_utils_available = vs_utils.is_available() +local is_asn_mode_enabled = isASNModeEnabled() + +local has_dump_cache = ntop.hasDumpCache() +local is_no_login_user = isNoLoginUser() +local http_prefix = ntop.getHttpPrefix() + +-- exporters +local flowDevices = (interface.getFlowDevices and interface.getFlowDevices()) or {} +local sFlowDevices = interface.getSFlowDevices() or {} +local obsPointsInfo = interface.getObsPointsInfo() or {} +local obs_points = obsPointsInfo["ObsPoints"] or {} +local num_obs_points = obsPointsInfo.numObsPoints or 0 + +local checks_config = checks.getConfigset()["config"] +local interface_config = checks_config["interface"] +local flow_config = checks_config["flow"] + +-- Check if some alerts are enabled +local devices_exclusion_enabled = false +local acl_violation_enabled = false + +if (interface_config) then + -- Interface alerts + if (interface_config["device_connection_disconnection"]) and + (interface_config["device_connection_disconnection"]["min"]["enabled"]) then + devices_exclusion_enabled = true + end +end + +-- Infrastructure +local infrastructure_view = false +local infrastructure_instances = {} +infrastructure_view, infrastructure_instances = isInfrastructureView() + +-- ************************************ + +local observationPointId = nil +print([[ +
+]]) + +print [[ +]] + +-- NOTE: see sidebar.js for the client logic +page_utils.init_menubar() + +if is_nedge then + dofile(dirs.installdir .. "/pro/scripts/lua/nedge/inc/menubar.lua") +else + -- ############################################## + + -- Dashboard + page_utils.add_menubar_section({ + section = page_utils.menu_sections.dashboard, + hidden = is_pcap_dump or is_system_interface or is_db_view_interface, + entries = {{ + entry = page_utils.menu_entries.traffic_dashboard, + url = '/lua/index.lua' + }, { + entry = page_utils.menu_entries.assets_dashboard, + hidden = (not has_ch_support) or (not asset_inventory_enabled) or (not is_enterprise_L), + url = "/lua/pro/assets_dashboard.lua" + }, { + entry = page_utils.menu_entries.traffic_report, + hidden = not (is_enterprise and has_ch_support) or infrastructure_view or is_viewed, -- disable if interface is viewed + url = "/lua/pro/report.lua" + }, { + entry = page_utils.menu_entries.hr_chart, + hidden = (not is_enterprise_M) or (not has_ch_support) or (not ifid_stats["has_hr_flows"]), + url = "/lua/pro/hr_chart.lua" + }} + }) + + -- ############################################## + + -- Active Monitoring + -- The Monitoring entry are used to go to the System interface pages + -- without using the Interface dropdown. The section is hidden + -- in system interface. + -- Interface is not system + page_utils.add_menubar_section({ + section = page_utils.menu_sections.monitoring, + hidden = is_system_interface or not is_admin, + entries = {{ + entry = page_utils.menu_entries.active_monitoring, + hidden = is_windows, + url = "/lua/active_monitoring.lua" + }, { + entry = page_utils.menu_entries.network_discovery, + hidden = not is_discoverable_interface or is_windows or is_loopback_interface or limit_resource_usage or + infrastructure_view, + url = "/lua/discover.lua" + }, { + entry = page_utils.menu_entries.infrastructure_dashboard, + hidden = (not is_enterprise_L and not is_nedge_enterprise) or not is_admin, + url = '/lua/pro/enterprise/infrastructure_config.lua' + }, { + entry = page_utils.menu_entries.snmp_monitoring, + hidden = (not is_enterprise_M and not is_nedge_enterprise), + url = "/lua/pro/enterprise/snmpdevices_stats.lua" + }, { + entry = page_utils.menu_entries.vulnerability_scan, + url = '/lua/vulnerability_scan.lua', + hidden = not is_vs_utils_available or is_zmq_interface + }} + }) + + -- ############################################## + + -- Alerts + page_utils.add_menubar_section({ + section = page_utils.menu_sections.alerts, + hidden = not prefs.are_alerts_enabled or not auth.has_capability(auth.capabilities.alerts) or + is_db_view_interface or infrastructure_view, + entries = {{ + entry = page_utils.menu_entries.alerts_list, + url = "/lua/alert_stats.lua" + }, { + entry = page_utils.menu_entries.alerts_graph, + url = "/lua/pro/alerts_graph.lua", + hidden = (not is_enterprise_L and not is_nedge_enterprise) or (not has_ch_support) or (is_pcap_dump) + }, { + entry = page_utils.menu_entries.alerts_geomap, + url = "/lua/pro/alerts_geomap.lua", + hidden = true or (not is_enterprise_XL) + }, { + entry = page_utils.menu_entries.alerts_analysis, + url = "/lua/pro/enterprise/alerts_analysis.lua", + hidden = (not is_enterprise) or is_pcap_dump + }, { + entry = page_utils.menu_entries.divider + }, { + entry = page_utils.menu_sections.notifications, + hidden = (not is_admin) or is_pcap_dump, + url = '/lua/admin/endpoint_notifications_list.lua' + }} + }) + + -- ############################################## + + -- Flows + page_utils.add_menubar_section({ + section = page_utils.menu_sections.flows, + hidden = is_asn_mode_enabled or (is_system_interface or infrastructure_view), + entries = {{ + entry = page_utils.menu_entries.active_flows, + url = "/lua/flows_stats.lua" + }, { + entry = page_utils.menu_entries.db_explorer, + hidden = (not is_enterprise and not is_nedge_enterprise) or + not auth.has_capability(auth.capabilities.historical_flows) or ifid_stats.isViewed or ifid_stats['type'] == + 'db' or not has_ch_support, + url = "/lua/pro/db_search.lua" + }, { + entry = page_utils.menu_entries.server_ports, + url = '/lua/server_ports.lua', + hidden = not is_enterprise_L + }, { + entry = page_utils.menu_entries.divider + }, { + entry = page_utils.menu_entries.bgp_looking_glass, + url = '/lua/bgp_looking_glass.lua', + hidden = isEmptyString(ntop.getPref("ntopng.prefs.bgp_server.ip_address")) or + isEmptyString(ntop.getPref('ntopng.prefs.bgp_server.port')) + + }} + }) + + -- ############################################## + -- chatbot, hide if viewed interface or system or not enterprise xl + page_utils.add_menubar_section({ + section = page_utils.menu_sections.nanalyst, + hidden = not page_utils.has_nanalyst(), + entries = {{ + entry = page_utils.menu_entries.nanalyst, + url = '/lua/pro/nanalyst.lua' + },{ + entry = page_utils.menu_entries.ai_policy, + url = '/lua/pro/ai_policy.lua' + }, { + entry = page_utils.menu_entries.analyst_pipeline, + url = '/lua/pro/analyst_pipeline.lua' + }, { + entry = page_utils.menu_entries.ai_usage_stats, + url = '/lua/pro/ai_stats.lua' + },{ + entry = page_utils.menu_entries.ai_audit, + url = '/lua/pro/ai_audit.lua' + }, + + }}) + + -- ############################################## + -- Views menu entry for ASN Mode + -- Group hosts, flows + + page_utils.add_menubar_section({ + section = page_utils.menu_sections.views, + hidden = not is_asn_mode_enabled or (is_system_interface or is_viewed or infrastructure_view), + entries = {{ + entry = page_utils.menu_entries.hosts_asn_mode, + url = '/lua/hosts_stats.lua' + }, { + entry = page_utils.menu_entries.active_flows_asn_mode, + url = "/lua/flows_stats.lua" + }, { + entry = page_utils.menu_entries.historical_flows_asn_mode, + hidden = (not is_enterprise and not is_nedge_enterprise) or + not auth.has_capability(auth.capabilities.historical_flows) or ifid_stats.isViewed or ifid_stats['type'] == + 'db' or not has_ch_support, + url = "/lua/pro/db_search.lua" + }, { + entry = page_utils.menu_entries.server_ports_asn_mode, + url = '/lua/server_ports.lua', + hidden = not is_enterprise_L + }, { + entry = page_utils.menu_entries.divider + }, { + entry = page_utils.menu_entries.bgp_looking_glass, + url = '/lua/bgp_looking_glass.lua', + hidden = isEmptyString(ntop.getPref("ntopng.prefs.bgp_server.ip_address")) or + isEmptyString(ntop.getPref('ntopng.prefs.bgp_server.port')) + + }} + }) + -- ############################################## + -- Hosts + + page_utils.add_menubar_section({ + section = page_utils.menu_sections.hosts, + hidden = is_system_interface or is_viewed or infrastructure_view or is_asn_mode_enabled, + entries = {{ + entry = page_utils.menu_entries.hosts, + url = '/lua/hosts_stats.lua' + }, { + entry = page_utils.menu_entries.devices, + hidden = (not ifid_stats.has_macs), + url = '/lua/macs_stats.lua' + }, { + entry = page_utils.menu_entries.divider + }, { + hidden = not (is_enterprise_M and not is_windows) or not asset_inventory_enabled, + entry = page_utils.menu_entries.assets, + url = '/lua/pro/assets.lua' + }} + }) + + -- ############################################## + + -- Exporters + + local has_exporters = (ifid_stats.type == "zmq") or (ifid_stats.type == "custom") or + (is_pro and (table.len(flowDevices) > 0)) + + page_utils.add_menubar_section({ + section = page_utils.menu_sections.collection, + hidden = not has_exporters or not is_enterprise_M or is_system_interface or infrastructure_view, + entries = {{ + entry = page_utils.menu_entries.sflow_exporters, + hidden = table.len(sFlowDevices) == 0, + url = '/lua/pro/enterprise/sflowdevices_stats.lua' + }, { + entry = page_utils.menu_entries.nprobe, + url = '/lua/pro/enterprise/nprobe.lua' + }, { + entry = page_utils.menu_entries.exporters_interfaces_stats, + url = '/lua/pro/exporters_interfaces_stats.lua' + }, { + entry = page_utils.menu_entries.observation_points, + hidden = (num_obs_points) == 0, + url = '/lua/pro/enterprise/observation_points.lua' + }} + }) +end + +-- ############################################## + +-- Maps + +local service_map_available = false +local asset_map_available = is_enterprise_XL + +service_map_available, _ = behavior_utils.mapsAvailable() + +page_utils.add_menubar_section({ + section = page_utils.menu_sections.maps, + hidden = is_system_interface or is_viewed or infrastructure_view, + entries = {{ + entry = page_utils.menu_entries.analysis_map, + hidden = not service_map_available, + url = '/lua/pro/enterprise/network_maps.lua?map=service_map' + }, { + entry = page_utils.menu_entries.geo_map, + hidden = is_loopback_interface or not is_geoip_enabled, + url = '/lua/hosts_geomap.lua' + }, { + entry = page_utils.menu_entries.hosts_map, + hidden = not is_enterprise or is_asn_mode_enabled, + url = '/lua/pro/enterprise/hosts_map.lua' + }} +}) + +-- ############################################## + +-- Interface +page_utils.add_menubar_section({ + hidden = is_system_interface or infrastructure_view, + section = page_utils.menu_sections.if_stats, + entries = {{ + entry = page_utils.menu_entries.interface, + url = "/lua/if_stats.lua" + }, { + entry = page_utils.menu_entries.divider + }, { + entry = page_utils.menu_entries.networks, + hidden = is_viewed_interface, + url = '/lua/network_stats.lua' + }, { + entry = page_utils.menu_entries.host_pools, + hidden = is_nedge, + url = '/lua/pool_stats.lua' + }, { + entry = page_utils.menu_entries.autonomous_systems, + hidden = (not is_geoip_enabled) or is_viewed_interface, + url = '/lua/as_stats.lua' + }, { + entry = page_utils.menu_entries.countries, + hidden = not is_geoip_enabled or is_viewed_interface, + url = '/lua/country_stats.lua' + }, { + entry = page_utils.menu_entries.vlans, + hidden = not has_vlans or is_viewed_interface, + url = '/lua/vlan_stats.lua' + }, { + entry = page_utils.menu_entries.pods, + hidden = not ifid_stats.has_seen_pods, + url = '/lua/pods_stats.lua' + }, { + entry = page_utils.menu_entries.containers, + hidden = not ifid_stats.has_seen_containers, + url = '/lua/containers_stats.lua' + }} +}) + +-- ############################################## + +-- System Health + +local health_entries = {{ + entry = page_utils.menu_entries.system_status, + url = '/lua/system_stats.lua' +}, { + entry = page_utils.menu_entries.interfaces_status, + url = '/lua/system_interfaces_stats.lua' +}, { + entry = page_utils.menu_entries.influxdb_status, + url = '/lua/monitor/influxdb_monitor.lua', + hidden = not is_influxdb_enabled +}, { + entry = page_utils.menu_entries.redis_status, + url = '/lua/monitor/redis_monitor.lua', + hidden = false -- TODO: add a check for redis monitoring status +}, { + entry = page_utils.menu_entries.clickhouse_status, + url = '/lua/pro/enterprise/monitor/clickhouse_monitor.lua', + hidden = not has_ch_support +}} + +-- Add script entries relative to system health (e.g., redis) ... +for k, entry in pairsByField(page_utils.scripts_menu, "sort_order", rev) do + -- NOTE: match on the health key to only pick the right subset of entries + if entry.menu_entry.section == page_utils.menu_sections.health.key then + health_entries[#health_entries + 1] = { + entry = page_utils.menu_entries[entry.menu_entry.key], + url = entry.url + } + end +end + +page_utils.add_menubar_section({ + hidden = not is_system_interface, + section = page_utils.menu_sections.health, + entries = health_entries +}) + +-- ############################################## + +-- Pollers (e.g., SNMP, active monitoring) +-- System interface menu + +local poller_entries = {{ + entry = page_utils.menu_entries.divider +}, { + hidden = not asset_inventory_enabled, + entry = page_utils.menu_entries.assets_snmp, + url = '/lua/pro/assets.lua' +}, { + entry = page_utils.menu_entries.snmp, + hidden = not is_system_interface or (not is_enterprise_M and not is_nedge_enterprise), + url = "/lua/pro/enterprise/snmpdevices_stats.lua" +}, { + entry = page_utils.menu_entries.active_monitoring, + hidden = not is_system_interface, + url = "/lua/active_monitoring.lua" +}, { + entry = page_utils.menu_entries.infrastructure_dashboard, + hidden = (not is_enterprise_L and not is_nedge_enterprise) or not is_admin, + url = '/lua/pro/enterprise/infrastructure_config.lua' +}} + +-- Add script entries relative to pollers (e.g., active monitoring) ... +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 + poller_entries[#poller_entries + 1] = { + entry = page_utils.menu_entries[entry.menu_entry.key], + url = entry.url + } + end +end + +page_utils.add_menubar_section({ + hidden = not is_system_interface, + section = page_utils.menu_sections.pollers, + entries = poller_entries +}) + +-- ############################################## + +-- System + +local system_entries = {} + +-- Add script entries... +for k, entry in pairsByField(page_utils.scripts_menu, "sort_order", rev) do + -- Skip pollers, they've already been set under pollers section + if not entry.menu_entry.section == "pollers" then + system_entries[#system_entries + 1] = { + entry = page_utils.menu_entries[entry.menu_entry.key], + url = entry.url + } + end +end + +-- Possibly add nEdge entries +if is_nedge or is_appliance then + -- Possibly add a divider if system_entries already contain elements + if #system_entries > 0 then + system_entries[#system_entries + 1] = { + entry = page_utils.menu_entries.divider, + hidden = not is_admin + } + end +end + +if is_nedge then + for _, entry in ipairs({{ + entry = page_utils.menu_entries.system_setup, + hidden = not is_admin, + url = '/lua/system_setup_ui/interfaces.lua' + }, { + entry = page_utils.menu_entries.dhcp_static_leases, + hidden = not is_admin or not is_routing_mode, + url = '/lua/pro/nedge/admin/dhcp_leases.lua' + }, { + entry = page_utils.menu_entries.dhcp_active_leases, + hidden = not is_admin or not is_routing_mode, + url = '/lua/pro/nedge/admin/dhcp_active_leases.lua' + }, { + entry = page_utils.menu_entries.port_forwarding, + hidden = not is_admin or not is_routing_mode, + url = '/lua/pro/nedge/admin/port_forwarding.lua' + }, { + entry = page_utils.menu_entries.rules_config, + hidden = not is_admin or not is_routing_mode, + url = '/lua/pro/nedge/admin/rules_config.lua' + }, { + entry = page_utils.menu_entries.forwarders_config, + hidden = not is_admin or not is_routing_mode, + url = '/lua/pro/nedge/admin/forwarders_config.lua' + }}) do + system_entries[#system_entries + 1] = entry + end +end + +if is_appliance then + for _, entry in ipairs({{ + entry = page_utils.menu_entries.system_setup, + hidden = not is_admin, + url = '/lua/system_setup_ui/mode.lua' + }}) do + system_entries[#system_entries + 1] = entry + end +end + +if #system_entries > 0 then + page_utils.add_menubar_section({ + section = page_utils.menu_sections.system_stats, + hidden = not is_allowed_sys_interface or not is_system_interface, + entries = system_entries + }) +end + +-- ############################################## + +-- Pools + +page_utils.add_menubar_section({ + hidden = true, -- Always add the pools menu (moved to the Hosts submenu) + section = page_utils.menu_sections.pools, + entries = {{ + entry = page_utils.menu_entries.manage_pools, + hidden = not is_admin, + url = '/lua/admin/manage_pools.lua' + }, { + entry = page_utils.menu_entries.host_members, + hidden = not is_admin, + url = '/lua/admin/manage_host_members.lua' + }} +}) + +-- ############################################## + +-- Notifications +page_utils.add_menubar_section({ + section = page_utils.menu_sections.notifications, + hidden = not is_system_interface or not is_admin, + url = '/lua/admin/endpoint_notifications_list.lua' +}) + +-- ############################################## + +local scripts_config_url = "/lua/admin/edit_configset.lua?subdir=all" +if tonumber(system_ifid) == tonumber(current_ifid) then + scripts_config_url = "/lua/admin/edit_configset.lua?subdir=system" +end + +-- Rules & Policies +page_utils.add_menubar_section({ + section = page_utils.menu_sections.policies, + hidden = infrastructure_view or not is_admin, + entries = {{ + entry = page_utils.menu_entries.access_control_list, + hidden = not is_admin or not is_enterprise_L or is_asn_mode_enabled, + url = '/lua/pro/admin/access_control_list.lua' + }, { + entry = page_utils.menu_entries.device_protocols, + hidden = not is_admin or is_asn_mode_enabled, + url = '/lua/admin/edit_device_protocols.lua' + }, { + entry = page_utils.menu_entries.device_exclusions, + section = page_utils.menu_sections.hosts, + hidden = not is_admin or not auth.has_capability(auth.capabilities.checks) or not is_enterprise_M or + not devices_exclusion_enabled, + url = '/lua/pro/admin/edit_device_exclusions.lua' + }, { + entry = page_utils.menu_entries.network_config, + section = page_utils.menu_sections.admin, + hidden = not is_admin or not auth.has_capability(auth.capabilities.checks), + url = '/lua/admin/network_configuration.lua' + }, { + entry = page_utils.menu_entries.traffic_rules, + url = '/lua/pro/traffic_rules.lua', + hidden = not is_enterprise or not is_admin + }, { + entry = page_utils.menu_entries.divider + }, { + entry = page_utils.menu_entries.scripts_config, + section = page_utils.menu_sections.checks, + hidden = not is_admin or not auth.has_capability(auth.capabilities.checks), + url = scripts_config_url + }, { + entry = page_utils.menu_entries.alert_exclusions, + section = page_utils.menu_sections.admin, + hidden = not is_admin or not auth.has_capability(auth.capabilities.checks) or not is_enterprise_M or + (tonumber(system_ifid) == tonumber(current_ifid)), + url = '/lua/pro/admin/edit_alert_exclusions.lua?subdir=host' + }, { + entry = page_utils.menu_entries.divider + }, { + entry = page_utils.menu_entries.profiles, + hidden = not is_admin or not is_pro or is_nedge or is_asn_mode_enabled, + url = '/lua/pro/admin/edit_profiles.lua' + }} +}) + +page_utils.add_menubar_section({ + section = page_utils.menu_sections.admin, + hidden = not is_admin, + entries = {{ + entry = page_utils.menu_entries.nedge_users, + hidden = not is_admin or not is_nedge, + url = '/lua/pro/nedge/admin/nf_list_users.lua' + }, { + entry = page_utils.menu_entries.manage_users, + -- Note: 'not _SESSION["localuser"]' indicates that this is an external + -- user (e.g. LDAP), in that case allow users management if fallback is enabled. + hidden = not is_admin or (not _SESSION["localuser"] and not has_local_auth), + url = '/lua/admin/users.lua' + }, { + entry = page_utils.menu_entries.preferences, + hidden = not is_admin, + url = '/lua/admin/prefs.lua' + }, { + hidden = not is_admin, + entry = page_utils.menu_entries.tags, + url = '/lua/tags.lua' + }, { + entry = page_utils.menu_entries.divider + }, { + entry = page_utils.menu_entries.category_lists, + hidden = not is_admin, + url = '/lua/admin/blacklists.lua?enabled_status=enabled' + }, { + entry = page_utils.menu_entries.manage_configurations, + hidden = not is_admin or not has_dump_cache, + url = '/lua/admin/manage_configurations.lua' + }, { + entry = page_utils.menu_entries.divider + }, { + entry = page_utils.menu_entries.categories, + hidden = not is_admin, + url = '/lua/admin/edit_categories.lua' + }} +}) + +-- ############################################## + +-- Developer + +if not info.oem and auth.has_capability(auth.capabilities.developer) then + + if not is_enterprise_M or (has_developer_enabled) then + page_utils.add_menubar_section({ + section = page_utils.menu_sections.dev, + entries = {{ + entry = page_utils.menu_entries.rest_api, + url = '/lua/swagger.lua' + }, { + entry = page_utils.menu_entries.analyze_pcap, + url = '/lua/upload_pcap.lua' + }, { + entry = page_utils.menu_entries.manage_data, + hidden = not is_admin, + url = '/lua/manage_data.lua' + }, { + entry = page_utils.menu_entries.checks_dev, + url = '/lua/checks_overview.lua' + }, { + entry = page_utils.menu_entries.alert_definitions, + url = '/lua/defs_overview.lua' + }, { + entry = page_utils.menu_entries.ts_definitions, + url = '/lua/ts_overview.lua' + }, { + entry = page_utils.menu_entries.directories, + url = '/lua/directories.lua' + }, { + entry = page_utils.menu_entries.api, + url = 'https://www.ntop.org/guides/ntopng/api/' + }} + }) + end +end + +-- ############################################## + +-- About +if not is_enterprise_M or has_help_enabled then + page_utils.add_menubar_section({ + section = page_utils.menu_sections.about, + hidden = info.oem, + entries = {{ + entry = page_utils.menu_entries.about, + url = '/lua/about.lua' + }, { + entry = page_utils.menu_entries.license, + hidden = info["pro.forced_community"] or (not is_admin), + url = '/lua/license.lua' + }, { + entry = page_utils.menu_entries.limits, + hidden = (not is_admin), + url = '/lua/limits.lua' + }, { + entry = page_utils.menu_entries.blog, + url = 'http://blog.ntop.org/' + }, { + entry = page_utils.menu_entries.telegram, + url = 'https://t.me/ntop_community' + }, { + entry = page_utils.menu_entries.manual, + url = 'https://www.ntop.org/guides/ntopng/' + }, { + entry = page_utils.menu_entries.divider + }, { + entry = page_utils.menu_entries.report_issue, + url = 'https://github.com/ntop/ntopng/issues' + }, { + entry = page_utils.menu_entries.suggest_feature, + url = 'https://www.ntop.org/support/need-help-2/contact-us/' + }} + }) + +end + +-- ############################################## + +page_utils.print_menubar() + +-- ############################################## +-- Interface + +print([[ + +]]) + +-- begging of #n-container +print([[
]]) + +-- ################################################### +-- Render toasts +toasts_manager.render_toasts("main-container", toasts_manager.load_main_toasts()) +-- ################################################### + +print("
") + +-- Hidden by default, will be shown by the footer if necessary +print( + '') + +-- Hidden by default, will be shown by the footer if necessary +print( + '') + +-- See if we are starting up and display an informative message +local secs_to_first_data = interface.getSecsToFirstData() + +-- Do not show messages that stay too short on screen (5 sec or more) +if secs_to_first_data > 5 then + print [[ + + + +]] +end + +if (_SESSION["INVALID_CSRF"]) then + print( + '') +end + +-- end of main alerts +print("
") + +-- append password change modal +if (not is_admin) then + dofile(dirs.installdir .. "/scripts/lua/inc/password_dialog.lua") +end diff --git a/http_src/components/sidebar/sidebar.scss b/http_src/components/sidebar/sidebar.scss index 17f096633f..afb9ed3b87 100644 --- a/http_src/components/sidebar/sidebar.scss +++ b/http_src/components/sidebar/sidebar.scss @@ -1,6 +1,6 @@ #n-sidebar { position: fixed; - width: var(--sidebar-width); + width: var(--sb-rail-w); top: 0; left: 0; bottom: 0; diff --git a/http_src/extensions/extensions.js b/http_src/extensions/extensions.js index 494daaab1f..5cfa1a5273 100644 --- a/http_src/extensions/extensions.js +++ b/http_src/extensions/extensions.js @@ -1 +1 @@ -import "./chart_colors"; +// chart_colors (legacy footer injector) removed — footer now handled by app-shell.vue diff --git a/http_src/views/private/clients/white-mode.scss b/http_src/views/private/clients/white-mode.scss index bb40150d58..122714be81 100644 --- a/http_src/views/private/clients/white-mode.scss +++ b/http_src/views/private/clients/white-mode.scss @@ -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; diff --git a/http_src/vue/app-footer.vue b/http_src/vue/app-footer.vue new file mode 100644 index 0000000000..5df0b9d759 --- /dev/null +++ b/http_src/vue/app-footer.vue @@ -0,0 +1,316 @@ + + + + diff --git a/http_src/vue/app-shell.vue b/http_src/vue/app-shell.vue new file mode 100644 index 0000000000..084b2367c0 --- /dev/null +++ b/http_src/vue/app-shell.vue @@ -0,0 +1,1967 @@ + + + + + + + + diff --git a/http_src/vue/components/search-box.vue b/http_src/vue/components/search-box.vue index 8b7a3caaff..8d6c36988a 100644 --- a/http_src/vue/components/search-box.vue +++ b/http_src/vue/components/search-box.vue @@ -3,30 +3,32 @@ -->