Skip to content

NMS-20127: dashboard Top-N and Metric Chart panels - #8723

Open
joseanesONMS wants to merge 47 commits into
developfrom
jira/NMS-20127-new-panels
Open

NMS-20127: dashboard Top-N and Metric Chart panels#8723
joseanesONMS wants to merge 47 commits into
developfrom
jira/NMS-20127-new-panels

Conversation

@joseanesONMS

Copy link
Copy Markdown
Contributor

NMS-20127 (dashboard rework): two new panels with no legacy homepage equivalent. Stacks on #8721 (the framework base), so review its top commit.

  • Top-N ranks entities by a chosen KPI over the selected timeframe (attributing each measurement to the source its response label encodes, not hash-ordered position).
  • Metric Chart plots one metric on one entity over time.
  • Both honor the dashboard timeframe (including custom ranges), guard against stale concurrent responses, and add their KPI/entity option editors to the panel options dialog. Add-only — not placed in the default layout.

…stence backend)

Adds a configurable, PrimeVue-based Vue 3 dashboard under /ui (route
/dashboard) to begin replacing the legacy JSP homepage, plus the REST
endpoint to persist its layout.

Frontend (ui/):
- Panel framework: registry, Pinia store, default layout, PanelFrame chrome
  (PrimeVue Panel), and a sample panel. Panels receive resolved filter /
  timeframe / refresh contracts.
- DashboardGrid uses grid-layout-plus for drag + resize (edit mode only);
  geometry flows grid -> store, add/remove/collapse flow store -> grid.
- Toolbar: global timeframe, refresh interval + pause (NMS-4404), add panel,
  save/edit; per-panel collapse/rename/remove.
- Global filter control (NMS-10507): surveillance categories + IP match.
- dashboardService talks to /api/v2/dashboard/system (404 -> built-in default).

Backend (opennms-webapp-rest):
- DashboardRestApi / DashboardRestService: GET/PUT /api/v2/dashboard/system,
  persisting one system-wide JSON layout document via JsonStore.

Addresses NMS-11946 (collapse/rearrange/hide) and lays groundwork for
NMS-4433 (new panel types). Future: per-user / named dashboards reuse the
same layout document by varying its scope.
…rview, nodes with alarms)

Replaces the placeholder default layout with three panels matching the legacy
homepage boxes:
- Notifications: outstanding-notice counts from /rest/notifications/summary.
- Status Overview: Chart.js doughnut of alarm counts by severity, read from
  /api/v2/alarms totalCount per severity (FIQL alarm.severity==).
- Nodes with Pending Alarms: alarms grouped by node with count + max severity.

Adds a shared severity util (ordering, labels, OpenNMS-standard colors) and a
notificationService. Panels refetch on the global refresh tick.
- Status Overview now shows BOTH legacy doughnuts (alarms + outages), sourced
  from /api/v2/status/summary/nodes/{alarms,outages} (nodes grouped by unacked
  alarms / current outages), replacing the prior alarms-only per-severity count.
- New News Feed panel from /api/v2/newsfeed (title/link/short description/tags).

Adds statusService and newsfeedService; both panels added to the default layout.
- Pending Situations: alarms filtered isSituation==true (/api/v2/alarms), with
  severity, affected-node/alarm counts.
- Nodes with Service Outages: currently-open outages from /api/v2/outages
  (FIQL ifRegainedService==epoch), node + service name.

Adds outageService and situationService; refactors the default layout into a
three-column arrangement (situations/alarms/outages, status overview,
notifications/news) via a small panel() helper.
Leaflet/OSM map (vue-leaflet) replicating the legacy homepage map: geolocated
nodes (/api/v2/nodes assetRecord) with markers colored by each node's highest
alarm severity (derived from /api/v2/alarms). Handles grid resize via
ResizeObserver -> invalidateSize. Added to the registry + default layout.
Match the legacy homepage proportions: 3 / 6 / 3 of the 12-col grid (was even
4/4/4). Left = situations/alarms/outages, center (wide) = status overview + map,
right = notifications/news. Individual panels remain resizable via the grid.
Replicates the legacy "Availability Over the Past 24 Hours" categories box from
GET /rest/availability (RTC category data: outage-text, availability-text,
availability-class). Table of category / outages / availability with an Overall
Service Availability total row; availability colored by class. No new backend
needed. Added to registry + default layout (center column, under Status Overview).
…s) panels

