SolidX
ReferenceDashboarding

Metadata Schema

Define dashboards, variables, widgets, and default layout in SolidX module metadata.

Dashboard definitions are authored in module metadata under the root-level dashboards key.

Mental Model

The dashboard schema has a small set of core players:

  • The dashboard definition describes the screen itself.
  • Variables describe the inputs a user can use to filter or parameterise the dashboard.
  • Widgets describe the individual building blocks on the page.
  • Provider bindings connect those widgets to backend data.
  • The default layout describes how the widgets should initially be arranged.

Placement in Metadata

The dashboards block is not a nested widget configuration area or a UI-only document. It is a first-class module metadata section and should be treated as part of the framework contract for the module.

dashboards should be a peer of sections such as:

  • actions
  • menus
  • roles
  • users

Minimal Dashboard Definition Shape

This is the smallest useful mental model for a dashboard definition. It gives the framework enough information to identify the dashboard, authorize access to it, and render a widget canvas that can later be expanded.

{
  "dashboardSchemaVersion": 1,
  "name": "queue-health",
  "displayName": "Queue Health Dashboard",
  "description": "Operational visibility for queue processing.",
  "moduleUserKey": "solid-core",
  "variables": [],
  "widgets": [],
  "defaultLayout": {
    "engine": "gridstack",
    "columns": 12,
    "items": []
  }
}

Variable Authoring

Variables define the inputs the dashboard accepts from the user. They are not just UI controls. They become part of the runtime payload sent to backend providers, so naming and semantics should be chosen carefully.

Supported variable patterns used by the framework today:

  • date
  • selectionStatic
  • selectionDynamic
  • isMultiSelect for selection variables

Date Variable

Use a date variable when widgets need a shared time window. In the current UI, this renders as a preset selector with an optional custom date range.

{
  "name": "date",
  "label": "Created At",
  "type": "date",
  "required": true
}

The UI supports preset selection (today, last_24_hours, last_7_days, last_30_days) and custom date range.

Static Selection Variable

Use a static selection variable when the option set is known at design time and does not require backend lookup.

{
  "name": "stage",
  "label": "Stage",
  "type": "selectionStatic",
  "isMultiSelect": true,
  "selectionStaticValues": [
    "pending:Pending",
    "failed:Failed",
    "succeeded:Succeeded"
  ]
}

Dynamic Selection Variable

Use a dynamic selection variable when the option list depends on live data and should be resolved through the existing selection provider pattern.

{
  "name": "queueName",
  "label": "Queue",
  "type": "selectionDynamic",
  "selectionConfig": {
    "providerName": "MqDashboardQueueNameVariableOptionsProvider",
    "providerContext": {
      "labelField": "name",
      "valueField": "name"
    }
  }
}

selectionConfig.providerContext is passed to the dynamic selection provider and is useful when the provider needs hints about how to shape the output. For example, a provider can use it to decide which field should become the display label and which field should become the persisted value.

Widget Authoring

Widgets are the runtime units of a dashboard. Each widget definition tells the framework what kind of widget it is, which backend provider should be invoked, and any provider-specific context needed to resolve the data.

Each widget binds to a backend provider using dataProvider.

{
  "id": "kpi-total-messages",
  "name": "Total Messages",
  "type": "kpi",
  "dataProvider": "MqDashboardTotalMessagesKpiProvider",
  "providerContext": {
    "metric": "count_total_messages"
  }
}

providerContext is a metadata-authored input passed through to the provider at runtime. It is useful for keeping provider classes reusable. For example:

  • A KPI provider can use providerContext.metric to decide which aggregate to compute.
  • A chart provider can use providerContext.bucket to choose hour vs day.
  • A table provider can use providerContext.columns and providerContext.sort to shape the output.

For custom frontend rendering, add componentName.

{
  "id": "queue-sla-heatmap",
  "name": "Queue SLA Heatmap",
  "type": "customChart",
  "dataProvider": "MqDashboardQueueSlaHeatmapProvider",
  "componentName": "QueueSlaHeatmapWidget"
}

