@object-ui/plugin-charts 17.2.0 → 17.5.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 +417 -0
- package/README.md +0 -11
- package/dist/ChartContainerImpl.d.ts +1 -1
- package/dist/ObjectChart.d.ts +13 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +601 -555
- package/dist/index.umd.cjs +2 -2
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +12 -12
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,416 @@
|
|
|
1
1
|
# @object-ui/plugin-charts
|
|
2
2
|
|
|
3
|
+
## 17.5.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 5fac011: Publish `normalizeChartSchema` from the package entry.
|
|
8
|
+
|
|
9
|
+
`normalizeChartSchema` is the single place the author-facing chart schema is translated into the renderer's internal pipeline contract, and `ChartRenderer` calls it on every render. It was not reachable from the package's only entry point, so a consumer that wanted to assert what `AdvancedChartImpl` is actually handed had to restate the translation rather than run it. It is now exported from the entry, along with the `NormalizedChartSchema` type it returns.
|
|
10
|
+
|
|
11
|
+
Additive only: nothing is removed or renamed, and the module was already in the entry's eager import graph via `ChartRenderer`, so this publishes a name rather than shipping new bytes.
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- 5900ac5: Analytics surfaces now run resolved select-option labels through the locale bundle — the chart legend and the related list on one page stop disagreeing
|
|
16
|
+
|
|
17
|
+
A dashboard widget grouped by a `select` field rendered the option's authored English label while the related list beside it rendered the translation. The decisive evidence in objectui#4030 is the stored value `orion`: the chart read `Orion Engineered Carbons`, a string with no resemblance to the value and matching the object's `label` byte for byte. So the analytics path had already RESOLVED the option label — it simply never ran the result through the i18n bundle before display. (`domestic → Domestic` differs from its value by case alone, which is why the first diagnosis, "the report groups by stored value", was wrong.)
|
|
18
|
+
|
|
19
|
+
There is exactly one resolution channel and this change reuses it rather than adding a chart-side dialect: `fieldOptionLabel` from `useObjectLabel`, i.e. `{ns}.fieldOptions.<object>.<field>.<value>` — the convention `@objectstack/spec` names objectui as the reader of, and the one list, form, kanban and record-picker surfaces already translate select options through. The bundle is applied ONCE, at the output of the label net that landed in objectui#4053/#4263, on the shared option list every consumer reads: chart axis and legend, the table/pivot cells of a dotted dimension, that table's CSV export, per-category colours and the declared category order. `@object-ui/core` gains `localizeFieldOptions` (the pure mirror of `translateOptions`), an optional translator on `buildDimensionLabelMap`, and `resolveDimensionFieldMeta` — the same single relationship walk `resolveDimensionFieldOptions` performs, now keeping the object that OWNS the terminal field, because for `crm_account.industry` the bundle key is `crm_account`, not the dataset's base object.
|
|
20
|
+
|
|
21
|
+
Two properties the fix is shaped around. The rows reach this net keyed either way — by stored value when the server did not resolve the dimension, by the English label when it did (ADR-0021) — and the reported screen is the second case, so the map answers to both keys and lands on the same translated display. And identity is untouched: `relabelDimensions` still rewrites display only, so a drilled chart segment clicked as `欧励隆` filters by `orion`, bucket ids and pivot totals keep their raw keys, and an option with no bundle entry (or an `en` console) renders exactly the authored label it renders today.
|
|
22
|
+
|
|
23
|
+
The per-locale work moved from the metadata fetch into the render, so switching language now re-labels in place instead of waiting for a refetch.
|
|
24
|
+
|
|
25
|
+
Not covered, and unchanged here: a LOCAL select dimension on a table/pivot, whose label the server resolves and whose client-side net is deliberately off (objectui#4263), and a dashboard global filter's own field label, which has no object name in its metadata to key a bundle lookup with — tracked on objectui#4030.
|
|
26
|
+
|
|
27
|
+
- 3fc2971: A null-keyed group renders as an explicit bucket instead of silently vanishing from a chart (objectui#4466)
|
|
28
|
+
|
|
29
|
+
`buildChartSeries`' single-dimension branch passed rows through verbatim, so a row whose category VALUE is `null` reached recharts with a null category and drew no mark. The visible outcome was not an empty chart but a quietly wrong one: rows `[{user_id: null, event_count: 51}, {user_id: 'Dev Admin', event_count: 2}]` drew exactly ONE bar — the dominant group, 51 of 53 events, dropped while the y-axis scale still accommodated it, so the chart understated its own data and the axis proved the data had been there. With every group null it drew axes, gridlines and an axis title with zero marks and no empty state, which is the shipped first-boot state of the built-in System Overview board's "Events by User" (every seeded `sys_audit_log` row is written with `user_id = NULL`).
|
|
30
|
+
|
|
31
|
+
The mapping lives in the shared series layer, so dashboard widgets and standalone `ObjectChart` get one answer rather than a per-chart patch in the recharts wrapper. It resolves the two-answers disagreement the card names as well: an empty result set keeps the designed empty state, a non-empty result always draws bars — the null bucket included.
|
|
32
|
+
|
|
33
|
+
`@object-ui/core` gains `NULL_CATEGORY_LABEL` and `ChartSeriesOptions`; `buildChartSeries` and `findChartSeriesRow` each take an optional trailing `options`. Both additive — every existing call site compiles and behaves identically, and a result with no null category is still returned by array identity. The two helpers are a pair on purpose: the caller matches a clicked segment against rows that still carry the raw `null`, so `findChartSeriesRow` reads the bucket label back to that row and the newly-visible bar keeps its drill-through instead of resolving to `-1`.
|
|
34
|
+
|
|
35
|
+
The label goes through the i18n channel (`chart.nullCategory`, en `(None)` / zh `(未指定)`, all ten packs), passed down by the renderer: `@object-ui/core` is React-free and cannot read the locale bundle, so it takes the resolved string the same way `dimensionOptionTranslator` takes a resolver. Its English constant is the floor for a provider-less host, not the mechanism.
|
|
36
|
+
|
|
37
|
+
`hasNoCategoryKey` (framework#4033) is untouched and now documented against this: a row that does not carry the category key AT ALL is a different defect — a dimension grouped by but never projected — and keeps its explanatory placeholder. The bucket deliberately never ADDS the key to such a row, which is what keeps that guard's signal alive. Key absent → the placeholder; key present with a null value → the bucket.
|
|
38
|
+
|
|
39
|
+
- aca27fa: The multi-dimension pivot branch buckets a null first-dimension value instead of dropping its bar (objectui#4497)
|
|
40
|
+
|
|
41
|
+
`buildChartSeries`' pivot branch (2+ dimensions, single measure) bucketed rows by `String(xRaw ?? '')` but wrote the RAW value into the emitted row, so a null first-dimension value produced `{status: null, Low: 3}` and reached recharts with a null category — which draws no mark. Measured at the DOM: a two-group pivot drew ONE bar, and an all-null pivot drew axes and gridlines with zero bar rectangles and no empty state. That is the same mechanism objectui#4466 fixed one branch below, on the branch that card deliberately left pinned as-is until the pivot's own bucketing had been measured.
|
|
42
|
+
|
|
43
|
+
The pivot now maps a null/undefined first-dimension VALUE to the same bucket label the single-dimension branch uses — `ChartSeriesOptions.nullCategoryLabel`, defaulting to `NULL_CATEGORY_LABEL`. One doctrine, one predicate, two call sites; no new export, and every existing call site compiles and behaves identically.
|
|
44
|
+
|
|
45
|
+
The bucket KEY is untouched, which is what keeps this a display fix: `String(xRaw ?? '')` still decides which rows share a bar, so every existing grouping is byte-identical and only the label the bucket carries changes. Rows that lack the category key entirely are still not bucketed — that shape is a dimension grouped by but never projected (framework#4033), a different defect with a different answer.
|
|
46
|
+
|
|
47
|
+
Drill-through needed no change, which was measured rather than assumed: the pivot's emitted rows are AGGREGATED, so they are not index-aligned with `drillRawRows` and the one production caller (`DatasetWidget.handleChartDrill`) already drills by SEARCHING the raw rows through `findChartSeriesRow`. Those raw rows still carry their null, and objectui#4466's label-matching covers the multi-dimension arm as well as the single-dimension one, so the newly-visible bar resolves to the right record. Pinned at both levels so a regression in either half surfaces as the dead click it would be.
|
|
48
|
+
|
|
49
|
+
- 613b167: A dataset dimension on a dotted relationship path now renders its option labels instead of the raw stored enum
|
|
50
|
+
|
|
51
|
+
A `DatasetDimension` whose `field` is a relationship path (`crm_account.industry`) got no select-option resolution at all: the chart plotted `education`, `finance`, `manufacturing` — the database column, unresolved — while the **same underlying field** reached as a **local** dimension rendered `Education`, `Finance`, `Manufacturing` beside it on the same dashboard. Nothing errored, so the widget just quietly showed database enum values to end users; on a non-English deployment those are words that appear nowhere else in the UI, since every form and list shows the translated label.
|
|
52
|
+
|
|
53
|
+
The label lookup read options as `baseObject.fields[<path>]`, which only ever matches the local spelling. For a dotted path the options live on the **related** object, so the lookup missed and the renderer fell through to the stored value.
|
|
54
|
+
|
|
55
|
+
The object-resolution step of that one lookup now walks the path: each segment before the last must be a declared relationship (`lookup` / `master_detail`, target read from `reference` / `reference_to` / `referenceTo` / `reference_to_object`), and the terminal field's options are read off the object that actually owns it. This is the same lookup for both spellings rather than a dotted-path variant beside it — a single-segment path never enters the walk and resolves exactly as before, so the local and joined paths cannot drift apart. Multi-hop paths (`crm_account.owner.department`) resolve too, which is the shape the dataset designer already emits.
|
|
56
|
+
|
|
57
|
+
Hops ride the caller's existing `GET /meta/object/:name` channel — the same authenticated read that fetched the base object — so no new fetch layer is introduced, and objects are fetched once per resolution even when several dimensions share a prefix. Every failure stays best-effort: a segment that is not a relationship, a target that cannot be loaded, or a terminal field with no options yields no mapping and the raw value survives, exactly as it does today.
|
|
58
|
+
|
|
59
|
+
Applies to both surfaces that carried this lookup: dashboard dataset widgets (`DatasetWidget`) and the chart view's dataset path (`ObjectChart`).
|
|
60
|
+
|
|
61
|
+
Scope: this ends at "the label is in hand". Whether that label then passes through the i18n bundle is a separate gap tracked upstream as objectstack#5076.
|
|
62
|
+
|
|
63
|
+
- 0b49d60: Analytics: `ObjectChart` consumes the shared label-net helpers instead of a third copy
|
|
64
|
+
|
|
65
|
+
objectui#4389 (PR #4404) named two copies of the analytics label-net glue — the dashboard's `DatasetWidget` and plugin-report's dataset block — and retired both into `@object-ui/core` + `@object-ui/react`. There was a THIRD, which that card did not name and its PR deliberately left out of scope: `packages/plugin-charts/src/ObjectChart.tsx` carried its own `translatorFor` closure, its own `buildDimensionLabelMap` loop, and its own base-object-read-then-walk composition. The `translatorFor` copy was logically identical to the two that were deleted, down to the comment explaining the binding.
|
|
66
|
+
|
|
67
|
+
`ObjectChart` now calls core's `dimensionOptionTranslator`, `deriveDimensionLabelMaps` and `loadDimensionFieldMeta` directly. Nothing about what a label IS changes — those helpers are the same code the two retired copies were rewritten onto, so the part that was genuinely duplicated three times is now written once.
|
|
68
|
+
|
|
69
|
+
Behaviour is unchanged by construction: same two metadata reads in the same order on the dataset path, same one read on the aggregate path, same best-effort fallback (an unresolvable path yields no entry and the raw value survives), same locale-applying memo boundary. `plugin-charts`' 22 test files / 170 assertions pass unchanged and their files are byte-identical to before, which is the acceptance evidence for a pure swap.
|
|
70
|
+
|
|
71
|
+
The card's second, optional step — moving the DATASET path's metadata read onto `@object-ui/react`'s `useDatasetDimensionMeta` — was attempted and declined on measurement; the shape blocker is recorded on objectui#4405 and in the PR. The two bug-fix properties the family exists to state (the read rides the host's authenticated `apiFetch`, objectui#4121; the fetched metadata stays locale-free, objectui#4030 / PR #4324) therefore remain stated locally in this file, exactly as before, and are undisturbed by this change.
|
|
72
|
+
|
|
73
|
+
- bcd3e02: `ObjectChart`'s category option-color / dimension-label probe now rides the host's
|
|
74
|
+
authenticated fetch (`SchemaRendererContext.apiFetch`) instead of the bare global
|
|
75
|
+
`fetch`.
|
|
76
|
+
|
|
77
|
+
Both metadata reads the effect makes — `GET /api/v1/meta/dataset/{dataset}` and
|
|
78
|
+
`GET /api/v1/meta/object/{object}` — went out on the global `fetch`, so in a hosted
|
|
79
|
+
console they skipped whatever the host supplies on that channel (Authorization /
|
|
80
|
+
tenant headers, base-URL rewrite, draft-preview params). A bearer-token session
|
|
81
|
+
carries its credential in a header rather than a cookie, so `credentials: 'include'`
|
|
82
|
+
alone left these two reads unauthenticated. The effect is best-effort and swallows
|
|
83
|
+
every failure, which made the symptom silent: semantic option colors and dataset
|
|
84
|
+
dimension labels simply never applied, and the chart fell back to the positional
|
|
85
|
+
theme palette and raw stored values.
|
|
86
|
+
|
|
87
|
+
Standalone embeds are unaffected — with no provider (or a provider that supplies no
|
|
88
|
+
`apiFetch`) the probe still uses the global `fetch`, the same documented fallback
|
|
89
|
+
`useRecordEditable` and `provider: 'api'` view sources use.
|
|
90
|
+
|
|
91
|
+
- Updated dependencies [0e67b53]
|
|
92
|
+
- Updated dependencies [ceccdcf]
|
|
93
|
+
- Updated dependencies [d6e5124]
|
|
94
|
+
- Updated dependencies [debad27]
|
|
95
|
+
- Updated dependencies [dc2aa3e]
|
|
96
|
+
- Updated dependencies [ee66e2e]
|
|
97
|
+
- Updated dependencies [ee26e65]
|
|
98
|
+
- Updated dependencies [5900ac5]
|
|
99
|
+
- Updated dependencies [932cbcd]
|
|
100
|
+
- Updated dependencies [734d186]
|
|
101
|
+
- Updated dependencies [f650253]
|
|
102
|
+
- Updated dependencies [3d9769a]
|
|
103
|
+
- Updated dependencies [8f85f8b]
|
|
104
|
+
- Updated dependencies [d0c3b26]
|
|
105
|
+
- Updated dependencies [3fc2971]
|
|
106
|
+
- Updated dependencies [aca27fa]
|
|
107
|
+
- Updated dependencies [dde7283]
|
|
108
|
+
- Updated dependencies [f7c6430]
|
|
109
|
+
- Updated dependencies [4dadf0d]
|
|
110
|
+
- Updated dependencies [ae10a01]
|
|
111
|
+
- Updated dependencies [92876f0]
|
|
112
|
+
- Updated dependencies [f279deb]
|
|
113
|
+
- Updated dependencies [4b70d28]
|
|
114
|
+
- Updated dependencies [eb7f586]
|
|
115
|
+
- Updated dependencies [e901131]
|
|
116
|
+
- Updated dependencies [d9d3463]
|
|
117
|
+
- Updated dependencies [2a40f69]
|
|
118
|
+
- Updated dependencies [bec3e14]
|
|
119
|
+
- Updated dependencies [613b167]
|
|
120
|
+
- Updated dependencies [b4d3c22]
|
|
121
|
+
- Updated dependencies [1f9b905]
|
|
122
|
+
- Updated dependencies [cb13400]
|
|
123
|
+
- Updated dependencies [828549a]
|
|
124
|
+
- Updated dependencies [e1ade8f]
|
|
125
|
+
- Updated dependencies [bc64bfe]
|
|
126
|
+
- Updated dependencies [abb0f81]
|
|
127
|
+
- Updated dependencies [38ab505]
|
|
128
|
+
- Updated dependencies [3e19fe7]
|
|
129
|
+
- Updated dependencies [bb58d1d]
|
|
130
|
+
- Updated dependencies [5cc847c]
|
|
131
|
+
- Updated dependencies [fa21254]
|
|
132
|
+
- Updated dependencies [33c32bf]
|
|
133
|
+
- Updated dependencies [66fb4fa]
|
|
134
|
+
- Updated dependencies [b953a97]
|
|
135
|
+
- Updated dependencies [d7f3e30]
|
|
136
|
+
- Updated dependencies [6d641c9]
|
|
137
|
+
- Updated dependencies [7e4f0e5]
|
|
138
|
+
- Updated dependencies [a84385b]
|
|
139
|
+
- Updated dependencies [45e1949]
|
|
140
|
+
- Updated dependencies [92250d6]
|
|
141
|
+
- Updated dependencies [c1d939f]
|
|
142
|
+
- Updated dependencies [58bebf6]
|
|
143
|
+
- Updated dependencies [405e808]
|
|
144
|
+
- Updated dependencies [49ae9f4]
|
|
145
|
+
- Updated dependencies [a3ae404]
|
|
146
|
+
- Updated dependencies [bfdf3d4]
|
|
147
|
+
- Updated dependencies [bb68488]
|
|
148
|
+
- Updated dependencies [c0f9a4b]
|
|
149
|
+
- Updated dependencies [b1e42d0]
|
|
150
|
+
- Updated dependencies [2459a3e]
|
|
151
|
+
- Updated dependencies [ac853ce]
|
|
152
|
+
- Updated dependencies [fa51109]
|
|
153
|
+
- Updated dependencies [d6aa172]
|
|
154
|
+
- Updated dependencies [fe52a04]
|
|
155
|
+
- Updated dependencies [d46f9b8]
|
|
156
|
+
- Updated dependencies [3f5f87c]
|
|
157
|
+
- Updated dependencies [2fea4d2]
|
|
158
|
+
- Updated dependencies [f5e1143]
|
|
159
|
+
- Updated dependencies [7f1cb33]
|
|
160
|
+
- Updated dependencies [f148a64]
|
|
161
|
+
- Updated dependencies [bb68488]
|
|
162
|
+
- Updated dependencies [2e3b0c0]
|
|
163
|
+
- Updated dependencies [9461dd3]
|
|
164
|
+
- Updated dependencies [78fa331]
|
|
165
|
+
- Updated dependencies [47f551b]
|
|
166
|
+
- Updated dependencies [31ab1ac]
|
|
167
|
+
- Updated dependencies [0082db8]
|
|
168
|
+
- Updated dependencies [ab04728]
|
|
169
|
+
- Updated dependencies [5bf09fd]
|
|
170
|
+
- Updated dependencies [06915b0]
|
|
171
|
+
- Updated dependencies [ff84b05]
|
|
172
|
+
- @object-ui/i18n@17.5.0
|
|
173
|
+
- @object-ui/react@17.5.0
|
|
174
|
+
- @object-ui/components@17.5.0
|
|
175
|
+
- @object-ui/core@17.5.0
|
|
176
|
+
- @object-ui/types@17.5.0
|
|
177
|
+
|
|
178
|
+
## 17.4.0
|
|
179
|
+
|
|
180
|
+
### Patch Changes
|
|
181
|
+
|
|
182
|
+
- a7e39a8: `ChartContainer`'s min-size fallback survives a consumer-supplied `style` (objectstack#7026)
|
|
183
|
+
|
|
184
|
+
The container wrote `style={{ minHeight: 280, minWidth: 0, ...props.style }}` and
|
|
185
|
+
then spread `{...props}` on the line BELOW it. `props` is the rest of
|
|
186
|
+
`ComponentProps< "div" >` — only `id`, `className`, `children`, `config` and
|
|
187
|
+
`disableSettleRemount` are destructured out of it — so it still carried the
|
|
188
|
+
consumer's `style`, and a later JSX attribute of the same name replaces an earlier
|
|
189
|
+
one outright. Any caller that passed a `style` therefore replaced the whole object:
|
|
190
|
+
both `minHeight` and `minWidth` vanished, and the `...props.style` merge written
|
|
191
|
+
inside it never executed even once. It was dead code that read, to anyone auditing
|
|
192
|
+
the file, as if the fallback were guaranteed.
|
|
193
|
+
|
|
194
|
+
That fallback is not decorative. It exists so Recharts' `ResponsiveContainer`
|
|
195
|
+
always has a non-zero box to measure: a dashboard widget that overrides the
|
|
196
|
+
container's `h-[350px]` class and wraps the chart in flex/grid without an explicit
|
|
197
|
+
child height leaves the box at 0, Recharts measures `width/height = -1`, and the
|
|
198
|
+
chart renders invisibly — the exact failure the guard was added for.
|
|
199
|
+
|
|
200
|
+
`style` is now destructured out of the rest props and merged explicitly, so which
|
|
201
|
+
side wins is stated in code instead of being decided by JSX attribute order, and
|
|
202
|
+
`{...props}` can no longer reach `style` at all.
|
|
203
|
+
|
|
204
|
+
Precedence: **an author's explicit size wins.** Simply spreading `{...props}`
|
|
205
|
+
first and merging unconditionally would have traded this bug for its mirror image
|
|
206
|
+
— `minHeight: 280` injected next to an authored `height: 100` floors that 100 to
|
|
207
|
+
280, silently overriding the author. So each half of the fallback applies only
|
|
208
|
+
when the consumer style declares neither of its own keys: `height`/`minHeight`
|
|
209
|
+
gate the height half, `width`/`minWidth` gate the width half, and a key present
|
|
210
|
+
but set to `undefined`/`null` counts as not declared. Every other consumer style
|
|
211
|
+
key passes through untouched.
|
|
212
|
+
|
|
213
|
+
Behaviour change surface, deliberately narrow. A caller that supplies no `style`
|
|
214
|
+
is byte-for-byte unchanged. A caller whose `style` declares a height — which today
|
|
215
|
+
is the only shape in the tree, `AdvancedChartImpl`'s `containerProps` forwarding
|
|
216
|
+
`ChartConfig.height` — keeps exactly the height it authored, also unchanged, and
|
|
217
|
+
additionally regains the `minWidth: 0` half. What changes is the case the issue
|
|
218
|
+
was filed for: a `style` carrying no size key (a margin, a padding, an
|
|
219
|
+
aspect-ratio, any future container-level presentation prop routed through the same
|
|
220
|
+
`containerProps` path) now keeps the min-size fallback instead of silently
|
|
221
|
+
stripping it.
|
|
222
|
+
|
|
223
|
+
Pinned in both directions, since a one-sided pin would have been satisfied by the
|
|
224
|
+
mirror-image fix: a non-size `style` keeps `min-height: 280` / `min-width: 0`
|
|
225
|
+
(red before this change), and an explicit `height: 100` renders as 100 with no
|
|
226
|
+
`min-height` floor (red under the unconditional-merge alternative).
|
|
227
|
+
|
|
228
|
+
- 4bc6c23: Converge dashboard widget `compareTo` on the executor's `{ kind, dimension? }` contract, and make the dataset path actually render a comparison
|
|
229
|
+
|
|
230
|
+
`CompareToConfig` was a three-branch union (`'previousPeriod' | 'previousYear' | { offset }`). `@objectstack/spec` collapsed it to the shape the analytics executor already implements — `DatasetCompareTo`, a plain strict object `{ kind: 'previousPeriod' | 'previousYear'; dimension?: string }` (objectstack#5011) — so this renderer now reads that one shape:
|
|
231
|
+
|
|
232
|
+
- `shiftFilterByCompareTo` / `compareToTrendLabelKey` dispatch on `compareTo.kind`. The `{ offset }` duration shift is gone: `{ offset: '1y' }` is `kind: 'previousYear'`, while `'7d'` / `'1M'` have no faithful target and are restated by the author on the widget's own `filter` plus `kind: 'previousPeriod'`. No trend label key is retired — the offset arm resolved to `vsPreviousPeriod`, which survives as the `previousPeriod` fallback.
|
|
233
|
+
- `DatasetWidget` no longer discards part of `compareTo`. It used to forward only the object form because the two string forms had no meaning downstream; with one shape there is nothing to discard, and a stale string is now invalid metadata rejected where it is authored rather than silently reinterpreted here.
|
|
234
|
+
- **The comparison now actually runs on the dataset path.** A widget states its window in its own `filter` (a date macro, or the dashboard date-range filter merged in), but the executor shifts a `timeDimensions` entry carrying a `dateRange` — so a dataset widget asking for a comparison got "compareTo needs a dated window to shift" and rendered none. When (and only when) a comparison is requested, the resolved filter's bounded date windows are lowered into `selection.timeDimensions[].dateRange` and moved out of `runtimeFilter` (a copy left behind would intersect the shifted window with the current one and empty every comparison column). Which dimension gets shifted stays the executor's decision: every window found is lowered under the name the author wrote, and zero or two candidates surfaces the executor's own error, listing them.
|
|
235
|
+
- The `<measure>__compare` columns that come back are now shown: a delta + window label on KPI widgets, a comparison column on tables, and a `variant: 'comparison'` overlay series on charts — the same treatment and the same `dashboard.trend.*` labels the inline object-provider widgets already use.
|
|
236
|
+
|
|
237
|
+
- 5bfaabd: `PageComponentSchema.dataSource` now reaches every object-bound block, not just
|
|
238
|
+
`list-view` — and `element:record_picker` stops discarding `view`
|
|
239
|
+
(objectstack#6953).
|
|
240
|
+
|
|
241
|
+
objectstack#5576 wired the spec's per-element data binding
|
|
242
|
+
(`dataSource: { object, view?, filter?, sort?, limit? }`) to `list-view` and left
|
|
243
|
+
the same declaration inert on every other page component. Two gaps remained, and
|
|
244
|
+
both were silent:
|
|
245
|
+
|
|
246
|
+
- **`element:record_picker` read four of the five keys and dropped `view`.** So
|
|
247
|
+
`dataSource: { object: 'account', view: 'hot' }` — the spec's own example —
|
|
248
|
+
built a picker over EVERY account instead of the rows the saved view selects.
|
|
249
|
+
Nothing threw and nothing rendered an error; the option list was simply wider
|
|
250
|
+
than what was authored, which also means a user could select a record the page
|
|
251
|
+
said was out of scope.
|
|
252
|
+
- **`object-grid` / `object-form` / `object-kanban` / `object-calendar` /
|
|
253
|
+
`object-chart` / `object-metric` / `record:related_list` read none of it.**
|
|
254
|
+
Each gates its fetch on its own `objectName`, and nothing mapped
|
|
255
|
+
`dataSource.object` onto it, so a page written the way the spec documents
|
|
256
|
+
rendered an empty grid / a field-less form / a board with no cards / an empty
|
|
257
|
+
month / an empty chart / a static metric number — with no request and no
|
|
258
|
+
diagnostic anywhere. Spec-valid metadata rendering nothing is the
|
|
259
|
+
objectstack#4413 shape.
|
|
260
|
+
|
|
261
|
+
Composition follows objectstack#5576's landed semantics unchanged on every block:
|
|
262
|
+
a named saved view supplies the baseline, a key written on the component itself
|
|
263
|
+
overrides it, an explicit binding key overrides both, `filter` AND-combines
|
|
264
|
+
("additional filter criteria" — a binding can narrow a view, never widen it), and
|
|
265
|
+
a `view` name that does not resolve renders a configuration error instead of
|
|
266
|
+
degrading to the object's full scope.
|
|
267
|
+
|
|
268
|
+
- `@object-ui/react` — new `useElementDataSourceSchema(schema, mapping, dataSource?)`
|
|
269
|
+
and `ElementDataSourceGate` apply a resolved binding to the schema keys a given
|
|
270
|
+
block reads, plus `ElementDataSourceErrorPanel` / `ElementDataSourceLoadingPanel`
|
|
271
|
+
for the two non-final states. One precedence table for all blocks rather than
|
|
272
|
+
one copy per block — that copy is how "additional filter criteria" would have
|
|
273
|
+
become two dialects.
|
|
274
|
+
- A mapping names **only** keys its block genuinely reads. A composed value
|
|
275
|
+
written onto a key the block ignores would be accepted and dropped, which is
|
|
276
|
+
the defect being removed, one layer deeper — so a kanban's swimlane `columns`
|
|
277
|
+
never receive a view's field list, and a block with no row cap leaves `limit`
|
|
278
|
+
unmapped. The per-block coverage table, including two residual gaps that are
|
|
279
|
+
named rather than papered over, is in `content/docs/guide/data-source.md`.
|
|
280
|
+
|
|
281
|
+
No behaviour changes for a block that carries no `dataSource`: the binding-free
|
|
282
|
+
path returns the schema by reference, so nothing remounts and nothing refetches.
|
|
283
|
+
|
|
284
|
+
- Updated dependencies [794c497]
|
|
285
|
+
- Updated dependencies [993336f]
|
|
286
|
+
- Updated dependencies [f0a625a]
|
|
287
|
+
- Updated dependencies [b5980f4]
|
|
288
|
+
- Updated dependencies [8aad9fd]
|
|
289
|
+
- Updated dependencies [6719877]
|
|
290
|
+
- Updated dependencies [56ff091]
|
|
291
|
+
- Updated dependencies [7864f03]
|
|
292
|
+
- Updated dependencies [0cbdca8]
|
|
293
|
+
- Updated dependencies [d229dfa]
|
|
294
|
+
- Updated dependencies [ecae400]
|
|
295
|
+
- Updated dependencies [4bc6c23]
|
|
296
|
+
- Updated dependencies [d3e738a]
|
|
297
|
+
- Updated dependencies [c3b01a7]
|
|
298
|
+
- Updated dependencies [f5f8744]
|
|
299
|
+
- Updated dependencies [7ed3360]
|
|
300
|
+
- Updated dependencies [69becd2]
|
|
301
|
+
- Updated dependencies [5e52495]
|
|
302
|
+
- Updated dependencies [0fa5e4d]
|
|
303
|
+
- Updated dependencies [b750823]
|
|
304
|
+
- Updated dependencies [5bfaabd]
|
|
305
|
+
- Updated dependencies [e06810e]
|
|
306
|
+
- Updated dependencies [ab3ad4f]
|
|
307
|
+
- Updated dependencies [c2fd122]
|
|
308
|
+
- Updated dependencies [ac2139c]
|
|
309
|
+
- Updated dependencies [b14ab3a]
|
|
310
|
+
- Updated dependencies [e24d767]
|
|
311
|
+
- Updated dependencies [8c60819]
|
|
312
|
+
- Updated dependencies [aca561a]
|
|
313
|
+
- Updated dependencies [e64a52e]
|
|
314
|
+
- Updated dependencies [844d17f]
|
|
315
|
+
- Updated dependencies [48132f7]
|
|
316
|
+
- Updated dependencies [4dcd52a]
|
|
317
|
+
- Updated dependencies [42ae5c6]
|
|
318
|
+
- Updated dependencies [0ef9dfd]
|
|
319
|
+
- Updated dependencies [1d723e3]
|
|
320
|
+
- Updated dependencies [0109f54]
|
|
321
|
+
- Updated dependencies [7e5bb5d]
|
|
322
|
+
- Updated dependencies [fbc23e0]
|
|
323
|
+
- Updated dependencies [6d762da]
|
|
324
|
+
- Updated dependencies [e6fdbdc]
|
|
325
|
+
- Updated dependencies [54233b1]
|
|
326
|
+
- Updated dependencies [f9faa7d]
|
|
327
|
+
- Updated dependencies [97b63d7]
|
|
328
|
+
- Updated dependencies [6bb454a]
|
|
329
|
+
- Updated dependencies [523be48]
|
|
330
|
+
- Updated dependencies [7e2b7e9]
|
|
331
|
+
- Updated dependencies [33526fd]
|
|
332
|
+
- Updated dependencies [32413ec]
|
|
333
|
+
- Updated dependencies [c1e1e6b]
|
|
334
|
+
- @object-ui/components@17.4.0
|
|
335
|
+
- @object-ui/react@17.4.0
|
|
336
|
+
- @object-ui/core@17.4.0
|
|
337
|
+
- @object-ui/i18n@17.4.0
|
|
338
|
+
- @object-ui/types@17.4.0
|
|
339
|
+
|
|
340
|
+
## 17.3.0
|
|
341
|
+
|
|
342
|
+
### Minor Changes
|
|
343
|
+
|
|
344
|
+
- 9e9e9a9: `DrillDownConfig` now declares only keys a renderer reads, and `target: 'navigate'` is honoured on charts too (#3354).
|
|
345
|
+
|
|
346
|
+
**Removed — two keys no renderer has ever read.** `DrillDownConfig.view` (self-described as "reserved") and `DrillDownConfig.sort` ("default sort applied to the drill list") had zero read sites repo-wide: the drill drawer rendered its inline `object-data-table` regardless of `view`, and no widget put `sort` into the drilled table schema. Authoring either did nothing, silently. They are removed rather than implemented because nothing asked for them, and this interface is the shape the protocol's own `drillDown` declaration is being derived from (objectstack#5022) — left in place, they were about to become dead keys carrying protocol authority. Removing a declared key from a published interface is technically breaking for anyone who wrote one, but only in the sense that TypeScript now reports what was already true at runtime: the key did nothing. Per this repo's version policy the bump stays `minor` (the fixed release group tracks `@objectstack`'s major). A compile-time pin in `@object-ui/types` keeps both keys from drifting back without a reader.
|
|
347
|
+
|
|
348
|
+
**Fixed — `ObjectChart` no longer degrades `target: 'navigate'` to a drawer.** All five widgets share `DrillDownConfig`, whose `target` JSDoc promises `'navigate'` skips the in-place view and opens the object's full list page when the host provides drill navigation. `DrillDownDrawer` delivered that for the table / pivot / metric widgets, but `ObjectChart` draws its own drawer and branched on `'dialog'` only — so `'navigate'` fell through to the default side sheet, indistinguishable from `'drawer'` even with a host handler wired. The chart now routes `'navigate'` through `DrillNavigationContext.openRecordList` with the same merged filter the drawer would have used, and keeps the documented fallback: with no host navigation handler it degrades to the drawer. `'drawer'` / `'dialog'` behaviour is unchanged, and the header's "Open in list" escape hatch stays independent of `target`.
|
|
349
|
+
|
|
350
|
+
The `object-chart` registry input deliberately keeps advertising `target: 'drawer' | 'dialog'` only. `ChartDrillDownSchema` in `@objectstack/spec` declares the chart drill target as those two, strictly, and the publish-time react-page lint parses that schema against the authored literal — so listing `'navigate'` in the designer palette would offer authors a value the publish gate rejects. Widening the protocol union is a spec-side follow-up (objectstack#5435); `'navigate'` works today for any host that composes an `object-chart` schema directly.
|
|
351
|
+
|
|
352
|
+
- 524a635: `<ObjectChart>` declares `drillDown` as a registry input, so the SDUI save gate treats the segment drill as a contract prop instead of an unknown one (framework#5022).
|
|
353
|
+
|
|
354
|
+
The component has read `schema.drillDown` all along — it is what opens the drawer of underlying records when you click a bar or a slice — but the prop was declared in neither the protocol nor this registry entry. The manifest the save gate validates page JSX against is built verbatim from these `inputs`, so an author who wrote the drill got an `unknown-prop` diagnostic for a prop that works. `@objectstack/spec` now declares the shape (`ChartDrillDownSchema`, published on the react-tier `<ObjectChart>` contract); this is the renderer half.
|
|
355
|
+
|
|
356
|
+
The published input describes the six keys the spec declares — `enabled`, `filter`, `title`, `target` (`'drawer' | 'dialog'`), `columns`, `maxRows` — and deliberately not the wider `DrillDownConfig` this repo shares with the table / pivot / metric widgets: `ObjectChart` reads none of `mode` / `report` / `view` / `sort`, and does not implement `target: 'navigate'` (it renders the drawer instead — objectui#3354).
|
|
357
|
+
|
|
358
|
+
The untyped `(schema as any).drillDown` read is now typed as `DrillDownConfig`. Narrowing it to the spec's `ChartDrillDown` is left as a TODO on the version pin: `@objectstack/spec` is pinned at `^17.0.0-rc.2` here and the declaration lands in the next rc, and re-declaring the shape locally would be the fork that lets the two drift.
|
|
359
|
+
|
|
360
|
+
### Patch Changes
|
|
361
|
+
|
|
362
|
+
- Updated dependencies [18cd432]
|
|
363
|
+
- Updated dependencies [532cf8b]
|
|
364
|
+
- Updated dependencies [680080a]
|
|
365
|
+
- Updated dependencies [a7651e6]
|
|
366
|
+
- Updated dependencies [d915c47]
|
|
367
|
+
- Updated dependencies [b71fc92]
|
|
368
|
+
- Updated dependencies [65516ba]
|
|
369
|
+
- Updated dependencies [94c5b7c]
|
|
370
|
+
- Updated dependencies [ca0fa8f]
|
|
371
|
+
- Updated dependencies [34595eb]
|
|
372
|
+
- Updated dependencies [3889ffb]
|
|
373
|
+
- Updated dependencies [5781fb1]
|
|
374
|
+
- Updated dependencies [7e2406a]
|
|
375
|
+
- Updated dependencies [9e9e9a9]
|
|
376
|
+
- Updated dependencies [56409c2]
|
|
377
|
+
- Updated dependencies [042e09d]
|
|
378
|
+
- Updated dependencies [9cbcbf4]
|
|
379
|
+
- Updated dependencies [85c4c9c]
|
|
380
|
+
- Updated dependencies [fd54c3e]
|
|
381
|
+
- Updated dependencies [4eeb932]
|
|
382
|
+
- Updated dependencies [5c856ec]
|
|
383
|
+
- Updated dependencies [23018cc]
|
|
384
|
+
- Updated dependencies [53811d1]
|
|
385
|
+
- Updated dependencies [68b6a28]
|
|
386
|
+
- Updated dependencies [0554e88]
|
|
387
|
+
- Updated dependencies [d915c47]
|
|
388
|
+
- Updated dependencies [f44d872]
|
|
389
|
+
- Updated dependencies [28b2e65]
|
|
390
|
+
- Updated dependencies [509104a]
|
|
391
|
+
- Updated dependencies [825bbe3]
|
|
392
|
+
- Updated dependencies [6195841]
|
|
393
|
+
- Updated dependencies [5dd0127]
|
|
394
|
+
- Updated dependencies [06632e9]
|
|
395
|
+
- Updated dependencies [a415684]
|
|
396
|
+
- Updated dependencies [a4cff5b]
|
|
397
|
+
- Updated dependencies [175bd79]
|
|
398
|
+
- Updated dependencies [5af2852]
|
|
399
|
+
- Updated dependencies [f833d3a]
|
|
400
|
+
- Updated dependencies [a6ec93d]
|
|
401
|
+
- Updated dependencies [2a9513d]
|
|
402
|
+
- Updated dependencies [71be406]
|
|
403
|
+
- Updated dependencies [d22ae31]
|
|
404
|
+
- Updated dependencies [c7ed4c3]
|
|
405
|
+
- Updated dependencies [2409e1d]
|
|
406
|
+
- Updated dependencies [789fe3e]
|
|
407
|
+
- Updated dependencies [8d8094a]
|
|
408
|
+
- @object-ui/core@17.3.0
|
|
409
|
+
- @object-ui/components@17.3.0
|
|
410
|
+
- @object-ui/types@17.3.0
|
|
411
|
+
- @object-ui/i18n@17.3.0
|
|
412
|
+
- @object-ui/react@17.3.0
|
|
413
|
+
|
|
3
414
|
## 17.2.0
|
|
4
415
|
|
|
5
416
|
### Minor Changes
|
|
@@ -798,6 +1209,7 @@
|
|
|
798
1209
|
project `health`) painted its categories from the generic `--chart-1..5`
|
|
799
1210
|
palette — the same gap the chart view (`object-chart`) had before #1932. It now
|
|
800
1211
|
resolves the dimension field's option colors (using the dataset's base `object`
|
|
1212
|
+
|
|
801
1213
|
- dimension→field map the query already returns) and threads them to the
|
|
802
1214
|
renderer as a per-category `categoryColors` map, so health green/red/yellow
|
|
803
1215
|
paints semantically.
|
|
@@ -1004,6 +1416,7 @@
|
|
|
1004
1416
|
- 991b62d: Add `compareTo` field to dashboard widgets for period-over-period
|
|
1005
1417
|
comparison. Supports `'previousPeriod'`, `'previousYear'`, and
|
|
1006
1418
|
`{ offset: '7d' | '4w' | '1M' | '1y' }`.
|
|
1419
|
+
|
|
1007
1420
|
- **Metric / gauge widgets** now compute a delta percentage when `compareTo`
|
|
1008
1421
|
is set and surface it as a derived `trend` (auto-labelled via
|
|
1009
1422
|
`dashboard.trend.vsLast*` i18n keys sniffed from the filter macros).
|
|
@@ -1488,6 +1901,7 @@
|
|
|
1488
1901
|
Library builds (vite lib mode) now externalize every non-relative import instead of bundling third-party CJS dependencies into the published dist. This avoids inlined `require("react")` / `require("react-dom")` calls that cause `Calling \`require\` for "react" in an environment that doesn't expose the \`require\` function` runtime errors when consumer apps re-bundle the published dist.
|
|
1489
1902
|
|
|
1490
1903
|
Specifically fixes:
|
|
1904
|
+
|
|
1491
1905
|
- `@object-ui/plugin-dashboard` no longer inlines `react-grid-layout` (and its transitive `react-draggable` / `react-resizable` CJS bundles). `react-grid-layout` is now declared as a peer dependency so consumers install a single ESM-friendly copy.
|
|
1492
1906
|
- `@object-ui/components`, `@object-ui/plugin-calendar`, `@object-ui/plugin-charts`, `@object-ui/plugin-designer` no longer inline `react-i18next` / `i18next` / `use-sync-external-store` CJS shims.
|
|
1493
1907
|
- All plugin packages now use a unified `external: (id) => !/^[./]/.test(id) && !id.startsWith(__dirname)` rule, ensuring future additions of CJS deps are automatically externalized.
|
|
@@ -1721,6 +2135,7 @@
|
|
|
1721
2135
|
- New plugin-object and ObjectQL SDK updates
|
|
1722
2136
|
|
|
1723
2137
|
**Added:**
|
|
2138
|
+
|
|
1724
2139
|
- New Plugin: @object-ui/plugin-object - ObjectQL plugin for automatic table and form generation
|
|
1725
2140
|
- ObjectTable: Auto-generates tables from ObjectQL object schemas
|
|
1726
2141
|
- ObjectForm: Auto-generates forms from ObjectQL object schemas with create/edit/view modes
|
|
@@ -1729,6 +2144,7 @@
|
|
|
1729
2144
|
- ObjectQL Integration: Enhanced ObjectQLDataSource with getObjectSchema() method using MetadataApiClient
|
|
1730
2145
|
|
|
1731
2146
|
**Changed:**
|
|
2147
|
+
|
|
1732
2148
|
- Updated @objectql/sdk from ^1.8.3 to ^1.9.1
|
|
1733
2149
|
- Updated @objectql/types from ^1.8.3 to ^1.9.1
|
|
1734
2150
|
|
|
@@ -1745,6 +2161,7 @@
|
|
|
1745
2161
|
- Patch release: Add automated changeset workflow and CI/CD improvements
|
|
1746
2162
|
|
|
1747
2163
|
This release includes infrastructure improvements:
|
|
2164
|
+
|
|
1748
2165
|
- Added changeset-based version management
|
|
1749
2166
|
- Enhanced CI/CD workflows with GitHub Actions
|
|
1750
2167
|
- Improved documentation for contributing and releasing
|
package/README.md
CHANGED
|
@@ -120,17 +120,6 @@ By using lazy loading, the main application bundle stays lean:
|
|
|
120
120
|
|
|
121
121
|
This results in significantly faster initial page loads for applications that don't use charts on every page.
|
|
122
122
|
|
|
123
|
-
<!-- release-metadata:v3.3.0 -->
|
|
124
|
-
|
|
125
|
-
## Compatibility
|
|
126
|
-
|
|
127
|
-
- **React:** 18.x or 19.x
|
|
128
|
-
- **Node.js:** ≥ 18
|
|
129
|
-
- **TypeScript:** ≥ 5.0 (strict mode)
|
|
130
|
-
- **`@objectstack/spec`:** ^3.3.0
|
|
131
|
-
- **`@objectstack/client`:** ^3.3.0
|
|
132
|
-
- **Tailwind CSS:** ≥ 3.4 (for packages with UI)
|
|
133
|
-
|
|
134
123
|
## Links
|
|
135
124
|
|
|
136
125
|
- 📚 [Documentation](https://www.objectui.org/docs/plugins/plugin-charts)
|
|
@@ -39,7 +39,7 @@ export type ChartContainerConfig = {
|
|
|
39
39
|
theme: Record<keyof typeof THEMES, string>;
|
|
40
40
|
});
|
|
41
41
|
};
|
|
42
|
-
declare function ChartContainer({ id, className, children, config, disableSettleRemount, ...props }: React.ComponentProps<"div"> & {
|
|
42
|
+
declare function ChartContainer({ id, className, children, config, disableSettleRemount, style, ...props }: React.ComponentProps<"div"> & {
|
|
43
43
|
config: ChartContainerConfig;
|
|
44
44
|
children: React.ComponentProps<typeof ResponsiveContainer>["children"];
|
|
45
45
|
/**
|
package/dist/ObjectChart.d.ts
CHANGED
|
@@ -46,3 +46,16 @@ export declare function aggregateRecords(records: any[], aggregate: {
|
|
|
46
46
|
export declare function resolveGroupByLabels(data: any[], groupByField: string, objectSchema: any, dataSource?: any, translateOption?: (value: string, fallbackLabel: string) => string): Promise<any[]>;
|
|
47
47
|
export { extractRecords } from '@object-ui/core';
|
|
48
48
|
export declare const ObjectChart: (props: any) => React.JSX.Element;
|
|
49
|
+
/**
|
|
50
|
+
* Registry shell for `object-chart` — maps the spec's
|
|
51
|
+
* `PageComponentSchema.dataSource` binding onto the keys {@link ObjectChart}
|
|
52
|
+
* reads (objectstack#6953).
|
|
53
|
+
*
|
|
54
|
+
* Nothing used to map `dataSource.object` onto `objectName`, and this block gates
|
|
55
|
+
* BOTH its fetch and its loading state on that key (`!schema.objectName &&
|
|
56
|
+
* !schema.dataset` returns early) — so a chart authored with the binding the
|
|
57
|
+
* spec documents rendered an empty frame with no error and no request. Lives
|
|
58
|
+
* here, beside the registration, rather than in `ChartContainerImpl` — the
|
|
59
|
+
* binding is a registry-boundary concern, not a rendering one.
|
|
60
|
+
*/
|
|
61
|
+
export declare const ObjectChartBlock: (props: any) => React.JSX.Element;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { ChartBarRenderer, ChartRenderer } from './ChartRenderer';
|
|
2
2
|
export type { BarChartSchema } from './types';
|
|
3
3
|
export { ChartBarRenderer, ChartRenderer };
|
|
4
|
-
export { ObjectChart } from './ObjectChart';
|
|
4
|
+
export { ObjectChart, ObjectChartBlock } from './ObjectChart';
|
|
5
|
+
export { normalizeChartSchema } from './normalizeChartSchema';
|
|
6
|
+
export type { NormalizedChartSchema } from './normalizeChartSchema';
|
|
5
7
|
export declare const chartComponents: {
|
|
6
8
|
'bar-chart': import('react').FC<import('./ChartRenderer').ChartBarRendererProps>;
|
|
7
9
|
chart: import('react').FC<import('./ChartRenderer').ChartRendererProps>;
|