doc/developers/vue_components/components_usage.md
This document contains documentation for vuejs components and their usage in ntopng UI. Components can be used in:
template.render function.
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
}
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
| Prop | Type | Required | Description |
|---|---|---|---|
chart | Object | Yes | Chart config object |
context | Object | Alternative | Wrapper with a chart key (used from Lua) |
| 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. |
<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',
}" />
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",
}
}),
})
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
| 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) |
| Field | Type | Required | Description |
|---|---|---|---|
charts | Array | Yes | Array of Chart Objects (same schema as PieChart) |
charts_per_row | number | No | Overrides column count |
<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',
},
],
}" />
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",
},
}
}),
})
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 |
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.
| 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) |
| 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 |
| Event | Payload | Description |
|---|---|---|
on_click | tab (Tab Object) | Fired when the user clicks a tab that is not already active |
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"
/>
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"
/>
count: null (or omit the field) to render the tab as text only — no badge is shownactive_tab_id is kept in sync via a watch, so external changes to the prop are reflectedSimple info banner rendered when there is no data to display. Supports both i18n keys and direct strings.
| 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 |
<!-- 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" />
Full-area loading overlay with spinner and translated label. Positions itself as fixed when the parent element exceeds 70% of the viewport height.
| 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 |
position: absolute and fills the parent via inset: 0 — the parent must have position: relativeresize events to recompute fixed positioningdata-theme="light" / data-theme="dark" on :root<div class="position-relative">
<LoadingOverlay :isLoading="loading" />
</div>
<!-- With custom spinner style -->
<LoadingOverlay :isLoading="loading" styles="width: 60px; height: 60px;" />