Both replicate the legacy summary boxes from the existing status REST
(/api/v2/status/business-services and /status/applications) — no new backend
needed; the list-with-severity endpoints already exist in StatusRestService.
Shared StatusListPanel renders name + severity badge, filtered to problem
severities (WARNING+). Added to registry + left column of the default layout.
…fullscreen

- Add Quick Search (node id/label/IP -> element/nodeList.htm), and Resource
  Graphs / KSC Reports launcher panels (link to legacy chooser pages; full
  typeahead is a follow-up).
- Default layout now mirrors the legacy homepage column order/positions for
  easy comparison: left = situations/alarms/outages/BSM/apps/news; center =
  status/availability/map; right = notifications/resource-graphs/KSC/quick-search.
- Toolbar: title tooltips on the timeframe + refresh selects (and pause), and a
  Full screen button (Fullscreen API on the dashboard container) for NOC displays.
…titles)

- PanelFrame: make the PrimeVue Panel content wrappers flex to a bounded height
  so fill-height panels (map, charts) size correctly instead of overflowing.
- Regional Status: always renders the map (even with no nodes); remembers pan +
  zoom across reloads via localStorage; empty-state shown as a small pill.
- Status Overview: thicker donuts (cutout 55%) that fit the box (no longer cut).
- Resource Graphs / KSC Reports: drop the redundant in-panel title (the panel
  header already shows it).
- web.xml: Permissions-Policy was fullscreen=() which blocked the Fullscreen API;
  changed to fullscreen=(self). Toolbar fullscreen toggle now also falls back to
  a CSS "maximize" if the API is unavailable.
- DashboardGrid: add bottom padding so the app's fixed copyright bar no longer
  cuts the last panels.
- Dashboard: global style so PrimeVue overlays (teleported to <body>) use the app
  sans-serif font instead of the serif default (fixes combo-box dropdown font).
- Status Overview: donuts resize with the panel (ResizeObserver) and are clipped
  to the box.
…panels

- Per-panel options dialog (gear): height mode + panel-type-specific settings.
- Height mode per panel: 'fixed' (fixed grid height + scrollbar) or 'auto'
  (PanelFrame measures natural content height; DashboardGrid fits the cell, so
  empty list panels shrink to a couple of lines). Auto panels aren't manually
  resizable and their height isn't persisted. Registry defaults match the legacy
  homepage: News Feed / Availability / Status Overview / Regional map = fixed,
  all the list panels = auto.
- New panels: Notes (free text in options) and HTML Content (iframe to a URL;
  same-origin per the frame-src CSP).
…tion)

grid-layout-plus doesn't recompact on programmatic height changes, so auto-height
resizes (and add/remove) could leave panels overlapping. Add our own vertical
compaction (place each item at the lowest non-colliding y in its columns) run
after auto-height changes and reconcile.
…TML URL validation

- Fixed panels now actually bound + scroll: the PrimeVue 4 chain has an extra
  .p-panel-content-wrapper between container and content that wasn't flexed —
  add it. This fixes News Feed/Availability scrollbars AND the Regional map
  (the map now gets a real height and renders tiles even with no nodes).
- Dashboard scrolls internally (flex column; grid is the scroll region) and the
  content chain gets a definite height via :has(#dashboard-root), so a tall
  dashboard no longer overflows past the app footer/copyright bar.
- HTML Content options: validate the URL — external (cross-origin) URLs are
  rejected with an explanation (blocked by frame-src 'self' CSP) before applying.
… whitespace)

Auto panels were clamped to the registry minSize.h, leaving whitespace under
short content (and reserving space visibly in edit mode). Use min-h=1 for
auto-height panels so the cell hugs the measured content.
…meframe)

New 'topn' panel: ranks by a selectable KPI with sort direction and N (options
dialog). Default KPI = Node Response Time (ICMP), descending, N=5. Data via the
measurements API (POST /rest/measurements): enumerate matching resources from
/rest/resources, query one AVERAGE bucket over the resolved timeframe, sort,
take N. KPI registry (topnService) is extensible for more KPIs.
A single range-sized RRD bucket returns NaN; query at ~range/1000 (min 5min)
and average the series for the aggregate.
- PanelFrame now wraps the PrimeVue Panel in a real <div> (frameRef) and measures
  that for auto-height — the component ref didn't reliably expose a DOM node, so
  auto panels never shrank (the leftover whitespace). Auto panels now fit content.
- Panel surface/header/text/border use Feather theme variables
  (--feather-elevation-background-2 / -primary-text-on-surface / -border-on-surface),
  which adapt under .open-dark — so panels are legible in dark mode instead of
  white-with-invisible-text.
