@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 +83 -0
- package/README.md +104 -22
- package/dist/index.js +1695 -551
- package/dist/index.umd.cjs +18 -18
- package/dist/packages/plugin-report/src/JoinedReportRenderer.d.ts +47 -0
- package/dist/packages/plugin-report/src/LegacyReportRenderer.d.ts +14 -0
- package/dist/packages/plugin-report/src/MatrixRenderer.d.ts +51 -0
- package/dist/packages/plugin-report/src/MatrixRenderer.stories.d.ts +24 -0
- package/dist/packages/plugin-report/src/ReportRenderer.d.ts +41 -11
- package/dist/packages/plugin-report/src/SpecReportGrid.d.ts +49 -0
- package/dist/packages/plugin-report/src/SpecReportGrid.stories.d.ts +31 -0
- package/dist/packages/plugin-report/src/buildChartData.d.ts +38 -0
- package/dist/packages/plugin-report/src/drill.d.ts +63 -0
- package/dist/packages/plugin-report/src/hooks/useReportData.d.ts +131 -0
- package/dist/packages/plugin-report/src/index.d.ts +14 -1
- package/package.json +13 -10
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
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
- 📦 **Auto-registered**
|
|
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
|
-
##
|
|
52
|
+
## Spec Reports — the four variants
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
The plugin renders any `Report` defined by `@objectstack/spec`:
|
|
55
55
|
|
|
56
|
-
|
|
56
|
+
```ts
|
|
57
|
+
import type { ReportInput } from '@objectstack/spec/ui';
|
|
58
|
+
import { ReportRenderer } from '@object-ui/plugin-report';
|
|
57
59
|
|
|
58
|
-
|
|
59
|
-
|
|
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
|
-
|
|
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
|
-
|
|
82
|
+
### Matrix (row × column pivot)
|
|
65
83
|
|
|
66
|
-
```
|
|
67
|
-
|
|
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
|
-
|
|
95
|
+
`dateGranularity` accepts `day | week | month | quarter | year` and is
|
|
96
|
+
pushed down to the server-side aggregator.
|
|
71
97
|
|
|
72
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|