ntopng/doc/developers/vue_components/components_usage.md
GabrieleDeri 9015774e2b
Fixes geomap shadow, navbar tabs component (#10184)
* Fixes geomap shadow, zoom group, navbar tabs component

* Update dist
2026-03-19 17:16:13 +01:00

8.4 KiB

Vue Components Reference

This document contains documentation for vuejs components and their usage in ntopng UI. Components can be used in:

  • Other vuejs components with the usual import and instantiation syntax of vuejs components
  • In lua pages using the template.render function.
    • IMPORTANT Be sure to import newly created components in http_src/vue/ntop_vue.js and export it, an example is reported below
// import the new component
import { default as PieChart } from "./charts/pie-chart.vue";

// export it 
let ntopVue = {
    // graphs
    MultiPieChart: MultiPieChart,
    PieChart: PieChart
}

PieChart

Single donut chart with legend, tooltip, and auto-refresh. If url is provided in the rest, the pie slice can be clicked and redirected to the page

Props

Prop Type Required Description
chart Object Yes Chart config object
context Object Alternative Wrapper with a chart key (used from Lua)

Chart Object

Field Type Required Description
name string Yes Unique chart ID
update_url string Yes Endpoint returning [{ label, value, url? }]
url_params Object No Query params appended to update_url
refresh number No Auto-refresh in ms (0 = disabled)
title string No Title above chart
unit string No Value formatter — "bytes", "number", etc.

Vue

<PieChart :chart="{
  name:       'myChart',
  title:      'Traffic by Protocol',
  update_url: `${http_prefix}/lua/rest/v2/get/interface/l7/stats.lua`,
  url_params: { ifid: context.ifid },
  refresh:    5000,
  unit:       'bytes',
}" />

Lua

template.render("pages/vue_page.template", {
   vue_page_name = "PieChart",
   page_context  = json.encode({
      chart = {
         name       = "myChart",
         title      = i18n("my_title"),
         update_url = http_prefix .. "/lua/rest/v2/get/interface/l7/stats.lua",
         url_params = { ifid = ifstats.id },
         refresh    = refresh,
         unit       = "bytes",
      }
   }),
})

MultiPieChart

Renders multiple PieChart instances in a responsive grid. if charts_per_row is specified, it is possible to choose the number of pie charts per row to display, otherwise all charts are disposed on one row with automatic flex and new row creation

Props

Prop Type Required Description
context Object Yes Object with charts array and optional charts_per_row
charts_per_row number No Columns in grid (default: all charts in one row)

Context Object

Field Type Required Description
charts Array Yes Array of Chart Objects (same schema as PieChart)
charts_per_row number No Overrides column count

Vue

<MultiPieChart :context="{
  charts_per_row: 2,
  charts: [
    {
      name:       'clientPorts',
      title:      'Client Ports',
      update_url: `${http_prefix}/lua/iface_ports_list.lua`,
      url_params: { clisrv: 'client', ifid: context.ifid },
      refresh:    5000,
      unit:       'number',
    },
    {
      name:       'serverPorts',
      title:      'Server Ports',
      update_url: `${http_prefix}/lua/iface_ports_list.lua`,
      url_params: { clisrv: 'server', ifid: context.ifid },
      refresh:    5000,
      unit:       'number',
    },
  ],
}" />

Lua

template.render("pages/vue_page.template", {
   vue_page_name = "MultiPieChart",
   page_context  = json.encode({
      charts_per_row = 2,
      charts = {
         {
            name       = "clientPorts",
            title      = i18n("ports_page.client_ports"),
            update_url = http_prefix .. "/lua/iface_ports_list.lua",
            url_params = table.merge({ clisrv = "client", ifid = ifId }, host_params),
            refresh    = refresh,
            unit       = "number",
         },
         {
            name       = "serverPorts",
            title      = i18n("ports_page.server_ports"),
            update_url = http_prefix .. "/lua/iface_ports_list.lua",
            url_params = table.merge({ clisrv = "server", ifid = ifId }, host_params),
            refresh    = refresh,
            unit       = "number",
         },
      }
   }),
})