This is the recommended pattern when the widget still follows the standard backend provider contract, but needs a specialised visual treatment in the UI. The queue SLA heatmap reference implementation is the canonical example of this approach.

Default Layout Authoring (Gridstack)

The default layout defines the initial visual arrangement of widgets before any user-specific override is saved. The current layout engine uses a Gridstack-compatible contract.

{
  "engine": "gridstack",
  "columns": 12,
  "items": [
    { "widgetId": "kpi-total-messages", "x": 0, "y": 0, "w": 3, "h": 2 },
    { "widgetId": "chart-stage-distribution", "x": 3, "y": 0, "w": 6, "h": 4 },
    { "widgetId": "table-recent-failures", "x": 0, "y": 4, "w": 12, "h": 4 }
  ]
}

Dashboards should be discoverable through the same action/menu metadata model used elsewhere in SolidX.

Dashboards should be exposed via metadata-driven menu/action pairs.

Recommended pattern:

  • Action type custom
  • Action path matching dashboard route
  • Menu item referencing the action

The action route should follow the canonical dashboard route pattern:

  • /admin/core/:moduleName/dashboard/:dashboardName

Example:

{
  "actions": [
    {
      "name": "solid-core-queue-health-dashboard-view",
      "displayName": "Queue Health Dashboard",
      "type": "custom",
      "customComponent": "/admin/core/solid-core/dashboard/queue-health"
    }
  ],
  "menus": [
    {
      "name": "solid-core-queue-health-dashboard-menu-item",
      "displayName": "Queue Health",
      "actionUserKey": "solid-core-queue-health-dashboard-view"
    }
  ]
}

Widget Permissions

Dashboard widget permissions use SolidX's existing explicit permission mechanism. This means dashboard authors must add the required permission entries to module metadata and then assign them to the appropriate roles, just like any other explicit SolidX permission.

The dashboard widget permission format is:

  • dashboard:<dashboard-name>:<widget-pattern>

Where:

  • The first segment is always dashboard
  • The second segment is the dashboard name
  • The third segment is the widget matcher

The widget matcher supports:

  • Exact widget names
  • * for all widgets in a dashboard
  • Regex-style patterns in the widget segment

Examples from the queue-health reference implementation:

{
  "permissions": [
    "dashboard:queue-health:kpi-.*",
    "dashboard:queue-health:chart-queue-.*",
    "dashboard:queue-health:chart-processing-latency-trend"
  ]
}

This means:

  • dashboard:queue-health:kpi-.* authorizes all KPI widgets such as kpi-total-messages
  • dashboard:queue-health:chart-queue-.* authorizes queue-focused charts such as chart-queue-wise-failures, chart-queue-wise-avg-elapsed, and chart-queue-sla-heatmap
  • dashboard:queue-health:chart-processing-latency-trend authorizes one specific widget only

Any widgets not covered by the user's effective permission set will remain visible in the dashboard layout, but they will not resolve data.

Permission Runtime Behavior

The permission check is enforced on the backend first.

When a user does not have permission for a widget:

The backend does not invoke that widget's data provider at all.

The backend returns a normalized unauthorized widget envelope.

The frontend still renders the widget card in the grid.

The widget body shows a compact Unauthorized state.

This behavior is intentional because it preserves layout consistency while keeping protected widget data entirely server-side.

To make dashboard permissions effective in a real project:

Declare the explicit permission strings in module metadata.

Attach those permissions to one or more roles.

Assign those roles to users.

That flow is standard SolidX RBAC behavior and dashboards follow the same model.

Authoring Checklist

Define the dashboard in dashboards[].

Define variables with clear names and labels.

Bind each widget to a valid backend dataProvider.

Define a complete defaultLayout for all widgets.

Add action and menu entries for discoverable navigation.

Add explicit dashboard widget permissions and bind them to the right roles.