Skip to content

Dashboard KPI widgets: reports[].widget, custom widgets, Report Editor panel#6133

Merged
delchev merged 1 commit into
masterfrom
feat/dashboard-widgets
Jul 3, 2026
Merged

Dashboard KPI widgets: reports[].widget, custom widgets, Report Editor panel#6133
delchev merged 1 commit into
masterfrom
feat/dashboard-widgets

Conversation

@delchev

@delchev delchev commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Meaningful dashboard tiles instead of raw per-entity record counts, in three layers:

reports[].widget — KPI tiles backed by reports

reports:
  - name: OverdueInvoices
    source: Invoice
    filter: "due <= CURRENT_DATE AND balance > 0"
    widget: { kind: count, label: Overdue Invoices, icon: alert-triangle }
  - name: RevenueByMonth
    dimensions: ["month(date)"]
    measures: ["sum(total)"]
    widget:
      value: "sum(total)"
      at: { "month(date)": now }     # type-aware token: current YYYYMM
      label: Revenue (this month)
  • kind: count — the report's record count; value — one aggregate cell (at pins dimensions via the existing typed-conditions filter; now resolves client-side: month(x) → current YYYYMM, year(x) → current year, date → today); list — the first limit rows as a mini table.
  • No new SQL machinery, endpoints, or file extensions: ReportIntentGenerator resolves authored expressions to the report's own column aliases into a widget block on the .report; the runtime is the existing generated report controller, fetched by the shared reports store (loadWidgetValue; 403 hides the tile for role-guarded reports).

Top-level widgets: — the custom escape hatch

kind: kpi is a number tile fed by a developer REST endpoint returning {value, description?} (value may be a display string like "99.9%"); kind: page embeds an HTML page like a report preview tile. The kind implies how the same-origin url is consumed — no separate source-type field.

Report Editor (Web IDE)

A new Dashboard Widget panel (enable, kind, label/icon, value-measure picker over the aggregate columns, at-pin table over the grouping columns, list limit) plus Description and Show on the home dashboard in General — hand-authored .report widgets for classic projects.

Semantics & i18n

Declared widgets flip the .model root dashboardKpis flag: the Harmonia shell bakes the entity tile list empty (no widgets → today's dashboard byte-identical), and a widget-bearing report loses its preview tile. Report + widget labels are translated end-to-end (new report-template translate source → <Name>-report catalogs; custom labels ride the model catalog; sidebar/dashboard/breadcrumb read them via displayLabel/widgetLabel).

Testing

Unit: IntentParserTest (10 widget cases), ReportIntentGeneratorTest, EdmIntentGeneratorTest. Integration: IntentEngineIT#report_widget_generates_the_kpi_block_and_replaces_entity_tiles (+ extended fixture). Verified live end-to-end on a demo project: count/value/list values over the generated controllers, the custom KPI endpoint, catalogs, entity-tile suppression and the no-widgets fallback.

Follow-ups (merge after this PR; inert on older parsers)

🤖 Generated with Claude Code

…s, Report Editor panel

Meaningful dashboard tiles instead of raw per-entity record counts, in
three layers:

- reports[].widget: a KPI tile backed by the report. kind count (the
  report's record count), value (one aggregate cell: `value` names a
  declared measure, `at` pins dimensions to the type-aware `now` token
  or a literal - month(x) -> current YYYYMM, year(x) -> current year,
  date -> today, resolved client-side), or list (first `limit` rows as
  a mini table). ReportIntentGenerator resolves authored expressions to
  the report's own column aliases and emits a `widget` block on the
  .report - no SQL and no URLs in the block; the runtime is the
  existing generated report controller (GET/POST /count, POST /search
  with typed conditions), fetched by the shared reports store
  (loadWidgetValue: apiBase derived from the discovered page path via a
  sanitizeJavaIdentifier mirror; 403 hides the tile for role-guarded
  reports).

- top-level widgets:: the custom escape hatch. kind kpi is a number
  tile fed by a developer REST endpoint returning {value, description?}
  (the value may be a display string); kind page embeds an HTML page
  like a report preview tile. The kind implies how the same-origin url
  is consumed - no separate source-type field. Baked onto the .model
  root by EdmIntentGenerator.

- editor-report: a Dashboard Widget panel (enable, kind, label/icon,
  value-measure picker over the aggregate columns, at-pin table over
  the grouping columns, list limit) plus Description and a dashboard
  checkbox in General - hand-authored .report widgets for classic
  projects.

Declared widgets flip the .model root dashboardKpis flag: the Harmonia
shell template bakes the entity tile list empty (no widgets -> today's
dashboard unchanged), and a widget-bearing report loses its preview
tile. Report and widget labels are translated end-to-end: the Harmonia
report-file template gains a translate source emitting the
<Name>-report catalog (report tId, columns, widget label), custom
widget labels ride the model catalog, and the sidebar/dashboard/
breadcrumb read them via the store's displayLabel/widgetLabel.

Covered by IntentParserTest/ReportIntentGeneratorTest/
EdmIntentGeneratorTest and IntentEngineIT
(report_widget_generates_the_kpi_block_and_replaces_entity_tiles);
verified live end-to-end (count/value/list values, custom KPI endpoint,
catalogs, entity-tile suppression and fallback). Samples and docs
follow in dirigiblelabs/sample-intent-model#5,
dirigiblelabs/sample-intent-multi-model#10 and
dirigible-io/dirigible-io.github.io#135 (merge after this).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@delchev delchev force-pushed the feat/dashboard-widgets branch from 3b4f1c9 to fd39c06 Compare July 3, 2026 18:46
@delchev delchev merged commit 919ef49 into master Jul 3, 2026
9 of 11 checks passed
@delchev delchev deleted the feat/dashboard-widgets branch July 3, 2026 18:46
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.

1 participant