…tespace)

Reduce PrimeVue panel header/content padding so short auto panels (Resource
Graphs, KSC, etc.) don't round up to an extra grid row, and run a vertical
compaction pass shortly after mount so columns stack tight once panels report
their auto heights.
…acy->new button

- DashboardGrid: compaction now reassigns the layout with FRESH item objects (and
  vertical-compact enabled) so grid-layout-plus actually re-renders compacted
  positions — removes the leftover gaps in saved layouts (e.g. Resource Graphs/KSC).
- Per-panel "Shade rows by severity" option (legacy-style) for Pending Situations,
  Nodes with Pending Alarms, and Availability — rows tinted by severity.
- Legacy homepage: "Try the new Dashboard (beta)" button below the Quick Search box
  (links to /opennms/ui/#/dashboard).
…ypes backend/combo

- DashboardGrid: grid-layout-plus only re-renders when the layout ARRAY ref/length
  changes (watch on [layout, length]); it ignored in-place h/y mutations. compactLayout
  now ALWAYS reassigns fresh item objects, so auto-height + compaction truly apply
  (this was why the whitespace "did nothing").
- Backend: DashboardRestService gains GET /api/v2/dashboard/service-types (id+name)
  via ServiceTypeDao; rebuilt + deployed the webapp-rest jar.
- Quick Search: "Providing service" combo populated from that endpoint, posting the
  service id to element/nodeList.htm (matches the legacy box).
…dup availability total

Spacing (real fix): switch the grid to pixel units — row-height=1, vertical
margin=0, h measured in px. Auto panels size to exactly their content height plus
a 12px gap (was rounding up to the next ~56px row, which caused the persistent
whitespace). Fixed panels fill the cell minus that 12px gap. Old/default layouts
(h in ~44px row units) are auto-converted to px on load.

Linking parity with the legacy front page:
- Panel titles deep-link (Situations/Alarms -> alarm/list.htm, Outages ->
  outage/list.htm, Applications -> application/index.jsp, Availability ->
  rtc/index.jsp, Notifications -> notification/index.jsp, Resource Graphs ->
  graph/index.jsp, KSC -> KSC/index.jsp). Plain text while in edit mode so the
  header stays a drag handle.
- Availability category names link to rtc/category.jsp (outage detail).

Availability: render the REST "Total" section's "Overall Service Availability"
row as the bold total instead of appending our own computed row (removes the
duplicate).

Legacy homepage "Try the new Dashboard" button: blue -> light gray.
- Business Services panel title now links to the BSM topology view
  (topology?provider=Business Services&layout=Hierarchy Layout&szl=1).
- Status Overview donut legends read the Feather text color so labels are
  legible on the dark surface (Chart.js' default gray was unreadable); a
  MutationObserver recolors them live when the .open-dark theme is toggled.
…the timeframe

New 'metric-chart' panel type: Chart.js line chart of a single metric on a
single entity over the panel's resolved timeframe. Entity and metric are
single-selects in the panel options (entity list = entities with data for
the chosen metric); defaults: localhost / Node Response Time (ICMP).
Reuses the Top-N KPI registry and measurements data path (listKpiSources
extracted from queryTopn).
Registry 'hidden' flag: the panel stays registered (renders if a layout
references it, handy for framework debugging) but is no longer offered
in production via Add Panel.
store.applyFactoryDefault() swaps in createDefaultLayout() (legacy homepage
parity incl. the Regional Map) and marks dirty; persists on Save. Fixes the
gap where a saved layout always shadowed the built-in default with no way
back (store.reset() only reloads the saved doc).
…parity)

Clicking a severity slice navigates to the legacy severity-filtered node
list (status/index.jsp?type=nodes&strategy={alarms|outages}&severityFilter=),
matching the original homepage status-box onclick; pointer cursor on hover.
# Conflicts:
#	ui/package.json
#	ui/pnpm-lock.yaml
FeatherDS is gone from the UI stack: the SORT enum import moves to its
vendored home in @/types, and the panel styling swaps the feather CSS
variables for the PrimeVue tokens the rest of /ui uses, including the
computed-style reads that color the Chart.js legends. grid-layout-plus is
the only dependency develop did not already carry.
Adds the missing automated coverage: store behavior (load/save/dirty
tracking, panel operations, geometry sync, override resolution), panel
registry and default-layout consistency, timeframe range math, severity
helpers, the service fallback paths, the global refresh timer, and a REST
integration test for the layout document lifecycle and service types.

The layout endpoint gets the security it implied but never enforced:
every user can read the system dashboard, only admins can save it —
enforced by Spring Security rules and an in-code check, and covered by
the integration test.
…at filters

The bare /api/v2/nodes?category=NAME parameter is ignored and returns every
node, so the global filter's category selection resolved to all node ids and
did not filter. Use the node search property that actually constrains by
membership (_s=category.name==NAME).
A stray symlink to a local worktree's node_modules was committed with the
base framework change; it makes the CI pnpm install fail with ENOTDIR when it
tries to create the real node_modules directory.
A stray symlink to a local worktree's node_modules was committed with the
base framework change; it makes the CI pnpm install fail with ENOTDIR when it
tries to create the real node_modules directory.
@joseanesONMS
joseanesONMS requested a review from synqotik August 3, 2026 13:59
…t compaction fix

Move the dashboard framework chrome off direct PrimeVue onto the
@opennms/onms-ui Onms-* wrappers (NMS-20081 seam), so the framework
passes the no-direct-primevue lint rule. PanelFrame's edit icons move
into the panel header slot since OnmsPanel forwards only that slot.

Add an auto-fit ("squeeze") layout option persisted on the layout doc
and toggleable in edit mode: panels pack up and down against their
neighbours, or stay free-form. Fix the auto-height race where an async
layout reload reset measured panel heights back to their authored
placeholder and left gaps — measured heights are now cached and reused
across rebuilds, so collapse/expand and initial load pack tightly.
…hboard-base

# Conflicts:
#	ui/pnpm-lock.yaml
…nto jira/NMS-20127-new-panels

# Conflicts:
#	ui/src/components/Dashboard/PanelOptionsDialog.vue
# Conflicts:
#	ui/package.json
#	ui/pnpm-lock.yaml
The develop refresh brought stricter stylistic eslint rules that the
dashboard test files predate; build-ui was red on 17 auto-fixable
object-curly-spacing/arrow-parens/brace-style errors. lint:fix output only;
the 52 dashboard tests still pass.
Companion to the base-branch lint fix; build-ui was red on auto-fixable
object-curly-spacing/arrow-parens errors in topnService.test.ts.

@marshallmassengill marshallmassengill left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see any blockers. Especially since this is going into a feature branch.

@joseanesONMS
joseanesONMS deleted the branch develop August 31, 2026 14:54
@joseanesONMS joseanesONMS reopened this Aug 31, 2026
@joseanesONMS
joseanesONMS changed the base branch from jira/NMS-19851-dashboard-base to develop August 31, 2026 14:55
@joseanesONMS
joseanesONMS dismissed marshallmassengill’s stale review August 31, 2026 14:55

The base branch was changed.

The dashboard base (#8721) landed on develop as a squash, so the shared
Dashboard files show add/add against this branch; develop's copies are
byte-identical to the base content this branch already merged, so the
branch's extended versions win. !smoke
@joseanesONMS

Copy link
Copy Markdown
Contributor Author

@marshallmassengill heads-up on the approval state: merging the base PR #8721 auto-closed this stacked PR (its base branch went away), and reopening/retargeting it to develop made GitHub dismiss your approval. The diff is exactly what you approved, plus a mechanical develop sync (the base content now on develop is byte-identical, so the shared files resolve to this branch's versions; lint/tests/build green). Re-approve when you get a moment and I'll merge.

@marshallmassengill
marshallmassengill self-requested a review August 31, 2026 15:16

@marshallmassengill marshallmassengill left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you post some screenshots of how this ends up appearing in the UI?

@joseanesONMS

Copy link
Copy Markdown
Contributor Author
Screenshot 2026-08-31 at 14 14 43 Screenshot 2026-08-31 at 14 11 51

@joseanesONMS

Copy link
Copy Markdown
Contributor Author
Screenshot 2026-08-31 at 14 22 28 Screenshot 2026-08-31 at 14 22 21

@marshallmassengill

Copy link
Copy Markdown
Contributor

Ok... so this PR adds the chart and Top-N panel types?

@joseanesONMS

Copy link
Copy Markdown
Contributor Author

Ok... so this PR adds the chart and Top-N panel types?

Yes. There is a PR to create a Parity Dashboard behind a New Dashboard button.
Then there is another PR to add the ability to edit.
Then there is another PR to add some new panels.

I need to do other new PRs (not done yet), for:
PDF Export.
Remove old Dashboard, and replace with new.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants