@object-ui/plugin-dashboard 14.0.0 → 15.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 CHANGED
@@ -1,5 +1,121 @@
1
1
  # @object-ui/plugin-dashboard
2
2
 
3
+ ## 15.0.0
4
+
5
+ ### Patch Changes
6
+
7
+ - @object-ui/types@15.0.0
8
+ - @object-ui/core@15.0.0
9
+ - @object-ui/i18n@15.0.0
10
+ - @object-ui/react@15.0.0
11
+ - @object-ui/components@15.0.0
12
+ - @object-ui/fields@15.0.0
13
+
14
+ ## 14.1.0
15
+
16
+ ### Minor Changes
17
+
18
+ - 5523fc4: Dashboard-level filters — the three #2578 item-5 enhancements (framework#2501):
19
+
20
+ - **react**: nested `PageVariablesProvider`s now MERGE instead of shadowing
21
+ wholesale. A filtered dashboard embedded in a Page with its own `variables`
22
+ keeps the outer page variables readable inside widget subtrees (`page.*`);
23
+ an inner definition shadows only the SAME name; writes route to the scope
24
+ that defines the variable (writing an outer-defined name from inside the
25
+ nested subtree updates the outer provider); `resetVariables` stays local.
26
+ Names defined nowhere still write locally, exactly as before.
27
+ - **core**: `buildWidgetScopedFilter` accepts an optional `knownFields` set —
28
+ a DEFAULT binding whose target field is not on the widget's object is
29
+ skipped with a console warning instead of emitting a query the backend
30
+ empty-matches. Explicit `filterBindings` strings are always honoured (a
31
+ typo surfaces as a visibly empty widget, never a silently dropped filter).
32
+ Omitting `knownFields` preserves the previous unchecked behaviour.
33
+ - **plugin-dashboard**: `DashboardRenderer` feeds `knownFields` from
34
+ `dataSource.getObjectSchema` for inline `object` widgets (best-effort —
35
+ unchecked while metadata loads or when the source can't describe objects).
36
+ `optionsFrom` dynamic filter options now resolve DISTINCT values
37
+ server-side via a dataset GROUP BY (`queryDataset` with an inline draft)
38
+ when the data source supports it, falling back to the previous client-side
39
+ top-200 dedupe otherwise.
40
+
41
+ - 887062c: feat(dashboard): dashboard-level filters (date / region) driving multiple charts (framework#2501)
42
+
43
+ A dashboard's `dateRange` + `globalFilters` declarations are now wired end to
44
+ end: the filter values live as dashboard-level variables (the page variables
45
+ primitive, so they're also readable as `page.<name>` in widget expressions),
46
+ a filter bar renders above the widgets, and at render time the dashboard
47
+ broadcasts the active values into every bound widget's inline query —
48
+ `AND`-merged with the widget's own `filter`. Charts stay inline and
49
+ self-contained; each widget maps a filter to **its own** field.
50
+
51
+ - **`@object-ui/types`** — `globalFilters[].name` (stable filter/variable key,
52
+ defaults to `field`) and `DashboardWidgetSchema.filterBindings`
53
+ (`Record<string, string | false>`: per-widget field override / `false`
54
+ opt-out). Zod mirrors included. **Pending paired `@objectstack/spec`
55
+ alignment (framework#2501)** — same precedent as `dataset` /
56
+ `categoryGranularity`.
57
+ - **`@object-ui/core`** — new pure `dashboard-filters` module
58
+ (`resolveDashboardFilterDefs`, `dashboardFilterVariableDefs`,
59
+ `buildFilterCondition`, `buildWidgetScopedFilter`); `mergeFilters` lifted
60
+ from plugin-report (re-exported there unchanged). Date presets emit
61
+ date-macro tokens (`{30_days_ago}` …) so widgets resolve them at query time
62
+ like hand-authored filters.
63
+ - **`@object-ui/plugin-dashboard`** — `DashboardFilterBar` (date presets +
64
+ custom range calendar, select with static `options` or `optionsFrom`,
65
+ text/number inputs, reset); `DashboardRenderer` mounts a
66
+ `PageVariablesProvider` when filters are declared and merges the
67
+ widget-scoped condition into inline widgets' `filter` and dataset widgets'
68
+ `runtimeFilter`. Dashboards without filters render exactly as before.
69
+
70
+ Binding precedence: explicit `filterBindings` string/`false` → legacy
71
+ `targetWidgets` allow-list → the filter's own `field` (dateRange defaults to
72
+ `created_at`). Static-data widgets are not filtered.
73
+
74
+ ### Patch Changes
75
+
76
+ - 2ded18c: Fix: a dashboard filter declaring its static `options` in the
77
+ `@objectstack/spec` object form (`options: [{ value, label }]` — the shape
78
+ the spec validates and what framework-authored dashboards ship) crashed the
79
+ whole dashboard with "Objects are not valid as a React child". Caught driving
80
+ the showcase Revenue Pulse dashboard in a real browser.
81
+
82
+ `resolveDashboardFilterDefs` now normalizes both the spec object form and the
83
+ bare-string shorthand (`options: ['EMEA']`) to `{ value, label }` pairs —
84
+ `DashboardFilterDef.options` is typed accordingly — and the filter bar's
85
+ select renders labels (the trigger now shows the selected option's label, not
86
+ its raw value). `@object-ui/types` aligns the `GlobalFilterSchema.options`
87
+ shape with the spec union.
88
+
89
+ - Updated dependencies [82441e4]
90
+ - Updated dependencies [2efa9fd]
91
+ - Updated dependencies [0890fa7]
92
+ - Updated dependencies [2ded18c]
93
+ - Updated dependencies [e628d1f]
94
+ - Updated dependencies [5523fc4]
95
+ - Updated dependencies [887062c]
96
+ - Updated dependencies [579b24d]
97
+ - Updated dependencies [2b30583]
98
+ - Updated dependencies [23d65c3]
99
+ - Updated dependencies [055e1d2]
100
+ - Updated dependencies [9e2d58f]
101
+ - Updated dependencies [dea65f7]
102
+ - Updated dependencies [f30ff68]
103
+ - Updated dependencies [073e7aa]
104
+ - Updated dependencies [3e8bf07]
105
+ - Updated dependencies [6c0135c]
106
+ - Updated dependencies [5b52624]
107
+ - Updated dependencies [4afb251]
108
+ - Updated dependencies [d5b1bc0]
109
+ - Updated dependencies [f94905d]
110
+ - Updated dependencies [2712fc1]
111
+ - Updated dependencies [f0f10f5]
112
+ - @object-ui/i18n@14.1.0
113
+ - @object-ui/fields@14.1.0
114
+ - @object-ui/core@14.1.0
115
+ - @object-ui/types@14.1.0
116
+ - @object-ui/react@14.1.0
117
+ - @object-ui/components@14.1.0
118
+
3
119
  ## 14.0.0
4
120
 
5
121
  ### Patch Changes
package/README.md CHANGED
@@ -195,6 +195,78 @@ const schema = {
195
195
  };
196
196
  ```
197
197
 
198
+ ## Dashboard-level filters
199
+
200
+ A dashboard can declare top-level filters — a date range and any number of
201
+ select / text filters — whose values drive **every bound widget at once**.
202
+ The filter values live as dashboard-level variables (the page/dashboard
203
+ variables primitive), and each widget declares which of **its own** fields a
204
+ filter binds to. At render time the dashboard merges the active filter values
205
+ into each bound widget's inline query (`AND`-combined with the widget's own
206
+ `filter`).
207
+
208
+ ```jsonc
209
+ {
210
+ "type": "dashboard",
211
+ "dateRange": {
212
+ "field": "created_at", // default binding target
213
+ "defaultRange": "last_30_days", // today | this_week | … | last_90_days | custom
214
+ "allowCustomRange": true // offer a custom from/to calendar
215
+ },
216
+ "globalFilters": [
217
+ {
218
+ "name": "region", // stable filter name (defaults to field)
219
+ "field": "region", // default binding target
220
+ "label": "Region",
221
+ "type": "select", // text | select | date | number | lookup
222
+ "options": ["EMEA", "APAC", "AMER"]
223
+ // or dynamic: "optionsFrom": { "object": "accounts", "valueField": "region" }
224
+ }
225
+ ],
226
+ "widgets": [
227
+ // Default binding: the filter's own `field` (dateRange → created_at).
228
+ { "id": "w1", "type": "bar", "object": "invoices", "aggregate": "count" },
229
+ // Explicit binding: map each filter to THIS widget's own field.
230
+ {
231
+ "id": "w2", "type": "line", "object": "accounts", "aggregate": "count",
232
+ "filterBindings": { "dateRange": "signed_at", "region": "sales_region" }
233
+ },
234
+ // Opt out of a filter with `false`.
235
+ {
236
+ "id": "w3", "type": "metric", "object": "invoices", "aggregate": "count",
237
+ "filterBindings": { "region": false }
238
+ }
239
+ ]
240
+ }
241
+ ```
242
+
243
+ Binding rules, in precedence order:
244
+
245
+ 1. `filterBindings[name]` as a string — apply the filter to that field.
246
+ 2. `filterBindings[name]: false` — opt this widget out.
247
+ 3. Legacy `targetWidgets` on the filter — when set, only listed widget ids
248
+ get the default binding (an explicit `filterBindings` entry still wins).
249
+ 4. Otherwise the filter applies to its own `field` (the built-in date range
250
+ defaults to `dateRange.field ?? 'created_at'`).
251
+
252
+ Notes:
253
+
254
+ - Date presets stay symbolic (`{30_days_ago}` … date-macro tokens) until
255
+ query time, so widgets resolve them exactly like hand-authored filters.
256
+ - Dataset-bound widgets receive the merged filter through the dataset
257
+ query's `runtimeFilter`.
258
+ - Static-data widgets (inline `data` arrays) have no query to scope and are
259
+ not filtered.
260
+ - Filter values are also readable in widget expressions as `page.<name>`
261
+ (e.g. `page.region`), since they are hosted as dashboard variables.
262
+ - `optionsFrom` resolves distinct option values server-side (a dataset
263
+ GROUP BY) when the data source supports dataset queries, falling back to
264
+ a client-side dedupe over the first 200 records otherwise.
265
+ - Default bindings are metadata-aware for inline `object` widgets: a default
266
+ field that doesn't exist on the widget's object is skipped with a console
267
+ warning instead of emitting a query that matches nothing. Explicit
268
+ `filterBindings` strings are always honoured as written.
269
+
198
270
  ## TypeScript Support
199
271
 
200
272
  ```typescript
@@ -0,0 +1,12 @@
1
+ import { default as React } from 'react';
2
+ import { DashboardFilterDef } from '@object-ui/core';
3
+ export interface DashboardFilterBarProps {
4
+ defs: DashboardFilterDef[];
5
+ values: Record<string, any>;
6
+ onChange: (name: string, value: any) => void;
7
+ onReset?: () => void;
8
+ dataSource?: any;
9
+ className?: string;
10
+ }
11
+ export declare function DashboardFilterBar({ defs, values, onChange, onReset, dataSource, className }: DashboardFilterBarProps): React.JSX.Element | null;
12
+ //# sourceMappingURL=DashboardFilterBar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DashboardFilterBar.d.ts","sourceRoot":"","sources":["../src/DashboardFilterBar.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;;;GAQG;AAEH,OAAO,KAAuC,MAAM,OAAO,CAAC;AAiB5D,OAAO,EAEL,KAAK,kBAAkB,EAExB,MAAM,iBAAiB,CAAC;AAOzB,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,kBAAkB,EAAE,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5B,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;IAC7C,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,UAAU,CAAC,EAAE,GAAG,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA2ND,wBAAgB,kBAAkB,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,EAAE,uBAAuB,4BAyCrH"}
@@ -39,5 +39,20 @@ export interface DashboardRendererProps {
39
39
  hideHeaderText?: boolean;
40
40
  [key: string]: any;
41
41
  }
42
+ /**
43
+ * DashboardRenderer — the public dashboard renderer.
44
+ *
45
+ * When the schema declares dashboard-level filters (`globalFilters` /
46
+ * `dateRange`, framework#2501), their values are hosted as dashboard
47
+ * variables in a `PageVariablesProvider` (the page/dashboard variables
48
+ * primitive) so the filter bar can write them, the widget broadcast can read
49
+ * them, and widget expressions can reference them as `page.<name>`.
50
+ * Dashboards without filters render exactly as before — no provider mounted.
51
+ *
52
+ * When a filtered dashboard is embedded inside a Page with its own
53
+ * variables, the nested providers MERGE (#2578 item 5): outer page variables
54
+ * stay readable inside widget subtrees, and only a same-named filter shadows
55
+ * the outer variable.
56
+ */
42
57
  export declare const DashboardRenderer: import('react').ForwardRefExoticComponent<Omit<DashboardRendererProps, "ref"> & import('react').RefAttributes<HTMLDivElement>>;
43
58
  //# sourceMappingURL=DashboardRenderer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"DashboardRenderer.d.ts","sourceRoot":"","sources":["../src/DashboardRenderer.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAG/E,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AA+J5F,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,eAAe,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4EAA4E;IAC5E,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,oCAAoC;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iCAAiC;IACjC,WAAW,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IACrE,kEAAkE;IAClE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,gDAAgD;IAChD,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,uDAAuD;IACvD,aAAa,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAClD;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,qBAAqB,EAAE,KAAK,IAAI,CAAC;IAC9D,mGAAmG;IACnG,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,wGAAwG;IACxG,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,aAAa,KAAK,OAAO,CAAC,YAAY,CAAC,GAAG,YAAY,CAAC,CAAC;IACrH;;;;;OAKG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,eAAO,MAAM,iBAAiB,gIAy1B7B,CAAC"}
1
+ {"version":3,"file":"DashboardRenderer.d.ts","sourceRoot":"","sources":["../src/DashboardRenderer.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAG/E,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAmL5F,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,eAAe,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4EAA4E;IAC5E,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,oCAAoC;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iCAAiC;IACjC,WAAW,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IACrE,kEAAkE;IAClE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,gDAAgD;IAChD,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,uDAAuD;IACvD,aAAa,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAClD;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,qBAAqB,EAAE,KAAK,IAAI,CAAC;IAC9D,mGAAmG;IACnG,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,wGAAwG;IACxG,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,aAAa,KAAK,OAAO,CAAC,YAAY,CAAC,GAAG,YAAY,CAAC,CAAC;IACrH;;;;;OAKG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAg7BD;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,iBAAiB,gIAiB7B,CAAC"}