SolidX
ReferenceDashboarding

Widget Data Provider

Implement, register, and expose a dashboard widget data provider in solid-core-module.

Backend providers are the data engine of dashboard widgets. Every dashboard widget should resolve data through a provider.

Mental Model

A widget data provider is the backend counterpart of a dashboard widget. Metadata decides which provider should be called, the provider decides how to fetch or compute the data, and the frontend widget decides how that resolved data should be shown.

Provider Contract

Implement IDashboardWidgetDataProvider from src/interfaces.ts.

Core methods:

  • name()
  • help()
  • getData(widgetDefinition, ctxt)

Registration Pattern

Use both decorators:

  • @Injectable()
  • @DashboardWidgetDataProvider()

The runtime registration path is:

  • Decorator metadata -> introspection (SolidIntrospectService) -> registry (SolidRegistry) -> runtime resolver (DashboardRuntimeService)

Provider Template

import { Injectable } from "@nestjs/common";
import { DashboardWidgetDataProvider } from "src/decorators/dashboard-widget-data-provider.decorator";
import {
  IDashboardWidgetDataProvider,
  IDashboardWidgetDataProviderContext,
  IDashboardWidgetDataResponseEnvelope,
} from "src/interfaces";

@DashboardWidgetDataProvider()
@Injectable()
export class ExampleDashboardWidgetProvider implements IDashboardWidgetDataProvider {
  name(): string {
    return "ExampleDashboardWidgetProvider";
  }

  help(): string {
    return "Returns sample widget data.";
  }

  async getData(
    widgetDefinition: Record<string, any>,
    ctxt: IDashboardWidgetDataProviderContext,
  ): Promise<IDashboardWidgetDataResponseEnvelope<any>> {
    const now = new Date().toISOString();

    return {
      meta: {
        providerName: this.name(),
        widgetName: ctxt.widgetName,
        generatedAt: now,
        durationMs: 0,
      },
      data: {
        value: 42,
        label: widgetDefinition?.name ?? "Example KPI",
      },
    };
  }
}

Bind Provider in Metadata

{
  "id": "kpi-example",
  "name": "Example KPI",
  "type": "kpi",
  "dataProvider": "ExampleDashboardWidgetProvider"
}

Reference Implementation: Queue SLA Heatmap

The framework now includes a canonical reference implementation for a fully custom queue-focused widget:

  • Backend provider: MqDashboardQueueSlaHeatmapProvider
  • Frontend widget: QueueSlaHeatmapWidget

The provider output contract is intentionally explicit:

{
  "xCategories": ["2026-06-01T08:00:00.000Z", "2026-06-01T09:00:00.000Z"],
  "yCategories": ["queue-a", "queue-b"],
  "points": [
    [0, 0, 4250.5],
    [1, 0, 6100.0],
    [0, 1, 11200.25]
  ],
  "tooltipFields": ["avgElapsedMillis", "messageCount", "peakElapsedMillis"],
  "pointDetails": [
    {
      "xIndex": 0,
      "yIndex": 0,
      "bucket": "2026-06-01T08:00:00.000Z",
      "queueName": "queue-a",
      "avgElapsedMillis": 4250.5,
      "messageCount": 18,
      "peakElapsedMillis": 9100
    }
  ],
  "legendThresholds": [
    { "label": "0-5s", "color": "#22c55e", "lte": 5000 },
    { "label": "5-15s", "color": "#f59e0b", "gt": 5000, "lte": 15000 }
  ]
}

This RI is useful because it shows the recommended split:

  • The provider owns data access and runtime contract design.
  • The frontend widget owns the final visual treatment.
  • Metadata binds the two together.
  • Use repository-driven queries (prefer security-rule-aware query builders where available).
  • Treat ctxt.variables as the source of user-selected filters.
  • Keep response contracts stable for frontend rendering.
  • Return a normalized envelope with meta and data.
  • Keep provider names explicit and unique.

Quick Validation Path

Start service.

Call the definition endpoint and verify the widget exists.

Call the widget data endpoint.

curl -X POST "$BASE_URL/dashboard/<module>/<dashboard>/widgets/<widgetId>/data" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"variables": {}}'

Then verify meta.providerName and the data payload shape.