Data Endpoint Format

All pie chart endpoints must return a JSON array:

[
  { "label": "TCP",  "value": 1024, "url": "/lua/flows_stats.lua?proto=6" },
  { "label": "UDP",  "value": 512 },
  { "label": "Other","value": 128 }
]
Field Required Description
label Yes Slice label shown in legend
value Yes Numeric value
url No Click-through URL for slice and legend item

NavbarTabs

Segmented tab-selector for filtering or switching views. Supports optional numeric count badges per tab. Active tab is highlighted in orange; inactive tabs show a warm orange tint on hover.

Props

Prop Type Required Description
tabs Array Yes Array of Tab Objects
active_tab_id String No ID of the initially active tab (defaults to first tab)

Tab Object

Field Type Required Description
id string Yes Unique tab identifier
label_i18n string Yes i18n key for the tab label
count number No Badge number shown next to the label. Omit or null to hide badge

Emits

Event Payload Description
on_click tab (Tab Object) Fired when the user clicks a tab that is not already active

Vue — text only

import { default as NavbarTabs } from "./components/navbar-tabs.vue";

<NavbarTabs
  :tabs="[
    { id: 'protocols', label_i18n: 'protocols' },
    { id: 'categories', label_i18n: 'categories' },
  ]"
  :active_tab_id="activePage"
  @on_click="(tab) => activePage = tab.id"
/>

Vue — with count badges (reactive)

Drive the count from a reactive map so badges update automatically when data loads:

import { ref, reactive, computed } from "vue";
import { default as NavbarTabs } from "./components/navbar-tabs.vue";

const active_status = ref("all");
const counts = reactive({});          // populated by on_rows_loaded or similar

const tabs = computed(() => [
  { id: "all",      label_i18n: "all",      count: counts.all      ?? null },
  { id: "enabled",  label_i18n: "enabled",  count: counts.enabled  ?? null },
  { id: "disabled", label_i18n: "disabled", count: counts.disabled ?? null },
]);

<NavbarTabs
  :tabs="tabs"
  :active_tab_id="active_status"
  @on_click="(tab) => active_status = tab.id"
/>

Notes

  • Pass count: null (or omit the field) to render the tab as text only — no badge is shown
  • active_tab_id is kept in sync via a watch, so external changes to the prop are reflected

NoData

Simple info banner rendered when there is no data to display. Supports both i18n keys and direct strings.

Props

Prop Type Required Description
show Boolean Yes Renders the component when true
i18nKey String No i18n translation key (default: 'flows_page.no_data')
message String No Direct string — takes priority over i18nKey if provided

Vue

<!-- Default message -->
<NoData :show="no_data" />

<!-- Custom i18n key -->
<NoData :show="no_data" i18nKey="some_page.empty_table" />

<!-- Direct string -->
<NoData :show="no_data" message="No flows available" />

<!-- Compound expression -->
<NoData :show="no_data && !loading" :message="no_data_message" i18nKey="flows_page.no_data" />

LoadingOverlay

Full-area loading overlay with spinner and translated label. Positions itself as fixed when the parent element exceeds 70% of the viewport height.

Props

Prop Type Required Description
isLoading Boolean Yes Shows the overlay when true, hides when false
styles String No Inline styles applied to the spinner element

Notes

  • The overlay uses position: absolute and fills the parent via inset: 0 — the parent must have position: relative
  • Automatically listens to resize events to recompute fixed positioning
  • Respects data-theme="light" / data-theme="dark" on :root

Vue

<div class="position-relative">
  <LoadingOverlay :isLoading="loading" />
</div>

<!-- With custom spinner style -->
<LoadingOverlay :isLoading="loading" styles="width: 60px; height: 60px;" />