@object-ui/plugin-report 17.6.0 → 18.0.0
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 +2136 -0
- package/README.md +98 -14
- package/dist/DatasetReportRenderer.d.ts +17 -3
- package/dist/LiveReportExporter.d.ts +19 -0
- package/dist/ReportExportEngine.d.ts +18 -3
- package/dist/ReportRenderer.d.ts +2 -2
- package/dist/displayLocale.d.ts +70 -0
- package/dist/formatValue.d.ts +19 -1
- package/dist/index.d.ts +12 -12
- package/dist/index.js +537 -461
- package/dist/index.umd.cjs +22 -22
- package/dist/useDatasetDimensionLabels.d.ts +5 -3
- package/package.json +12 -15
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ Report components for Object UI — render, view and export reports, with schedu
|
|
|
12
12
|
- 🧱 **Joined reports** — vertically stacked sub-reports; each block names its own `dataset`, filter and ordering
|
|
13
13
|
- 🎨 **Type-aware cells** — the presentation-layer `ReportViewer` renders `select` → Badge, `lookup` → link, `boolean` → ✓/✗, `email`/`url`/`phone` → links, `image` → thumbnail
|
|
14
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": "
|
|
15
|
+
- 📦 **Auto-registered** — components register with `ComponentRegistry` on import; embed via `{ "type": "report", "report": {...} }`
|
|
16
16
|
|
|
17
17
|
## Installation
|
|
18
18
|
|
|
@@ -33,8 +33,12 @@ report-authoring component in this package (see
|
|
|
33
33
|
|
|
34
34
|
```tsx
|
|
35
35
|
import { ReportRenderer } from '@object-ui/plugin-report';
|
|
36
|
+
import type { DataSource } from '@object-ui/types';
|
|
36
37
|
|
|
37
38
|
// `dataSource` and `router` are host-provided.
|
|
39
|
+
declare const dataSource: DataSource;
|
|
40
|
+
declare const router: { push: (href: string) => void };
|
|
41
|
+
|
|
38
42
|
function ReportPage() {
|
|
39
43
|
return (
|
|
40
44
|
<ReportRenderer
|
|
@@ -57,9 +61,17 @@ already decided the shape — it takes the report as `report`, not `schema`:
|
|
|
57
61
|
|
|
58
62
|
```tsx
|
|
59
63
|
import { DatasetReportRenderer, isDatasetReport } from '@object-ui/plugin-report';
|
|
64
|
+
import type { DataSource } from '@object-ui/types';
|
|
65
|
+
|
|
66
|
+
// `stored` is whatever the host loaded; `dataSource` is host-provided.
|
|
67
|
+
declare const stored: unknown;
|
|
68
|
+
declare const dataSource: DataSource;
|
|
60
69
|
|
|
61
|
-
|
|
62
|
-
|
|
70
|
+
function StoredReportPage() {
|
|
71
|
+
if (isDatasetReport(stored)) {
|
|
72
|
+
return <DatasetReportRenderer report={stored} dataSource={dataSource} />;
|
|
73
|
+
}
|
|
74
|
+
return null;
|
|
63
75
|
}
|
|
64
76
|
```
|
|
65
77
|
|
|
@@ -69,6 +81,12 @@ that schema, not props of the component:
|
|
|
69
81
|
|
|
70
82
|
```tsx
|
|
71
83
|
import { ReportViewer } from '@object-ui/plugin-report';
|
|
84
|
+
import type { ReportComponentSchema } from '@object-ui/types';
|
|
85
|
+
|
|
86
|
+
// All three are host-provided.
|
|
87
|
+
declare const reportDefinition: ReportComponentSchema;
|
|
88
|
+
declare const rows: Array<Record<string, unknown>>;
|
|
89
|
+
declare const refetch: () => void;
|
|
72
90
|
|
|
73
91
|
function LegacyReportPage() {
|
|
74
92
|
return (
|
|
@@ -89,9 +107,13 @@ the report declares no object, no field, no aggregate and no date bucket of its
|
|
|
89
107
|
own. `defineReport` validates at authoring time and returns the parsed shape
|
|
90
108
|
`ReportRenderer` takes as `schema`:
|
|
91
109
|
|
|
92
|
-
```
|
|
110
|
+
```tsx
|
|
93
111
|
import { defineReport } from '@objectstack/spec/ui';
|
|
94
112
|
import { ReportRenderer } from '@object-ui/plugin-report';
|
|
113
|
+
import type { DataSource } from '@object-ui/types';
|
|
114
|
+
|
|
115
|
+
// `ds` is host-provided.
|
|
116
|
+
declare const ds: DataSource;
|
|
95
117
|
|
|
96
118
|
const report = defineReport({
|
|
97
119
|
name: 'opp_by_stage',
|
|
@@ -205,6 +227,14 @@ order, so ordering by the across dimension is what fixes the column order;
|
|
|
205
227
|
declaring nothing still reads correctly, because a selected time dimension
|
|
206
228
|
defaults to ascending.
|
|
207
229
|
|
|
230
|
+
With no `order`, a **select** dimension follows its field's declared option
|
|
231
|
+
order (table rows, matrix headers on both axes, the embedded chart's
|
|
232
|
+
categories): declared options first, values the options do not declare next in
|
|
233
|
+
the dataset's order, the empty bucket last. With several grouping dimensions the
|
|
234
|
+
outer one is laid out first and the inner one within each outer group; a
|
|
235
|
+
dimension whose field declares no options keeps the dataset's order. An
|
|
236
|
+
authored `order` keeps the server's order.
|
|
237
|
+
|
|
208
238
|
### Embedded chart
|
|
209
239
|
|
|
210
240
|
`chart.type` is one of the spec's chart names; `xAxis` / `yAxis` are **bare
|
|
@@ -234,6 +264,11 @@ defineReport({
|
|
|
234
264
|
`series`, `colors`, `height`, `showDataLabels`, `annotations` and `interaction`
|
|
235
265
|
are passed through to the chart as authored.
|
|
236
266
|
|
|
267
|
+
The chart runs its own `xAxis` × `yAxis` dataset query, so it binds the same way
|
|
268
|
+
on every non-`joined` type. It draws above a `tabular` or `summary` table, and
|
|
269
|
+
below the cross-tab of a `matrix` that declares `columns`; there `xAxis` may name
|
|
270
|
+
a `rows` or a `columns` dimension.
|
|
271
|
+
|
|
237
272
|
## Server-side aggregation + drill-down
|
|
238
273
|
|
|
239
274
|
A dataset-bound report selects its dimensions (`rows`, and for `matrix` also
|
|
@@ -246,6 +281,13 @@ pre-aggregated rows it is handed and never re-aggregates bucketed values
|
|
|
246
281
|
client-side, since measures like `avg` cannot be recombined without drifting
|
|
247
282
|
from the semantic layer.
|
|
248
283
|
|
|
284
|
+
When the dataset query is refused because the viewer may not read the data
|
|
285
|
+
(`403` / `PERMISSION_DENIED`, as the shared `classifyLoadError` from
|
|
286
|
+
`@object-ui/react` reads it), the report shows a localized "You don't have
|
|
287
|
+
access" state instead of its table, the same title a dataset dashboard widget
|
|
288
|
+
shows, and never the server's message. Any other failure still shows the error
|
|
289
|
+
and its message.
|
|
290
|
+
|
|
249
291
|
Drill-down is a **host callback, not a registered handler**: pass `onDrill` and
|
|
250
292
|
every aggregated row / matrix cell becomes clickable. The report emits *what was
|
|
251
293
|
clicked*; the host decides where that goes, because the renderer only knows
|
|
@@ -253,6 +295,12 @@ dimension names (ADR-0021 D2).
|
|
|
253
295
|
|
|
254
296
|
```tsx
|
|
255
297
|
import { ReportRenderer, type DatasetDrillArgs } from '@object-ui/plugin-report';
|
|
298
|
+
import type { DataSource, SpecReport } from '@object-ui/types';
|
|
299
|
+
|
|
300
|
+
// `report`, `dataSource` and `router` are host-provided.
|
|
301
|
+
declare const report: SpecReport;
|
|
302
|
+
declare const dataSource: DataSource;
|
|
303
|
+
declare const router: { push: (href: string) => void };
|
|
256
304
|
|
|
257
305
|
<ReportRenderer
|
|
258
306
|
schema={report}
|
|
@@ -284,13 +332,23 @@ The server does **not** currently evaluate `` cel`...` `` expressions
|
|
|
284
332
|
embedded in filter values. Use module-load ISO strings instead:
|
|
285
333
|
|
|
286
334
|
```ts
|
|
335
|
+
import { defineReport } from '@objectstack/spec/ui';
|
|
336
|
+
|
|
287
337
|
const daysAgo = (n: number): string => {
|
|
288
338
|
const d = new Date();
|
|
289
339
|
d.setUTCDate(d.getUTCDate() - n);
|
|
290
340
|
return d.toISOString().slice(0, 10);
|
|
291
341
|
};
|
|
292
342
|
|
|
293
|
-
|
|
343
|
+
defineReport({
|
|
344
|
+
name: 'recent_pipeline',
|
|
345
|
+
label: 'Recent Pipeline',
|
|
346
|
+
type: 'summary',
|
|
347
|
+
dataset: 'opportunity_pipeline',
|
|
348
|
+
rows: ['stage'],
|
|
349
|
+
values: ['amount_sum'],
|
|
350
|
+
runtimeFilter: { close_date: { $gte: daysAgo(30) } },
|
|
351
|
+
});
|
|
294
352
|
```
|
|
295
353
|
|
|
296
354
|
See the bundled CRM `customer_churn_signals` demo for the full pattern.
|
|
@@ -405,8 +463,12 @@ does not compile. It is the one `async` export function, resolving to a
|
|
|
405
463
|
|
|
406
464
|
```tsx
|
|
407
465
|
import { exportWithLiveData } from '@object-ui/plugin-report';
|
|
466
|
+
import type { DataSource, ReportComponentSchema } from '@object-ui/types';
|
|
408
467
|
|
|
409
468
|
// `myAdapter` is a host-provided DataSource (see @object-ui/data-*).
|
|
469
|
+
declare const myAdapter: DataSource;
|
|
470
|
+
declare const report: ReportComponentSchema;
|
|
471
|
+
|
|
410
472
|
const result = await exportWithLiveData(report, {
|
|
411
473
|
dataSource: myAdapter,
|
|
412
474
|
resource: 'orders',
|
|
@@ -427,6 +489,10 @@ spreadsheet line number:
|
|
|
427
489
|
|
|
428
490
|
```tsx
|
|
429
491
|
import { exportExcelWithFormulas } from '@object-ui/plugin-report';
|
|
492
|
+
import type { ReportComponentSchema } from '@object-ui/types';
|
|
493
|
+
|
|
494
|
+
declare const report: ReportComponentSchema;
|
|
495
|
+
declare const rows: Array<Record<string, unknown>>;
|
|
430
496
|
|
|
431
497
|
exportExcelWithFormulas(report, rows, {
|
|
432
498
|
columns: [
|
|
@@ -434,12 +500,22 @@ exportExcelWithFormulas(report, rows, {
|
|
|
434
500
|
{ name: 'total', header: 'Total', formula: '=B{ROW}*C{ROW}' },
|
|
435
501
|
],
|
|
436
502
|
includeAggregationRow: true,
|
|
503
|
+
locale: 'de-DE',
|
|
437
504
|
});
|
|
438
505
|
```
|
|
439
506
|
|
|
440
507
|
Omitting `columns` derives them from `report.fields`. `includeAggregationRow`
|
|
441
508
|
appends a totals row built from each field's `aggregation`.
|
|
442
509
|
|
|
510
|
+
`locale` is the BCP-47 tag the numeric cells are formatted in — above, an
|
|
511
|
+
`amount` of `1234.5` writes `1.234,50` rather than `1,234.50`. Pass the tag the
|
|
512
|
+
session renders in: `useDisplayLocale()` from `@object-ui/i18n` in React, or
|
|
513
|
+
whatever your non-React caller resolved. This function is not a component and a
|
|
514
|
+
display locale is a property of the session rather than of the authored report
|
|
515
|
+
schema, so its caller is the only place the tag can come from. Omitted, cells
|
|
516
|
+
format in `'en'` — the display channel's own last resort, which is neither
|
|
517
|
+
`'en-US'` nor the machine's locale (objectui#10020).
|
|
518
|
+
|
|
443
519
|
### Scheduled export
|
|
444
520
|
|
|
445
521
|
A schedule is **data on the report schema**, not a component: it is
|
|
@@ -453,9 +529,11 @@ and a completion callback:
|
|
|
453
529
|
|
|
454
530
|
```ts
|
|
455
531
|
import { createScheduleTrigger } from '@object-ui/plugin-report';
|
|
456
|
-
import type { ReportComponentSchema, ReportScheduleConfig } from '@object-ui/types';
|
|
532
|
+
import type { DataSource, ReportComponentSchema, ReportScheduleConfig } from '@object-ui/types';
|
|
457
533
|
|
|
458
534
|
// `dataSource` and `notify` are host-provided.
|
|
535
|
+
declare const dataSource: DataSource;
|
|
536
|
+
declare const notify: (recipients: string[], subject: string | undefined) => void;
|
|
459
537
|
|
|
460
538
|
const report: ReportComponentSchema = {
|
|
461
539
|
type: 'report',
|
|
@@ -490,19 +568,23 @@ it ran.
|
|
|
490
568
|
|
|
491
569
|
### Schema-Driven Usage
|
|
492
570
|
|
|
493
|
-
Importing the package registers
|
|
571
|
+
Importing the package registers two component types with `ComponentRegistry`:
|
|
572
|
+
|
|
573
|
+
| `type` | Component | Notes |
|
|
574
|
+
| --------------- | ---------------- | ------------------------------------------------------------ |
|
|
575
|
+
| `report` | `ReportRenderer` | The dispatcher. A spec report goes under its `report` key. |
|
|
576
|
+
| `report-viewer` | `ReportViewer` | Presentation-layer viewer. |
|
|
494
577
|
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
| `spec-report` | `ReportRenderer` | Spec-native alias; the report goes under `report`. |
|
|
499
|
-
| `report-viewer` | `ReportViewer` | Presentation-layer viewer. |
|
|
578
|
+
To embed a report, wrap the `@objectstack/spec` report definition (`ReportSchema`)
|
|
579
|
+
in a `report` node's `report` member. When `report` is present, the node renders
|
|
580
|
+
that report and reads none of its own presentation keys.
|
|
500
581
|
|
|
501
582
|
```json
|
|
502
583
|
{
|
|
503
|
-
"type": "
|
|
584
|
+
"type": "report",
|
|
504
585
|
"report": {
|
|
505
586
|
"name": "opp_by_stage",
|
|
587
|
+
"label": "Opportunities by Stage",
|
|
506
588
|
"type": "summary",
|
|
507
589
|
"dataset": "opportunity_pipeline",
|
|
508
590
|
"rows": ["stage"],
|
|
@@ -513,7 +595,9 @@ Importing the package registers three component types with `ComponentRegistry`:
|
|
|
513
595
|
|
|
514
596
|
There is no `report-builder` component type — the authoring component that name
|
|
515
597
|
addressed was removed in the 9.0 cutover, so a node declaring it resolves to
|
|
516
|
-
nothing.
|
|
598
|
+
nothing. `spec-report` is retired too (objectui#11440): it was an alias of `report`
|
|
599
|
+
carrying the same wrapper, and a node declaring it now resolves to nothing. Write
|
|
600
|
+
`"type": "report"` instead; the `report` member is unchanged.
|
|
517
601
|
|
|
518
602
|
### Type-aware cell rendering
|
|
519
603
|
|
|
@@ -24,6 +24,9 @@
|
|
|
24
24
|
* so an older server that returns no `totals` renders the plain cross-tab
|
|
25
25
|
* with no totals row/column. A matrix without `columns` degrades to the
|
|
26
26
|
* flat grouped table.
|
|
27
|
+
* - `chart` (any non-joined type) → the embedded chart, its own
|
|
28
|
+
* `chart.xAxis` × `chart.yAxis` dataset query: above the grouped / flat
|
|
29
|
+
* table, below the matrix cross-tab (objectui#10964).
|
|
27
30
|
* - `joined` → a vertical stack of blocks, each its own dataset-bound table,
|
|
28
31
|
* with the report-level `runtimeFilter` merged into every block.
|
|
29
32
|
*
|
|
@@ -40,6 +43,17 @@
|
|
|
40
43
|
* never a client-side re-sort: sorting here would order the truncated page
|
|
41
44
|
* rather than the query, and could not sort by a derived measure at all.
|
|
42
45
|
*
|
|
46
|
+
* Declaring NO `order` leaves the grid in the dataset's `GROUP BY` order — the
|
|
47
|
+
* stored values' alphabetical order — which for a select dimension is not the
|
|
48
|
+
* domain order. So, and only then, this renderer lays a select dimension's
|
|
49
|
+
* groups out in its field's DECLARED option order (objectui#12243, the reading
|
|
50
|
+
* objectui#11809 set for grid groups and dashboard charts): the table rows, the
|
|
51
|
+
* matrix headers on both axes and the embedded chart's categories. Declared
|
|
52
|
+
* options first, undeclared values next in the dataset's order, the empty
|
|
53
|
+
* bucket last; a dimension without options keeps its arrival order. It moves
|
|
54
|
+
* nothing the server ordered on the author's behalf (see
|
|
55
|
+
* `arrangeByDeclaredOptions`).
|
|
56
|
+
*
|
|
43
57
|
* For a matrix that also decides the ACROSS axis: `colHeaders` are collected in
|
|
44
58
|
* row-arrival order, so ordering the rows by the across dimension is what makes
|
|
45
59
|
* the columns read left-to-right in that order. Declaring nothing still reads
|
|
@@ -155,7 +169,7 @@ export type ReportChartPlan =
|
|
|
155
169
|
| {
|
|
156
170
|
kind: 'single_value';
|
|
157
171
|
}
|
|
158
|
-
/** Tabular family — the
|
|
172
|
+
/** Tabular family — the report's own table beside it IS the rendering; no duplicate chart. */
|
|
159
173
|
| {
|
|
160
174
|
kind: 'tabular';
|
|
161
175
|
}
|
|
@@ -176,8 +190,8 @@ export type ReportChartPlan =
|
|
|
176
190
|
* - the single-value families (`gauge` / `solid-gauge` / `metric` / `kpi` /
|
|
177
191
|
* `bullet`) render the measure as a number — the spec's own comment calls
|
|
178
192
|
* them "honest single-value variants pending a real dial/target renderer";
|
|
179
|
-
* - `table` / `pivot` add no duplicate chart: the
|
|
180
|
-
*
|
|
193
|
+
* - `table` / `pivot` add no duplicate chart: the table that always renders
|
|
194
|
+
* beside the chart slot is exactly the tabular presentation;
|
|
181
195
|
* - anything else is out-of-spec and gets a visible notice.
|
|
182
196
|
*
|
|
183
197
|
* `combo` joined `ChartTypeSchema` in spec 17.0.0-rc.1 and routes as a series
|
|
@@ -13,6 +13,13 @@ export interface LiveExportOptions {
|
|
|
13
13
|
format?: ReportExportFormat;
|
|
14
14
|
/** Export config override */
|
|
15
15
|
exportConfig?: ReportExportConfig;
|
|
16
|
+
/**
|
|
17
|
+
* BCP-47 display tag for the HTML / PDF "Generated:" time — in React,
|
|
18
|
+
* whatever `useDisplayLocale()` (`@object-ui/i18n`) returned for the session.
|
|
19
|
+
* Omitted, `exportReport` falls back to the display channel's own last
|
|
20
|
+
* resort, never to the machine's locale (objectui#9909).
|
|
21
|
+
*/
|
|
22
|
+
locale?: string;
|
|
16
23
|
}
|
|
17
24
|
/**
|
|
18
25
|
* Excel column configuration for formatted export
|
|
@@ -83,6 +90,18 @@ export declare function exportExcelWithFormulas(report: ReportComponentSchema, d
|
|
|
83
90
|
columns?: ExcelColumnConfig[];
|
|
84
91
|
filename?: string;
|
|
85
92
|
includeAggregationRow?: boolean;
|
|
93
|
+
/**
|
|
94
|
+
* BCP-47 tag the numeric cells are formatted in — in React, whatever
|
|
95
|
+
* `useDisplayLocale()` (`@object-ui/i18n`) returned for the session.
|
|
96
|
+
*
|
|
97
|
+
* It lives on the OPTIONS BAG because this module is not a component and
|
|
98
|
+
* has no hook to read: a locale can only reach it from its caller, and a
|
|
99
|
+
* report schema is the wrong carrier for it (a display locale is a property
|
|
100
|
+
* of the session, not of the authored report). Omitted, it falls back to
|
|
101
|
+
* the display channel's own last resort — never to `'en-US'`, and never to
|
|
102
|
+
* a dropped tag, which would mean the MACHINE's locale (objectui#10020).
|
|
103
|
+
*/
|
|
104
|
+
locale?: string;
|
|
86
105
|
}): void;
|
|
87
106
|
/**
|
|
88
107
|
* Create a schedule trigger that can be invoked by workflow engines.
|
|
@@ -2,6 +2,21 @@ import { ReportComponentSchema, ReportExportConfig, ReportExportFormat } from '@
|
|
|
2
2
|
/**
|
|
3
3
|
* Report Export Engine
|
|
4
4
|
* Handles exporting report data to various formats using browser-native APIs.
|
|
5
|
+
*
|
|
6
|
+
* ## The export's display locale (objectui#9909)
|
|
7
|
+
*
|
|
8
|
+
* The HTML and PDF exports stamp a "Generated:" time into a file the reader
|
|
9
|
+
* downloads and keeps. That time used to be `new Date().toLocaleString()` —
|
|
10
|
+
* no tag, i.e. the MACHINE's locale, which is neither of the repo's two
|
|
11
|
+
* locale channels. The functions below take the tag as a trailing, OPTIONAL
|
|
12
|
+
* `locale` parameter — the same additive shape `formatValue` took in
|
|
13
|
+
* objectui#10020, and for the same reason: they are published exports, so a
|
|
14
|
+
* required parameter would break every existing caller. Omitted, it falls back
|
|
15
|
+
* to {@link DISPLAY_LOCALE_LAST_RESORT}, the display channel's own last resort
|
|
16
|
+
* — never to a dropped tag. In React the caller passes `useDisplayLocale()`;
|
|
17
|
+
* `ReportViewer` does. ⚠️ A display locale is a property of the SESSION, not
|
|
18
|
+
* of the authored report, so it is deliberately NOT a `ReportExportConfig`
|
|
19
|
+
* member: that type is authored metadata (`exportConfigs` on the schema).
|
|
5
20
|
*/
|
|
6
21
|
/**
|
|
7
22
|
* Export report data as CSV
|
|
@@ -14,11 +29,11 @@ export declare function exportAsJSON(report: ReportComponentSchema, data: any[],
|
|
|
14
29
|
/**
|
|
15
30
|
* Export report as HTML (printable format)
|
|
16
31
|
*/
|
|
17
|
-
export declare function exportAsHTML(report: ReportComponentSchema, data: any[], config?: ReportExportConfig): void;
|
|
32
|
+
export declare function exportAsHTML(report: ReportComponentSchema, data: any[], config?: ReportExportConfig, locale?: string): void;
|
|
18
33
|
/**
|
|
19
34
|
* Export report as PDF using browser print
|
|
20
35
|
*/
|
|
21
|
-
export declare function exportAsPDF(report: ReportComponentSchema, data: any[], config?: ReportExportConfig): void;
|
|
36
|
+
export declare function exportAsPDF(report: ReportComponentSchema, data: any[], config?: ReportExportConfig, locale?: string): void;
|
|
22
37
|
/**
|
|
23
38
|
* Export report as Excel-compatible CSV (with BOM for proper UTF-8 in Excel)
|
|
24
39
|
*/
|
|
@@ -26,4 +41,4 @@ export declare function exportAsExcel(report: ReportComponentSchema, data: any[]
|
|
|
26
41
|
/**
|
|
27
42
|
* Main export function - routes to correct format handler
|
|
28
43
|
*/
|
|
29
|
-
export declare function exportReport(format: ReportExportFormat, report: ReportComponentSchema, data: any[], config?: ReportExportConfig): void;
|
|
44
|
+
export declare function exportReport(format: ReportExportFormat, report: ReportComponentSchema, data: any[], config?: ReportExportConfig, locale?: string): void;
|
package/dist/ReportRenderer.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { SpecReport, DataSource } from '@object-ui/types';
|
|
2
|
-
import { LegacyReportRendererProps } from './LegacyReportRenderer';
|
|
3
|
-
import { DatasetDrillArgs } from './DatasetReportRenderer';
|
|
2
|
+
import { LegacyReportRendererProps } from './LegacyReportRenderer.js';
|
|
3
|
+
import { DatasetDrillArgs } from './DatasetReportRenderer.js';
|
|
4
4
|
/**
|
|
5
5
|
* ReportRenderer
|
|
6
6
|
*
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ObjectUI
|
|
3
|
+
* Copyright (c) 2024-present ObjectStack Inc.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* displayLocale — the one place this package spells the display locale's LAST
|
|
10
|
+
* RESORT, and the one place it formats a number with a THREADED tag.
|
|
11
|
+
*
|
|
12
|
+
* Two module-private copies of both used to be the alternative (`formatValue`
|
|
13
|
+
* and `LiveReportExporter` each hard-coded `'en-US'`), which is how the
|
|
14
|
+
* divergence objectui#10020 records happened in the first place: a package can
|
|
15
|
+
* only contradict a contract it states in more than one place.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* `'en'` — the tag `useDisplayLocale` (`@object-ui/i18n`) itself falls back to
|
|
19
|
+
* when neither the tenant's regional default nor the active UI language
|
|
20
|
+
* answers. Quoted from that hook's contract, which names BOTH alternatives as
|
|
21
|
+
* wrong answers:
|
|
22
|
+
*
|
|
23
|
+
* > `'en'` — a concrete last resort rather than `undefined`. `undefined`
|
|
24
|
+
* > would hand `Intl` the *machine's* locale, which is invisible in review
|
|
25
|
+
* > and non-deterministic in CI; `'en'` at least fails the same way
|
|
26
|
+
* > everywhere. Note this is `'en'`, not `'en-US'`: the point of
|
|
27
|
+
* > objectui#4033 is that `en-US` is not the world's default.
|
|
28
|
+
*
|
|
29
|
+
* So this constant may become neither `'en-US'` (the tag objectui#10020 removed
|
|
30
|
+
* from five display sites in this package) nor `undefined` (objectui#9909's
|
|
31
|
+
* separate defect shape, which `ReportExportEngine.ts`'s "Generated:" time
|
|
32
|
+
* carried until that card threaded a locale there, defaulting to this same
|
|
33
|
+
* constant).
|
|
34
|
+
*
|
|
35
|
+
* ⚠️ It is a local re-spelling of that literal, not an import of it:
|
|
36
|
+
* `@object-ui/i18n` exports the HOOK but no constant for the tag inside it, and
|
|
37
|
+
* a plain formatter cannot call a hook. Anything that moves the contract's last
|
|
38
|
+
* resort has to move this line too — pinned from the behavioural side by
|
|
39
|
+
* `__tests__/reportDisplayLocale-10020.test.tsx`, which asserts the omitted
|
|
40
|
+
* argument agrees with an explicit `'en'`.
|
|
41
|
+
*/
|
|
42
|
+
export declare const DISPLAY_LOCALE_LAST_RESORT = "en";
|
|
43
|
+
/**
|
|
44
|
+
* `Number.prototype.toLocaleString` with a tag that came from OUTSIDE this
|
|
45
|
+
* module.
|
|
46
|
+
*
|
|
47
|
+
* The retry is load-bearing rather than defensive, and it is the threading
|
|
48
|
+
* itself that makes it so: a hard-coded literal can never be malformed, while a
|
|
49
|
+
* threaded tag originates in tenant configuration (ADR-0053) and reaches here
|
|
50
|
+
* verbatim. `Intl` throws `RangeError` on a malformed tag — measured on
|
|
51
|
+
* `'en_US'`, underscore instead of hyphen, the likeliest such typo — and these
|
|
52
|
+
* call sites are inside a cell render, so an uncaught throw takes the whole
|
|
53
|
+
* report down rather than misformatting one number.
|
|
54
|
+
*
|
|
55
|
+
* ⚠️ The degradation is to {@link DISPLAY_LOCALE_LAST_RESORT}, NOT to a dropped
|
|
56
|
+
* tag, because this package's display tags follow `useDisplayLocale`'s
|
|
57
|
+
* contract: in React the tag IS that hook's value, and an omitted one defaults
|
|
58
|
+
* to the hook's own last resort. Under that contract, dropping the tag hands
|
|
59
|
+
* `Intl` the machine's locale — the other answer the contract quoted above
|
|
60
|
+
* rules out, non-deterministic in CI and invisible in review.
|
|
61
|
+
*
|
|
62
|
+
* `@object-ui/core`'s sibling retry (`formatNumberInLocale`, through
|
|
63
|
+
* `formatDisplayNumber`) drops the tag instead. That is a deliberate
|
|
64
|
+
* difference, not an oversight, and not a wrong answer: `core` is the
|
|
65
|
+
* React-free formatter, and where its retry lands is what its own declared
|
|
66
|
+
* contract (`DisplayNumberFormatOptions.locale`) gives a caller with no tag in
|
|
67
|
+
* hand — the runtime default, the viewer's own environment. Each retry follows
|
|
68
|
+
* its own package's declared contract (objectui#10098).
|
|
69
|
+
*/
|
|
70
|
+
export declare function formatNumberInDisplayLocale(value: number, locale: string, options?: Intl.NumberFormatOptions): string;
|
package/dist/formatValue.d.ts
CHANGED
|
@@ -2,5 +2,23 @@ import { ReportField } from '@object-ui/types';
|
|
|
2
2
|
/**
|
|
3
3
|
* Format a cell value based on the field definition.
|
|
4
4
|
* Handles number (with thousand separators), currency, percent, and date formatting.
|
|
5
|
+
*
|
|
6
|
+
* `locale` is the BCP-47 DISPLAY tag the numeric branches below format in —
|
|
7
|
+
* in React, whatever `useDisplayLocale()` returned for the session. It is
|
|
8
|
+
* OPTIONAL, and that is a deliberate contract decision rather than convenience
|
|
9
|
+
* (objectui#10020): this function is a published export of
|
|
10
|
+
* `@object-ui/plugin-report`, so a REQUIRED third parameter would be a breaking
|
|
11
|
+
* change to a public signature. Optional is purely additive — everything that
|
|
12
|
+
* compiled before compiles after.
|
|
13
|
+
*
|
|
14
|
+
* ⚠️ The cost of that choice, named rather than hidden: an OPTIONAL locale
|
|
15
|
+
* leaves a leg that is still wrong when nobody passes one. Closing it is the
|
|
16
|
+
* caller's job, and inside this repo every caller does — `ReportViewer` is a
|
|
17
|
+
* component and resolves `useDisplayLocale()` itself at all three of its call
|
|
18
|
+
* sites, pinned in `__tests__/reportDisplayLocale-10020.test.tsx`. An OPTIONAL
|
|
19
|
+
* parameter nobody passes is the same defect with a longer signature.
|
|
20
|
+
*
|
|
21
|
+
* The default is {@link DISPLAY_LOCALE_LAST_RESORT} — the contract's own last
|
|
22
|
+
* resort, which is neither the `'en-US'` this card removed nor an absent tag.
|
|
5
23
|
*/
|
|
6
|
-
export declare function formatValue(value: any, field?: ReportField): string;
|
|
24
|
+
export declare function formatValue(value: any, field?: ReportField, locale?: string): string;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { ReportRenderer } from './ReportRenderer';
|
|
2
|
-
import { LegacyReportRenderer } from './LegacyReportRenderer';
|
|
3
|
-
import { ReportViewer } from './ReportViewer';
|
|
4
|
-
import { DatasetReportRenderer, isDatasetReport } from './DatasetReportRenderer';
|
|
1
|
+
import { ReportRenderer } from './ReportRenderer.js';
|
|
2
|
+
import { LegacyReportRenderer } from './LegacyReportRenderer.js';
|
|
3
|
+
import { ReportViewer } from './ReportViewer.js';
|
|
4
|
+
import { DatasetReportRenderer, isDatasetReport } from './DatasetReportRenderer.js';
|
|
5
5
|
export { ReportRenderer, LegacyReportRenderer, ReportViewer, DatasetReportRenderer, isDatasetReport };
|
|
6
|
-
export type { ReportRendererProps, ReportRendererSchema } from './ReportRenderer';
|
|
7
|
-
export type { LegacyReportRendererProps } from './LegacyReportRenderer';
|
|
8
|
-
export type { DatasetReportRendererProps, DatasetDrillArgs } from './DatasetReportRenderer';
|
|
9
|
-
export { formatValue } from './formatValue';
|
|
10
|
-
export { exportReport, exportAsCSV, exportAsJSON, exportAsHTML, exportAsPDF, exportAsExcel } from './ReportExportEngine';
|
|
11
|
-
export { exportWithLiveData, exportExcelWithFormulas, createScheduleTrigger, } from './LiveReportExporter';
|
|
12
|
-
export type { LiveExportOptions, LiveExportResult, ExcelColumnConfig, ScheduleTriggerCallback, } from './LiveReportExporter';
|
|
13
|
-
export { mergeFilters } from './mergeFilters';
|
|
6
|
+
export type { ReportRendererProps, ReportRendererSchema } from './ReportRenderer.js';
|
|
7
|
+
export type { LegacyReportRendererProps } from './LegacyReportRenderer.js';
|
|
8
|
+
export type { DatasetReportRendererProps, DatasetDrillArgs } from './DatasetReportRenderer.js';
|
|
9
|
+
export { formatValue } from './formatValue.js';
|
|
10
|
+
export { exportReport, exportAsCSV, exportAsJSON, exportAsHTML, exportAsPDF, exportAsExcel } from './ReportExportEngine.js';
|
|
11
|
+
export { exportWithLiveData, exportExcelWithFormulas, createScheduleTrigger, } from './LiveReportExporter.js';
|
|
12
|
+
export type { LiveExportOptions, LiveExportResult, ExcelColumnConfig, ScheduleTriggerCallback, } from './LiveReportExporter.js';
|
|
13
|
+
export { mergeFilters } from './mergeFilters.js';
|