@object-ui/plugin-dashboard 13.2.0 → 14.1.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 +123 -0
- package/README.md +72 -0
- package/dist/DashboardFilterBar.d.ts +12 -0
- package/dist/DashboardFilterBar.d.ts.map +1 -0
- package/dist/DashboardRenderer.d.ts +15 -0
- package/dist/DashboardRenderer.d.ts.map +1 -1
- package/dist/index.js +1086 -790
- package/dist/index.umd.cjs +2 -2
- package/package.json +9 -9
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,128 @@
|
|
|
1
1
|
# @object-ui/plugin-dashboard
|
|
2
2
|
|
|
3
|
+
## 14.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 5523fc4: Dashboard-level filters — the three #2578 item-5 enhancements (framework#2501):
|
|
8
|
+
|
|
9
|
+
- **react**: nested `PageVariablesProvider`s now MERGE instead of shadowing
|
|
10
|
+
wholesale. A filtered dashboard embedded in a Page with its own `variables`
|
|
11
|
+
keeps the outer page variables readable inside widget subtrees (`page.*`);
|
|
12
|
+
an inner definition shadows only the SAME name; writes route to the scope
|
|
13
|
+
that defines the variable (writing an outer-defined name from inside the
|
|
14
|
+
nested subtree updates the outer provider); `resetVariables` stays local.
|
|
15
|
+
Names defined nowhere still write locally, exactly as before.
|
|
16
|
+
- **core**: `buildWidgetScopedFilter` accepts an optional `knownFields` set —
|
|
17
|
+
a DEFAULT binding whose target field is not on the widget's object is
|
|
18
|
+
skipped with a console warning instead of emitting a query the backend
|
|
19
|
+
empty-matches. Explicit `filterBindings` strings are always honoured (a
|
|
20
|
+
typo surfaces as a visibly empty widget, never a silently dropped filter).
|
|
21
|
+
Omitting `knownFields` preserves the previous unchecked behaviour.
|
|
22
|
+
- **plugin-dashboard**: `DashboardRenderer` feeds `knownFields` from
|
|
23
|
+
`dataSource.getObjectSchema` for inline `object` widgets (best-effort —
|
|
24
|
+
unchecked while metadata loads or when the source can't describe objects).
|
|
25
|
+
`optionsFrom` dynamic filter options now resolve DISTINCT values
|
|
26
|
+
server-side via a dataset GROUP BY (`queryDataset` with an inline draft)
|
|
27
|
+
when the data source supports it, falling back to the previous client-side
|
|
28
|
+
top-200 dedupe otherwise.
|
|
29
|
+
|
|
30
|
+
- 887062c: feat(dashboard): dashboard-level filters (date / region) driving multiple charts (framework#2501)
|
|
31
|
+
|
|
32
|
+
A dashboard's `dateRange` + `globalFilters` declarations are now wired end to
|
|
33
|
+
end: the filter values live as dashboard-level variables (the page variables
|
|
34
|
+
primitive, so they're also readable as `page.<name>` in widget expressions),
|
|
35
|
+
a filter bar renders above the widgets, and at render time the dashboard
|
|
36
|
+
broadcasts the active values into every bound widget's inline query —
|
|
37
|
+
`AND`-merged with the widget's own `filter`. Charts stay inline and
|
|
38
|
+
self-contained; each widget maps a filter to **its own** field.
|
|
39
|
+
|
|
40
|
+
- **`@object-ui/types`** — `globalFilters[].name` (stable filter/variable key,
|
|
41
|
+
defaults to `field`) and `DashboardWidgetSchema.filterBindings`
|
|
42
|
+
(`Record<string, string | false>`: per-widget field override / `false`
|
|
43
|
+
opt-out). Zod mirrors included. **Pending paired `@objectstack/spec`
|
|
44
|
+
alignment (framework#2501)** — same precedent as `dataset` /
|
|
45
|
+
`categoryGranularity`.
|
|
46
|
+
- **`@object-ui/core`** — new pure `dashboard-filters` module
|
|
47
|
+
(`resolveDashboardFilterDefs`, `dashboardFilterVariableDefs`,
|
|
48
|
+
`buildFilterCondition`, `buildWidgetScopedFilter`); `mergeFilters` lifted
|
|
49
|
+
from plugin-report (re-exported there unchanged). Date presets emit
|
|
50
|
+
date-macro tokens (`{30_days_ago}` …) so widgets resolve them at query time
|
|
51
|
+
like hand-authored filters.
|
|
52
|
+
- **`@object-ui/plugin-dashboard`** — `DashboardFilterBar` (date presets +
|
|
53
|
+
custom range calendar, select with static `options` or `optionsFrom`,
|
|
54
|
+
text/number inputs, reset); `DashboardRenderer` mounts a
|
|
55
|
+
`PageVariablesProvider` when filters are declared and merges the
|
|
56
|
+
widget-scoped condition into inline widgets' `filter` and dataset widgets'
|
|
57
|
+
`runtimeFilter`. Dashboards without filters render exactly as before.
|
|
58
|
+
|
|
59
|
+
Binding precedence: explicit `filterBindings` string/`false` → legacy
|
|
60
|
+
`targetWidgets` allow-list → the filter's own `field` (dateRange defaults to
|
|
61
|
+
`created_at`). Static-data widgets are not filtered.
|
|
62
|
+
|
|
63
|
+
### Patch Changes
|
|
64
|
+
|
|
65
|
+
- 2ded18c: Fix: a dashboard filter declaring its static `options` in the
|
|
66
|
+
`@objectstack/spec` object form (`options: [{ value, label }]` — the shape
|
|
67
|
+
the spec validates and what framework-authored dashboards ship) crashed the
|
|
68
|
+
whole dashboard with "Objects are not valid as a React child". Caught driving
|
|
69
|
+
the showcase Revenue Pulse dashboard in a real browser.
|
|
70
|
+
|
|
71
|
+
`resolveDashboardFilterDefs` now normalizes both the spec object form and the
|
|
72
|
+
bare-string shorthand (`options: ['EMEA']`) to `{ value, label }` pairs —
|
|
73
|
+
`DashboardFilterDef.options` is typed accordingly — and the filter bar's
|
|
74
|
+
select renders labels (the trigger now shows the selected option's label, not
|
|
75
|
+
its raw value). `@object-ui/types` aligns the `GlobalFilterSchema.options`
|
|
76
|
+
shape with the spec union.
|
|
77
|
+
|
|
78
|
+
- Updated dependencies [82441e4]
|
|
79
|
+
- Updated dependencies [2efa9fd]
|
|
80
|
+
- Updated dependencies [0890fa7]
|
|
81
|
+
- Updated dependencies [2ded18c]
|
|
82
|
+
- Updated dependencies [e628d1f]
|
|
83
|
+
- Updated dependencies [5523fc4]
|
|
84
|
+
- Updated dependencies [887062c]
|
|
85
|
+
- Updated dependencies [579b24d]
|
|
86
|
+
- Updated dependencies [2b30583]
|
|
87
|
+
- Updated dependencies [23d65c3]
|
|
88
|
+
- Updated dependencies [055e1d2]
|
|
89
|
+
- Updated dependencies [9e2d58f]
|
|
90
|
+
- Updated dependencies [dea65f7]
|
|
91
|
+
- Updated dependencies [f30ff68]
|
|
92
|
+
- Updated dependencies [073e7aa]
|
|
93
|
+
- Updated dependencies [3e8bf07]
|
|
94
|
+
- Updated dependencies [6c0135c]
|
|
95
|
+
- Updated dependencies [5b52624]
|
|
96
|
+
- Updated dependencies [4afb251]
|
|
97
|
+
- Updated dependencies [d5b1bc0]
|
|
98
|
+
- Updated dependencies [f94905d]
|
|
99
|
+
- Updated dependencies [2712fc1]
|
|
100
|
+
- Updated dependencies [f0f10f5]
|
|
101
|
+
- @object-ui/i18n@14.1.0
|
|
102
|
+
- @object-ui/fields@14.1.0
|
|
103
|
+
- @object-ui/core@14.1.0
|
|
104
|
+
- @object-ui/types@14.1.0
|
|
105
|
+
- @object-ui/react@14.1.0
|
|
106
|
+
- @object-ui/components@14.1.0
|
|
107
|
+
|
|
108
|
+
## 14.0.0
|
|
109
|
+
|
|
110
|
+
### Patch Changes
|
|
111
|
+
|
|
112
|
+
- Updated dependencies [443360a]
|
|
113
|
+
- Updated dependencies [c70bca7]
|
|
114
|
+
- Updated dependencies [86c69c3]
|
|
115
|
+
- Updated dependencies [05e56ca]
|
|
116
|
+
- Updated dependencies [a44e7b6]
|
|
117
|
+
- Updated dependencies [5971cc4]
|
|
118
|
+
- Updated dependencies [6a74160]
|
|
119
|
+
- @object-ui/core@14.0.0
|
|
120
|
+
- @object-ui/i18n@14.0.0
|
|
121
|
+
- @object-ui/react@14.0.0
|
|
122
|
+
- @object-ui/types@14.0.0
|
|
123
|
+
- @object-ui/components@14.0.0
|
|
124
|
+
- @object-ui/fields@14.0.0
|
|
125
|
+
|
|
3
126
|
## 13.2.0
|
|
4
127
|
|
|
5
128
|
### 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;
|
|
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"}
|