@object-ui/plugin-report 4.0.11 → 4.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,88 @@
1
1
  # @object-ui/plugin-report
2
2
 
3
+ ## 4.2.1
4
+
5
+ ### Patch Changes
6
+
7
+ - @object-ui/types@4.2.1
8
+ - @object-ui/core@4.2.1
9
+ - @object-ui/i18n@4.2.1
10
+ - @object-ui/react@4.2.1
11
+ - @object-ui/components@4.2.1
12
+ - @object-ui/fields@4.2.1
13
+ - @object-ui/plugin-grid@4.2.1
14
+
15
+ ## 4.2.0
16
+
17
+ ### Minor Changes
18
+
19
+ - 650392e: MatrixRenderer now displays i18n-translated labels for picklist (`select` / `status`) groupings instead of raw values (e.g. `Best Case` / `Commit` / `Pipeline` instead of `best_case` / `commit` / `pipeline`). Field labels in the corner cell, row/column total labels, and the `(Empty)` / `(All)` placeholders are also fully translated. Adds `report.*` keys to `en` and `zh` locale bundles.
20
+ - 26f5fce: Simplify report identity: replace the dashboard-style KPI grid with a compact "Totals" strip so reports look like reports (table-first with a grand total), not like mini-dashboards.
21
+ - `SpecReportGrid` now renders one inline `Totals: Label1: value Label2: value …` strip above the chart and table, styled as a muted single-line band — clearly subordinate to the data grid below.
22
+ - The Totals strip is now also shown for `tabular` reports when they declare aggregating columns (matches Salesforce's "Grand Total" convention).
23
+ - Drop the duplicate chart title `<div>`: the chart component already renders its own title from `report.chart.title`.
24
+ - Test ids renamed: `spec-report-kpis` → `spec-report-totals`, `spec-report-kpi-${key}` → `spec-report-total-${key}`.
25
+
26
+ Visual distinction from dashboards is now intentional: dashboard widgets use prominent floating KPI cards to convey "headline numbers"; report Totals describe the single dataset on the page and are intentionally compact.
27
+
28
+ - 84b4bf1: Summary reports now render i18n-translated labels in the chart axis, chart series legend, and totals strip. `buildChartData` accepts a new `labels` parameter so callers (currently `SpecReportGrid`) can supply field/column/aggregate/value resolvers. Replaces raw column keys (e.g. `Count of case_number`) and raw picklist values (e.g. `closed`, `in_progress`) with their translated display labels (e.g. `案例编号 · 计数`, `已关闭`, `处理中`). Adds `report.totals` locale key.
29
+
30
+ ### Patch Changes
31
+
32
+ - Updated dependencies [eb738bd]
33
+ - Updated dependencies [650392e]
34
+ - Updated dependencies [84b4bf1]
35
+ - @object-ui/i18n@4.2.0
36
+ - @object-ui/components@4.2.0
37
+ - @object-ui/fields@4.2.0
38
+ - @object-ui/react@4.2.0
39
+ - @object-ui/plugin-grid@4.2.0
40
+ - @object-ui/types@4.2.0
41
+ - @object-ui/core@4.2.0
42
+
43
+ ## 4.1.0
44
+
45
+ ### Minor Changes
46
+
47
+ - b4ce9e2: Fix summary reports: render chart + KPIs, correct empty-table on server-aggregated data.
48
+ - `plugin-report`: `SpecReportGrid` now renders a KPI strip (per aggregating column) and a chart section above the grid for `summary` reports. KPI section auto-hides when no aggregating columns. New `buildChartData()` adapter buckets aggregated `ReportRow[]` to chart-ready data, auto-sorts pie/funnel descending, and falls back to row count when the chart `yAxis` points at a non-numeric column. When the data is server-aggregated, the grid switches columns to `[groupings, ${field}__${agg}]` so cells aren't empty against a raw-row column schema.
49
+ - `plugin-charts`: register `'column'` as an alias of `'bar'` in `ChartRenderer` / `AdvancedChartImpl` (Recharts only has `BarChart`).
50
+ - `app-shell`: `ReportView` now routes any object-backed report (matrix/joined/summary/tabular/columns/groupingsAcross) through the spec `ReportRenderer`; fully-legacy `fields`+`data` schemas still use `ReportViewer`.
51
+
52
+ - b42a0d0: Server-side `dateGranularity` pushdown.
53
+
54
+ `useReportData()` reports with `{ groupBy: [{ field, dateGranularity }] }`
55
+ are now aggregated directly in the database via native SQL (`strftime` /
56
+ `to_char` / `date_format`) instead of fetching raw rows and bucketing in
57
+ Node. The framework's `driver-sql` advertises per-granularity support via
58
+ `IDataDriver.supports.queryDateGranularity` and the engine transparently
59
+ falls back to in-memory bucketing only when the dialect can't express a
60
+ given granularity (notably SQLite `week`, which needs `strftime('%V')`
61
+ added in SQLite 3.46). Output bucket labels (`2026-Q2`, `2026-01-15`,
62
+ `2026-W23`, …) are byte-for-byte identical between paths so drill
63
+ `groupKey` filters compose correctly across SQL and in-memory routes.
64
+
65
+ Requires framework ≥ commit `b26d217c`.
66
+
67
+ ### Patch Changes
68
+
69
+ - @object-ui/types@4.1.0
70
+ - @object-ui/core@4.1.0
71
+ - @object-ui/react@4.1.0
72
+ - @object-ui/components@4.1.0
73
+ - @object-ui/fields@4.1.0
74
+ - @object-ui/plugin-grid@4.1.0
75
+
76
+ ## 4.0.12
77
+
78
+ ### Patch Changes
79
+
80
+ - @object-ui/types@4.0.12
81
+ - @object-ui/core@4.0.12
82
+ - @object-ui/react@4.0.12
83
+ - @object-ui/components@4.0.12
84
+ - @object-ui/fields@4.0.12
85
+
3
86
  ## 4.0.11
4
87
 
5
88
  ### Patch Changes
package/README.md CHANGED
@@ -4,15 +4,15 @@ Report components for Object UI — build, view, render, and export reports with
4
4
 
5
5
  ## Features
6
6
 
7
- - 📊 **Report Builder** - Visual drag-and-drop report construction
8
- - 👁️ **Report Viewer** - Interactive report viewing with toolbar controls
9
- - 🎨 **Type-aware cells** - select → Badge, lookup → link, boolean → ✓/✗, email/url/phone → mailto/external/tel links, image → thumbnail, etc. (auto-hydrated from object metadata)
10
- - 🖨️ **Report Renderer** - Render reports from JSON definitions with charts
11
- - 📤 **Multi-Format Export** - Export to CSV, JSON, HTML, PDF, and Excel
12
- - 🔄 **Live Data Export** - Export with real-time data via `exportWithLiveData`
13
- - 📈 **Excel Formulas** - Export Excel files with live formulas via `exportExcelWithFormulas`
14
- - ⏰ **Schedule Config** - Configure recurring report generation and delivery
15
- - 📦 **Auto-registered** - Components register with `ComponentRegistry` on import
7
+ - 🧩 **Four spec report variants** — `tabular` / `summary` / `matrix` / `joined`, dispatched by a single `<ReportRenderer schema={...}>`
8
+ - 🧮 **Server-side aggregation** — `useReportData()` posts spec `QueryAST` to `POST /api/v1/data/:object/query`; transparent in-memory fallback
9
+ - 📅 **Date bucketing** — `dateGranularity: day|week|month|quarter|year` on `groupingsAcross` / `groupingsDown`
10
+ - 🪜 **Multi-level grouping + totals** — row totals, column totals, grand totals for matrix; tabular/summary delegate to `ObjectGrid`
11
+ - 🎯 **Cell drill-down** — every aggregated cell dispatches a `drill` action via `ActionRunner`; targets List view or a nested Report (M3)
12
+ - 🧱 **Joined reports** — vertically stacked sub-reports; each block owns its own `objectName`, filter and data fetch
13
+ - 🎨 **Type-aware cells** — `select` → Badge, `lookup` → link, `boolean` → ✓/✗, `email`/`url`/`phone` → links, `image` → thumbnail (auto-hydrated from object metadata)
14
+ - 🖨️ **Multi-format export** — CSV, JSON, HTML, PDF, Excel; live-data and Excel-formula variants
15
+ - 📦 **Auto-registered** — components register with `ComponentRegistry` on import; embed via `{ "type": "spec-report", "report": {...} }`
16
16
 
17
17
  ## Installation
18
18
 
@@ -49,33 +49,115 @@ function EmbeddedReport() {
49
49
  }
50
50
  ```
51
51
 
52
- ## API
52
+ ## Spec Reports — the four variants
53
53
 
54
- ### ReportBuilder
54
+ The plugin renders any `Report` defined by `@objectstack/spec`:
55
55
 
56
- Visual report construction interface:
56
+ ```ts
57
+ import type { ReportInput } from '@objectstack/spec/ui';
58
+ import { ReportRenderer } from '@object-ui/plugin-report';
57
59
 
58
- ```tsx
59
- <ReportBuilder report={initialReport} />
60
+ const report: ReportInput = {
61
+ name: 'opp_by_stage',
62
+ objectName: 'opportunity',
63
+ type: 'summary',
64
+ columns: [
65
+ { field: 'stage' },
66
+ { field: 'amount', aggregate: 'sum' },
67
+ { field: 'id', label: 'Deals', aggregate: 'count' },
68
+ ],
69
+ groupingsDown: [{ field: 'stage', sortOrder: 'asc' }],
70
+ };
71
+
72
+ <ReportRenderer schema={report} dataSource={ds} />
60
73
  ```
61
74
 
62
- ### ReportViewer
75
+ | `type` | Description |
76
+ | --------- | ---------------------------------------------------- |
77
+ | `tabular` | Flat record list |
78
+ | `summary` | Single-axis grouped + aggregated |
79
+ | `matrix` | Row × column pivot with cell aggregates and totals |
80
+ | `joined` | Vertically stacked sub-reports, each with own data |
63
81
 
64
- Interactive report viewer with toolbar:
82
+ ### Matrix (row × column pivot)
65
83
 
66
- ```tsx
67
- <ReportViewer report={reportDefinition} showToolbar />
84
+ ```ts
85
+ {
86
+ name: 'pipeline_by_quarter',
87
+ objectName: 'opportunity',
88
+ type: 'matrix',
89
+ columns: [{ field: 'amount', label: 'Pipeline', aggregate: 'sum' }],
90
+ groupingsDown: [{ field: 'forecast_category' }],
91
+ groupingsAcross: [{ field: 'close_date', dateGranularity: 'quarter' }],
92
+ }
68
93
  ```
69
94
 
70
- ### ReportRenderer
95
+ `dateGranularity` accepts `day | week | month | quarter | year` and is
96
+ pushed down to the server-side aggregator.
71
97
 
72
- Renders a report from a JSON chart configuration:
98
+ ### Joined (M3)
99
+
100
+ ```ts
101
+ {
102
+ name: 'churn_signals',
103
+ objectName: 'account', // container default
104
+ type: 'joined',
105
+ columns: [],
106
+ blocks: [
107
+ { name: 'at_risk', type: 'summary', columns: [...], filter: {...} },
108
+ { name: 'lost', type: 'summary', objectName: 'opportunity', columns: [...], filter: {...} },
109
+ ],
110
+ }
111
+ ```
112
+
113
+ Block rules: `objectName` falls back to the container; `filter` is ANDed
114
+ with the container's; each block runs an isolated `useReportData()` call;
115
+ `block.type` must not be `joined` (no recursion).
116
+
117
+ ## Server-side aggregation + drill-down
118
+
119
+ `useReportData()` translates a `Report` into spec `QueryAST` and posts it
120
+ to `POST /api/v1/data/:object/query`. If the endpoint is unavailable it
121
+ falls back transparently to `dataSource.find()` + client-side aggregation.
122
+
123
+ Every aggregated cell dispatches a `drill` action through `ActionRunner`:
73
124
 
74
125
  ```tsx
75
- <ReportRenderer title="Revenue" description="Q4 Revenue" chart={chartConfig} />
126
+ import { registerDrillHandler } from '@object-ui/plugin-report';
127
+ registerDrillHandler(actionRunner, { navigate: router.push });
128
+ ```
129
+
130
+ Drill targets:
131
+ 1. **List view** — default; navigates to the filtered records.
132
+ 2. **Report drawer** — if the host widget declares `drillDown.report`,
133
+ the click opens a side drawer that renders that report scoped to the
134
+ cell's group key (composes dashboard → report → record).
135
+
136
+ ## Filter-time date helpers — current limitation
137
+
138
+ The server does **not** currently evaluate `` cel`...` `` expressions
139
+ embedded in filter values. Use module-load ISO strings instead:
140
+
141
+ ```ts
142
+ const daysAgo = (n: number): string => {
143
+ const d = new Date();
144
+ d.setUTCDate(d.getUTCDate() - n);
145
+ return d.toISOString().slice(0, 10);
146
+ };
147
+
148
+ filter: { close_date: { $gte: daysAgo(30) } }
76
149
  ```
77
150
 
78
- ### Export Functions
151
+ See the bundled CRM `customer_churn_signals` demo for the full pattern.
152
+ Native filter-time CEL evaluation is tracked for a future major version.
153
+
154
+ ## Legacy components
155
+
156
+ `ReportBuilder`, `ReportViewer` and the export functions below remain
157
+ available for legacy presentation-layer reports and are not affected by
158
+ the spec-driven pipeline above.
159
+
160
+
79
161
 
80
162
  Export reports in multiple formats:
81
163