@object-ui/react 16.1.0 → 17.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 +639 -1
- package/README.md +41 -0
- package/dist/SchemaRenderer.js +12 -2
- package/dist/context/InlineEditContext.d.ts +21 -0
- package/dist/context/InlineEditContext.js +7 -2
- package/dist/context/NotificationContext.d.ts +245 -17
- package/dist/context/NotificationContext.js +222 -20
- package/dist/context/ThemeContext.js +4 -8
- package/dist/hooks/index.d.ts +2 -1
- package/dist/hooks/index.js +3 -1
- package/dist/hooks/useAnimation.d.ts +40 -4
- package/dist/hooks/useAnimation.js +41 -10
- package/dist/hooks/useCapabilityGate.d.ts +16 -0
- package/dist/hooks/useCapabilityGate.js +60 -0
- package/dist/hooks/useClientNotifications.d.ts +0 -6
- package/dist/hooks/useClientNotifications.js +7 -53
- package/dist/hooks/useFilterScope.d.ts +30 -0
- package/dist/hooks/useFilterScope.js +55 -0
- package/dist/hooks/useNavigationOverlay.d.ts +11 -0
- package/dist/hooks/useNavigationOverlay.js +35 -1
- package/dist/hooks/usePageVariables.js +23 -11
- package/dist/hooks/useRecordSearch.js +98 -4
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -1
- package/dist/spec-bridge/SpecBridge.d.ts +0 -4
- package/dist/spec-bridge/SpecBridge.js +0 -12
- package/dist/spec-bridge/bridges/list-view.js +5 -11
- package/dist/spec-bridge/index.d.ts +0 -2
- package/dist/spec-bridge/index.js +0 -2
- package/dist/utils/error-message.d.ts +31 -0
- package/dist/utils/error-message.js +49 -0
- package/package.json +7 -7
- package/dist/hooks/useColumnSummary.d.ts +0 -38
- package/dist/hooks/useColumnSummary.js +0 -54
- package/dist/spec-bridge/bridges/dashboard.d.ts +0 -81
- package/dist/spec-bridge/bridges/dashboard.js +0 -121
- package/dist/spec-bridge/bridges/page.d.ts +0 -58
- package/dist/spec-bridge/bridges/page.js +0 -101
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,643 @@
|
|
|
1
1
|
# @object-ui/react
|
|
2
2
|
|
|
3
|
+
## 17.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- c4db402: refactor(views): ListView's `aria` and `sharing` are the spec sub-shapes (#2890 scope A step 5)
|
|
8
|
+
|
|
9
|
+
Last rename batch in the ListView vocabulary migration.
|
|
10
|
+
|
|
11
|
+
**`aria`** is now the spec's `AriaPropsSchema`: `label` → `ariaLabel`,
|
|
12
|
+
`describedBy` → `ariaDescribedBy`, folded at the ListView boundary like every
|
|
13
|
+
other legacy key. Two things fall out of adopting the spec shape:
|
|
14
|
+
|
|
15
|
+
- `role` becomes authorable. The list region hardcoded `role="region"`; it now
|
|
16
|
+
reads `aria.role` and falls back to `region`.
|
|
17
|
+
- `aria.live` stays as a documented local extension — it has no spec
|
|
18
|
+
counterpart, and dropping it would silently disable a shipped capability.
|
|
19
|
+
Promote it rather than growing that extension.
|
|
20
|
+
|
|
21
|
+
**`sharing`** is now the spec's `ViewSharingSchema` (`{ type, lockedBy }`),
|
|
22
|
+
imported by reference — the local four-key object is gone. The legacy pair folds
|
|
23
|
+
in: `visibility` collapses onto the two ownership kinds the spec models (only
|
|
24
|
+
`private` is `personal`; `team` / `organization` / `public` are all
|
|
25
|
+
`collaborative`), and a bare `enabled: true` maps to `personal`, which is the
|
|
26
|
+
badge the user already saw (the old title fell back to `'private'`).
|
|
27
|
+
|
|
28
|
+
_Visible change_: the share badge's tooltip shows the spec ownership type, so a
|
|
29
|
+
view authored with `visibility: 'team'` reads "Sharing: collaborative" instead
|
|
30
|
+
of "Sharing: team". The four-value audience has no spec home and nothing but
|
|
31
|
+
that tooltip consumed it; keeping a second audience enum alive would re-open the
|
|
32
|
+
fork this issue closes.
|
|
33
|
+
|
|
34
|
+
Also fixes the **spec bridge**, which was doing the opposite of its job: given a
|
|
35
|
+
spec-shaped `sharing`, `transformListView` _downgraded_ it — inventing a legacy
|
|
36
|
+
`visibility` audience and an `enabled` flag that the renderer then had to fold
|
|
37
|
+
back. Both sides speak `ViewSharing` now, so it passes through.
|
|
38
|
+
|
|
39
|
+
`conditionalFormatting` and `exportOptions` are deliberately **not** folded.
|
|
40
|
+
Both objectui shapes are supersets carrying capability the spec cannot express —
|
|
41
|
+
the `{ field, operator, value }` rule form, and `maxRecords` / `includeHeaders`
|
|
42
|
+
/ `fileNamePrefix`. Folding them onto the narrower spec shapes would delete
|
|
43
|
+
working features; they want promotion upstream, not a rename.
|
|
44
|
+
|
|
45
|
+
- 07de839: fix(notifications): the config, `position` and action `variant` are read instead of forked or ignored (#3014 follow-up)
|
|
46
|
+
|
|
47
|
+
The last of the notification contract. After `displayType` (#3071) and `icon`
|
|
48
|
+
(#3076), four gaps of the same family were left:
|
|
49
|
+
|
|
50
|
+
- **the config was 3/4 inert** — only `defaultDuration` was ever read.
|
|
51
|
+
`maxVisible` and `stacking` were carried and ignored, while
|
|
52
|
+
`NotificationBanners` capped at a hard-coded `3` of its own;
|
|
53
|
+
- **its field names forked from `NotificationConfigSchema`** — `position` vs
|
|
54
|
+
`defaultPosition`, a renderer-local `stacking` boolean with no spec
|
|
55
|
+
counterpart, and no `pauseOnHover` at all;
|
|
56
|
+
- **a notification could not declare a `position`.** The #3008 parity guard
|
|
57
|
+
asserted the position _vocabulary_ matched the spec while nothing positioned
|
|
58
|
+
anything by it — a guard passing over an unused value;
|
|
59
|
+
- **`NotificationActionButton.variant` was the shadcn Button vocabulary**
|
|
60
|
+
(`default | destructive | outline`) under a spec-shaped name, forking
|
|
61
|
+
`NotificationActionSchema.variant` (`primary | secondary | link`).
|
|
62
|
+
|
|
63
|
+
**How positioning resolves now** — `notification.position ?? config.defaultPosition
|
|
64
|
+
?? nothing`, and "nothing" is a real answer:
|
|
65
|
+
|
|
66
|
+
- **declared** → the surface pins itself there, always. `presentNotificationToast`
|
|
67
|
+
passes it per-toast so the contract wins over the container;
|
|
68
|
+
- **undeclared** → the surface keeps its own anchor (a snackbar's bottom edge) or
|
|
69
|
+
defers to the host's toast chrome.
|
|
70
|
+
|
|
71
|
+
That asymmetry is the design decision. The host's sonner container also serves
|
|
72
|
+
toasts that are _not_ spec notifications (the console action runtime's own
|
|
73
|
+
`toast.*` calls), so it stays the fallback authority for placement — never a
|
|
74
|
+
competing one. A declared position a component prop could silently override
|
|
75
|
+
would be the same "validates, then does nothing" shape this whole area is about.
|
|
76
|
+
Hence `defaultPosition` has no fabricated default: "the host didn't say" has to
|
|
77
|
+
be representable.
|
|
78
|
+
|
|
79
|
+
Also: `maxVisible` / `stackDirection` now drive every stacking surface through
|
|
80
|
+
one shared `visibleNotificationStack` (cap keeps the NEWEST, stack grows in the
|
|
81
|
+
declared direction); `pauseOnHover` holds a transient notification's timer and
|
|
82
|
+
resumes it with the time it had left, which needed the provider to track live
|
|
83
|
+
timers rather than fire-and-forget `setTimeout`s. Legacy spellings still resolve:
|
|
84
|
+
`position` folds into `defaultPosition`, and `stacking: false` reads as
|
|
85
|
+
`maxVisible: 1` rather than being ignored.
|
|
86
|
+
|
|
87
|
+
`onToast` now receives the resolved config as a second argument, so the delegate
|
|
88
|
+
can apply the parts of the contract only it can. Existing one-argument handlers
|
|
89
|
+
are unaffected. The spec-parity guard gained the action-variant vocabulary, the
|
|
90
|
+
one notification enum it did not cover.
|
|
91
|
+
|
|
92
|
+
- 2a40b5e: feat(notifications): each spec `displayType` gets its own presentation instead of a toast (#3014)
|
|
93
|
+
|
|
94
|
+
#3008 closed the **contract** half of this: `NotificationContext`'s union matched
|
|
95
|
+
`NotificationTypeSchema`, and `notify()` materialized the declared type so a
|
|
96
|
+
consumer _could_ branch on it. Nothing did. `NotificationProvider` handed every
|
|
97
|
+
item to the host's `onToast` delegate regardless of type, so an author picking
|
|
98
|
+
`banner` or `inline` got a transient overlay — plausible output, wrong output.
|
|
99
|
+
|
|
100
|
+
Each of the five spec types now has a presentation of its own:
|
|
101
|
+
|
|
102
|
+
| `displayType` | Presentation | Rendered by |
|
|
103
|
+
| ------------- | ------------------------------------------------------ | ---------------------------------- |
|
|
104
|
+
| `toast` | transient overlay (unchanged) | the host's `onToast` delegate |
|
|
105
|
+
| `snackbar` | bottom-anchored bar, one at a time, at most one action | `<NotificationSnackbar />` |
|
|
106
|
+
| `banner` | page-width strip **in the content flow** | `<NotificationBanners />` |
|
|
107
|
+
| `alert` | blocking acknowledgement dialog, FIFO queue | `<NotificationAlerts />` |
|
|
108
|
+
| `inline` | in place, at the raising surface | `<NotificationInline scope="…" />` |
|
|
109
|
+
|
|
110
|
+
The four surface components ship from `@object-ui/components` and subscribe via
|
|
111
|
+
`useNotificationsByPresentation(type, scope?)`.
|
|
112
|
+
|
|
113
|
+
**Answers to the three questions the issue left open:**
|
|
114
|
+
|
|
115
|
+
1. **Banner/inline placement is the host's.** They are not overlays: a banner takes
|
|
116
|
+
space at the top of the content area and an `inline` notification belongs next to
|
|
117
|
+
the thing that raised it. So the context exposes the items and the surfaces
|
|
118
|
+
subscribe, rather than one `onToast`-style delegate positioning everything. An
|
|
119
|
+
`inline` notification carries a `scope` that pairs it with its outlet, so two
|
|
120
|
+
forms on one page don't show each other's messages.
|
|
121
|
+
2. **`alert` is modal-ish but NOT the action system's `ModalHandler`.** That handler
|
|
122
|
+
resolves a page/object, renders it, and reports an `ActionResult` back to the
|
|
123
|
+
`ActionRunner`; a notification alert has no schema, no target and no result.
|
|
124
|
+
Routing it there would mean synthesizing a page just to say "OK". It renders
|
|
125
|
+
through the `AlertDialog` primitive instead — no second action-modal path.
|
|
126
|
+
3. **`snackbar` earns its own component.** It supersedes rather than stacks, anchors
|
|
127
|
+
bottom regardless of the toast position config, and takes at most one action.
|
|
128
|
+
Making it a sonner variant is what "presents as a toast" means.
|
|
129
|
+
|
|
130
|
+
**Also fixed:** auto-dismiss now follows the presentation. `toast`/`snackbar` keep
|
|
131
|
+
the transient timer; `banner`/`alert`/`inline` are persistent unless the raiser sets
|
|
132
|
+
`duration` explicitly — a persistent banner used to evaporate on the shared 5s toast
|
|
133
|
+
timer. `dismissible` is honored on the persistent surfaces (an `alert` always keeps
|
|
134
|
+
its acknowledge button; `dismissible: false` only closes the Escape route).
|
|
135
|
+
|
|
136
|
+
`onToast` now receives **only** `toast` items. A provider with no `onToast` remains
|
|
137
|
+
the supported store-only mode (a bell reading `notifications`/`unreadCount`), but
|
|
138
|
+
raising one of the other four types with its surface unmounted warns in dev, naming
|
|
139
|
+
the component to mount — that failure used to be silent.
|
|
140
|
+
|
|
141
|
+
`NOTIFICATION_PRESENTATIONS` is typed `Record<NotificationPresentation, …>`, so a new
|
|
142
|
+
member in the spec enum fails type-check until its presentation is decided; a parity
|
|
143
|
+
test additionally asserts the table covers `NotificationTypeSchema` exactly and that
|
|
144
|
+
no two types share a surface.
|
|
145
|
+
|
|
146
|
+
- ce08d55: chore(deps): upgrade `@objectstack/*` to 17.0.0-rc.0, and let the spec take back what it now owns
|
|
147
|
+
|
|
148
|
+
`spec` / `client` / `formula` / `lint` move from `^16.x` to `^17.0.0-rc.0`. Two
|
|
149
|
+
groups of v17 changes reach this repo, and they pull in opposite directions —
|
|
150
|
+
the spec pruned surface objectui re-exported, and adopted surface objectui had
|
|
151
|
+
been carrying locally.
|
|
152
|
+
|
|
153
|
+
**The spec pruned dead Theme config (objectstack#3494), so the re-exports went
|
|
154
|
+
with it.** `ThemeSchema` dropped `spacing`, `breakpoints`, `logo`, `density`,
|
|
155
|
+
`wcagContrast`, `rtl`, `touchTarget` and `keyboardNavigation` — authorable but
|
|
156
|
+
never enforced, so authoring them was already a silent no-op. `@object-ui/types`
|
|
157
|
+
re-exported those sub-schemas _by reference_ (issue #2231), so they could not
|
|
158
|
+
survive the prune without becoming hand-written mirrors — exactly the second
|
|
159
|
+
de-facto contract AGENTS.md #0.1 forbids. Removed from the public surface:
|
|
160
|
+
|
|
161
|
+
- Types: `Spacing`, `Breakpoints`, `DensityMode`, `WcagContrastLevel`,
|
|
162
|
+
`ThemeLogo`, and the deprecated `SpacingScale` alias
|
|
163
|
+
- Schemas: `SpacingSchema`, `SpacingScaleSchema`, `BreakpointsSchema`,
|
|
164
|
+
`ThemeLogoSchema`, and the `SpacingSchemaType` / `BreakpointsSchemaType` helpers
|
|
165
|
+
- `Theme.spacing`, `Theme.breakpoints` and `Theme.logo`
|
|
166
|
+
|
|
167
|
+
`mergeThemes` no longer merges the three dropped keys. `generateThemeVars` is
|
|
168
|
+
unaffected — it never emitted them, which is why the liveness audit called them
|
|
169
|
+
dead. The one real consumer was `ThemeProvider`, which set the favicon from
|
|
170
|
+
`theme.logo.favicon`; that path is gone, because v17 strips the key at parse and
|
|
171
|
+
it could never arrive again. The live favicon is unaffected: it comes from
|
|
172
|
+
operator branding (`getFaviconUrl()`), applied in the console's `index.html`,
|
|
173
|
+
`main.tsx`, and on route change.
|
|
174
|
+
|
|
175
|
+
Nothing else read the pruned types. In particular the list-density feature is
|
|
176
|
+
untouched — `useDensityMode` and `rowHeightToDensityMode` use `@object-ui/core`'s
|
|
177
|
+
own local `DensityMode`, which never came from the spec.
|
|
178
|
+
|
|
179
|
+
**The spec adopted objectui's ListColumn extensions (objectui#2231), so the
|
|
180
|
+
extension collapsed.** `ListColumnSchema` used to `.extend()` the spec with two
|
|
181
|
+
fields, each carrying a note to promote it upstream rather than grow the
|
|
182
|
+
extension; v17 did exactly that. `summary` is now the spec's
|
|
183
|
+
`union([ColumnSummarySchema, ColumnSummaryConfigSchema])` — the same enum ∪
|
|
184
|
+
`{ type, field }` form `useColumnSummary` reads — and `prefix` is the spec's
|
|
185
|
+
`ColumnPrefixSchema`. `ListColumnSchema` is now a plain by-reference re-export.
|
|
186
|
+
One behavior change rides along: `prefix.type` defaults to `'text'` on parse
|
|
187
|
+
instead of staying `undefined`, so the cell renderer always gets a value.
|
|
188
|
+
|
|
189
|
+
**Node 22 is now the floor.** Every `@objectstack` package declares
|
|
190
|
+
`engines.node: ">=22.0.0"` (objectstack#3825; Node 20 reached EOL 2026-04-30).
|
|
191
|
+
This repo claimed `>=20` and ran CI on Node 20.x, so it promised — and validated
|
|
192
|
+
— a runtime its own core dependency does not support. `engines.node` is now
|
|
193
|
+
`>=22`, CI runs Node 22.x, and the CI/deployment docs say so.
|
|
194
|
+
|
|
195
|
+
The major stays 17: per AGENTS.md the major tracks `@objectstack`'s major, which
|
|
196
|
+
is also 17, and that convention deliberately outranks semver purity — so the
|
|
197
|
+
removals above ship as a minor rather than desyncing the two.
|
|
198
|
+
|
|
199
|
+
- 0ded602: fix(form): a server rejection that names fields now marks those fields (objectstack#3896)
|
|
200
|
+
|
|
201
|
+
The server has always said which field it rejected. `@objectstack/objectql`'s
|
|
202
|
+
validators throw `VALIDATION_FAILED` with `fields[]` — one entry per offending
|
|
203
|
+
field, each with a human `message` — and both the REST layer and the runtime
|
|
204
|
+
dispatcher serve that as a 400 with the entries intact.
|
|
205
|
+
|
|
206
|
+
Every form dropped them. The submit handler caught the rejection, ran the
|
|
207
|
+
message through `extractWriteErrorMessage`, and showed **one undirected toast**:
|
|
208
|
+
the user was told something was wrong but not _what_, on a surface that already
|
|
209
|
+
knows how to mark an input — and already does exactly that for client-side
|
|
210
|
+
validation. On a long form the offending field was often off-screen, so "创建"
|
|
211
|
+
appeared to do nothing.
|
|
212
|
+
|
|
213
|
+
**Now the two failures behave identically, because they share one
|
|
214
|
+
implementation.** The per-field marking, the toast naming the fields, and the
|
|
215
|
+
scroll-and-focus of the first offender (#2793) were extracted from the
|
|
216
|
+
client-side invalid handler; the server path calls the same function. As far as
|
|
217
|
+
the person filling in the form is concerned these are the same event — only the
|
|
218
|
+
referee differs.
|
|
219
|
+
|
|
220
|
+
Three layers, each of which was dropping the detail:
|
|
221
|
+
|
|
222
|
+
- **`@object-ui/react`** — new `extractFieldErrors(err)` (exported alongside
|
|
223
|
+
`extractWriteErrorMessage` / `isPermissionError`) normalises the three shapes
|
|
224
|
+
the error can arrive in: a typed `ValidationError` from the ObjectStack
|
|
225
|
+
adapter, the raw `@objectstack/client` error (whose `details` falls back to the
|
|
226
|
+
whole response body, which is where `fields[]` lands), and a hand-rolled error
|
|
227
|
+
carrying `fields` directly — the server duck-types that shape identically, so
|
|
228
|
+
the client must not be pickier than the server. Entries with no usable `field`
|
|
229
|
+
are **dropped rather than guessed at**: marking an innocent input is worse than
|
|
230
|
+
the generic toast.
|
|
231
|
+
- **`@object-ui/data-objectstack`** — `normaliseClientError` now maps a 400
|
|
232
|
+
`VALIDATION_FAILED` onto the `ValidationError` class that has sat in
|
|
233
|
+
`errors.ts` since the package was written, exported and **never once
|
|
234
|
+
constructed**. Its `validationErrors: Array<{ field, message }>` shape was
|
|
235
|
+
already exactly right. `create` also now normalises at all: only `update` did,
|
|
236
|
+
so a rejected insert reached callers as the raw client error — and a create is
|
|
237
|
+
the path that most often trips required-field validation.
|
|
238
|
+
- **`@object-ui/components`** — the form renderer maps the entries onto
|
|
239
|
+
`form.setError` and takes over the failure, **but only when every rejected
|
|
240
|
+
field has a visible input to carry it**. If the server also rejected something
|
|
241
|
+
the form does not render, it falls through to the banner, whose top-level
|
|
242
|
+
message concatenates every field's reason — so the part the user cannot see
|
|
243
|
+
inline is still said out loud instead of silently dropped.
|
|
244
|
+
|
|
245
|
+
This also removes the need for the client-side predicate mirroring added in
|
|
246
|
+
#2962: a form no longer has to guess what the server will reject in order to
|
|
247
|
+
warn about it beforehand, and mirrored predicates drift.
|
|
248
|
+
|
|
249
|
+
Non-field failures (403 / permission denials / anything without `fields[]`) take
|
|
250
|
+
exactly the path they took before.
|
|
251
|
+
|
|
252
|
+
### Patch Changes
|
|
253
|
+
|
|
254
|
+
- fc0272a: fix(actions): apply the ADR-0066 D4 capability gate on every action surface (framework#3923)
|
|
255
|
+
|
|
256
|
+
An action declaring `requiredPermissions` is supposed to be one declaration with
|
|
257
|
+
two enforcement surfaces: 403 on the server, hidden button in the UI. The UI half
|
|
258
|
+
only ever ran inside `ActionEngine.getActionsForLocation` — and the surfaces
|
|
259
|
+
`record_header`, `record_more`, `list_item` and `list_toolbar` actually render on
|
|
260
|
+
do not go through the engine. They filter their own action lists. So a button
|
|
261
|
+
declaring a capability nobody holds rendered, live and clickable, on the record
|
|
262
|
+
header, in every grid row menu, and on the list toolbar. For a `type: 'api'`
|
|
263
|
+
action pointed at a self-authored endpoint, nothing else was checking either: the
|
|
264
|
+
platform's action route (which is where the 403 comes from) never sees that
|
|
265
|
+
request.
|
|
266
|
+
|
|
267
|
+
`page:header`, `action:bar` (business _and_ `systemActions`) and the grid's
|
|
268
|
+
`RowActionMenu` now apply the same gate, via a shared `useCapabilityGate()` so
|
|
269
|
+
the surfaces cannot drift apart. The rule is the engine's, unchanged: hide unless
|
|
270
|
+
the caller holds **all** declared capabilities; an empty held set is "holds
|
|
271
|
+
nothing" and gates; **unknown** — no action runtime, no resolved capabilities —
|
|
272
|
+
fails OPEN, because the server is the authority and hiding a permitted user's
|
|
273
|
+
button on missing client data is the worse failure.
|
|
274
|
+
|
|
275
|
+
The record surface was also feeding the gate nothing to work with.
|
|
276
|
+
`RecordDetailView` mounts its own `<ActionProvider>`, which shadows the shell's
|
|
277
|
+
for every action on that page, and seeded it with identity only — no
|
|
278
|
+
`systemPermissions`. Since unknown fails open, that alone un-gated every
|
|
279
|
+
`record_header` / `record_more` / `record_section` action on the one page those
|
|
280
|
+
locations exist on. It now forwards the caller's resolved capabilities (and only
|
|
281
|
+
once they have actually resolved, so a standalone embed without a
|
|
282
|
+
`PermissionProvider` keeps failing open rather than hiding everything).
|
|
283
|
+
|
|
284
|
+
`useRecordEditable`'s record-level explain probe went out on a bare
|
|
285
|
+
`fetch(..., { credentials: 'include' })`. A bearer-token session carries its
|
|
286
|
+
credential in the `Authorization` header, not a cookie, so the probe came back
|
|
287
|
+
401 on a perfectly valid admin session and the verdict silently failed open —
|
|
288
|
+
the hook was inert in exactly the deployments it was written for. It now rides
|
|
289
|
+
the host's authenticated fetch (`SchemaRendererProvider`'s `apiFetch`), falling
|
|
290
|
+
back to the global one for standalone embeds.
|
|
291
|
+
|
|
292
|
+
- 9eb932b: fix(console): three real-user console failures — 403 blamed on the network, ⌘K search capped at 8 objects, nav gating fields inert
|
|
293
|
+
|
|
294
|
+
1. **List error panel classifies the failure** (`plugin-list`, `i18n`): a 403/401 from the data source used to render the same "check your connection" copy as a genuine outage, sending users to debug their network while the server was correctly denying access. The panel now classifies by `httpStatus`/`status`/`statusCode`, the `PERMISSION_DENIED`/`UNAUTHORIZED` error codes, or an `HTTP <status>` message prefix, and renders dedicated permission-denied / sign-in-required copy (all nine locales).
|
|
295
|
+
|
|
296
|
+
2. **⌘K / full-page search scope is no longer truncated** (`react`): `maxObjectsQueried` caps the per-object fanout fallback, not the search scope — it used to slice the candidate pool itself, so the `objects` whitelist sent to the platform's `/api/v1/search` only ever named the first 8 nav objects. Which sidebar group came first decided which records were findable; everything later in the nav was unsearchable no matter what the user typed.
|
|
297
|
+
|
|
298
|
+
3. **Nav gating fields finally gate** (`app-shell`): `evaluateVisibility` only evaluated `${…}` template strings, so the `{ dialect: 'cel', source }` envelopes the spec normalizes every authored `visible` predicate into fell through to a blanket "visible" — a constant-false predicate still rendered for everyone. It now delegates to `ExpressionEvaluator.evaluateCondition`, which routes CEL envelopes to the canonical `@objectstack/formula` engine. And the sidebars' `requiredPermissions` check treats a bare name as an ADR-0066 system capability (union of the user's permission-set `systemPermissions` from `/me/permissions`) — the same subset rule the server applies to `AppSchema.requiredPermissions` — instead of misreading it as `can(<name>, 'read')`, which had degraded `requiredPermissions` into a hide-from-everyone switch (admins included). The `object:action` form and the legacy object-read fallback keep working.
|
|
299
|
+
|
|
300
|
+
- 4952edf: fix(errors): error-code branches survive the framework's ADR-0112 rename — objectstack#3841
|
|
301
|
+
|
|
302
|
+
Framework ADR-0112 renamed the whole `error.code` vocabulary from lowercase
|
|
303
|
+
`snake_case` to `SCREAMING_SNAKE` (`destructive_change` → `DESTRUCTIVE_CHANGE`).
|
|
304
|
+
Eleven places compared `err.code` against the old spelling with `===`, so against
|
|
305
|
+
a swept server they simply stopped matching — and nothing threw. The affordance
|
|
306
|
+
each branch guards just vanished and the user got the generic error toast instead:
|
|
307
|
+
|
|
308
|
+
- the destructive-change confirm dialog (resource editor, permission matrix)
|
|
309
|
+
- the "create a writable package first" hint
|
|
310
|
+
- field-scoped validation issues on embedded item saves
|
|
311
|
+
- the all-or-nothing publish summary naming the causal item
|
|
312
|
+
- unknown-object tolerance in the app header and in record search
|
|
313
|
+
- the marketplace's local-install messages for conflict / auth / unavailable
|
|
314
|
+
- `isNotFoundError` in the data layer
|
|
315
|
+
|
|
316
|
+
`RECORD_NOT_FOUND` had already been renamed a release earlier, so that branch was
|
|
317
|
+
already dead before this fix.
|
|
318
|
+
|
|
319
|
+
New `errorCodeIs` / `errorCodeIsAnyOf` in `@object-ui/types` compare
|
|
320
|
+
case-insensitively, so the console keeps working against servers on either side
|
|
321
|
+
of the rename — the console ships separately from the server it talks to. Every
|
|
322
|
+
call site now passes the catalog (SCREAMING) spelling, and `error-code.ts` is the
|
|
323
|
+
single file to delete once no supported server emits the old vocabulary.
|
|
324
|
+
|
|
325
|
+
- 2374a49: fix(sdui): a react page no longer loses its state to a memo that never held, and a source that exports nothing fails loudly
|
|
326
|
+
|
|
327
|
+
Writing the regression guard for objectui#2954's "latent hazard" found it was
|
|
328
|
+
already real.
|
|
329
|
+
|
|
330
|
+
**`evaluatedSchema` was memoised on values rebuilt every render.**
|
|
331
|
+
`SchemaRenderer` fell back to a fresh `{}` when no `SchemaRendererProvider` sat
|
|
332
|
+
above it, and `usePageVariables()` returned a brand-new object literal outside a
|
|
333
|
+
`PageVariablesProvider`. Both feed the `evaluatedSchema` memo's dependency list,
|
|
334
|
+
so for any tree without those providers the memo never hit: the schema was
|
|
335
|
+
re-cloned and the ExpressionEvaluator re-run on every render, and children got a
|
|
336
|
+
new schema identity every time. A `kind:'react'` page memoises its compiled
|
|
337
|
+
source on that identity, so the page was recompiled — a new page function, a new
|
|
338
|
+
element type — and React remounted it, silently discarding the user's `useState`.
|
|
339
|
+
Any registry notification (every lazy plugin's first load) triggered it. Both
|
|
340
|
+
fallbacks are now module constants.
|
|
341
|
+
|
|
342
|
+
**A source that exports nothing now throws instead of rendering blank.**
|
|
343
|
+
`generateElement` inserts the implicit `export default` only when the source
|
|
344
|
+
_starts with_ JSX, a `function` declaration, `()` or `class` — so the very
|
|
345
|
+
common `const Page = () => …` exported nothing, and the page rendered blank with
|
|
346
|
+
no error reported anywhere. It now throws with a message naming the fix, which
|
|
347
|
+
`ReactRunner`'s error panel surfaces. `export default null` still means "render
|
|
348
|
+
nothing"; a default export that is not a component throws too.
|
|
349
|
+
|
|
350
|
+
**`PageSchema['kind']` matches `@objectstack/spec`.** It declared
|
|
351
|
+
`'full' | 'slotted'` while the renderer had shipped `'react'` and
|
|
352
|
+
`'html'`/`'jsx'` since ADR-0080 and read the field through a cast. The union now
|
|
353
|
+
spells all five and the cast is gone.
|
|
354
|
+
|
|
355
|
+
Docs: new `content/docs/guide/react-pages.md` (choosing between the executed and
|
|
356
|
+
parsed tiers, the capability gate, the injected scope, flat props, `Block`,
|
|
357
|
+
`useAdapter`, source shapes, error handling) and a `@object-ui/react-runtime`
|
|
358
|
+
README — the package had neither, while being the tier AI-authored pages target.
|
|
359
|
+
|
|
360
|
+
- Updated dependencies [62311b6]
|
|
361
|
+
- Updated dependencies [9e7349e]
|
|
362
|
+
- Updated dependencies [8864971]
|
|
363
|
+
- Updated dependencies [9b773f9]
|
|
364
|
+
- Updated dependencies [1cf0de7]
|
|
365
|
+
- Updated dependencies [752e18f]
|
|
366
|
+
- Updated dependencies [c785740]
|
|
367
|
+
- Updated dependencies [b41f401]
|
|
368
|
+
- Updated dependencies [19e9fa0]
|
|
369
|
+
- Updated dependencies [d61efd1]
|
|
370
|
+
- Updated dependencies [95b7214]
|
|
371
|
+
- Updated dependencies [7d9734d]
|
|
372
|
+
- Updated dependencies [6ae818e]
|
|
373
|
+
- Updated dependencies [9eb932b]
|
|
374
|
+
- Updated dependencies [746dd00]
|
|
375
|
+
- Updated dependencies [aebfa4f]
|
|
376
|
+
- Updated dependencies [38ca8be]
|
|
377
|
+
- Updated dependencies [3cb9646]
|
|
378
|
+
- Updated dependencies [4952edf]
|
|
379
|
+
- Updated dependencies [7f0252e]
|
|
380
|
+
- Updated dependencies [7d35010]
|
|
381
|
+
- Updated dependencies [c4d7b20]
|
|
382
|
+
- Updated dependencies [7639a61]
|
|
383
|
+
- Updated dependencies [94e63ef]
|
|
384
|
+
- Updated dependencies [02aef0c]
|
|
385
|
+
- Updated dependencies [6f29aa5]
|
|
386
|
+
- Updated dependencies [d21794c]
|
|
387
|
+
- Updated dependencies [c4db402]
|
|
388
|
+
- Updated dependencies [5319bf1]
|
|
389
|
+
- Updated dependencies [49e5671]
|
|
390
|
+
- Updated dependencies [b5b97e2]
|
|
391
|
+
- Updated dependencies [f59f2c1]
|
|
392
|
+
- Updated dependencies [4874117]
|
|
393
|
+
- Updated dependencies [ad0183a]
|
|
394
|
+
- Updated dependencies [ce08d55]
|
|
395
|
+
- Updated dependencies [a17ef09]
|
|
396
|
+
- Updated dependencies [aa1240a]
|
|
397
|
+
- Updated dependencies [2374a49]
|
|
398
|
+
- Updated dependencies [390c071]
|
|
399
|
+
- Updated dependencies [d10f526]
|
|
400
|
+
- Updated dependencies [2d5d594]
|
|
401
|
+
- Updated dependencies [ea7f477]
|
|
402
|
+
- Updated dependencies [7f23cd0]
|
|
403
|
+
- Updated dependencies [0ded602]
|
|
404
|
+
- Updated dependencies [24e0e0a]
|
|
405
|
+
- Updated dependencies [f8a95e5]
|
|
406
|
+
- Updated dependencies [3a6cf24]
|
|
407
|
+
- Updated dependencies [aa35561]
|
|
408
|
+
- Updated dependencies [03bd53b]
|
|
409
|
+
- Updated dependencies [3c1f321]
|
|
410
|
+
- Updated dependencies [a045a32]
|
|
411
|
+
- Updated dependencies [912496d]
|
|
412
|
+
- Updated dependencies [9867281]
|
|
413
|
+
- @object-ui/core@17.1.0
|
|
414
|
+
- @object-ui/types@17.1.0
|
|
415
|
+
- @object-ui/data-objectstack@17.1.0
|
|
416
|
+
- @object-ui/i18n@17.1.0
|
|
417
|
+
|
|
418
|
+
## 17.0.0
|
|
419
|
+
|
|
420
|
+
### Major Changes
|
|
421
|
+
|
|
422
|
+
- c77108c: refactor(spec-bridge): remove the dead page/dashboard bridges (#1892)
|
|
423
|
+
|
|
424
|
+
`SpecBridge`'s `page` and `dashboard` bridges — `bridgePage`, `bridgeDashboard`,
|
|
425
|
+
and the `SpecBridge#transformPage` / `#transformDashboard` methods — had no
|
|
426
|
+
runtime consumer. Pages render through their own renderer and dashboards
|
|
427
|
+
through `DashboardView → DashboardRenderer → DatasetWidget` (ADR-0021); neither
|
|
428
|
+
path routes through `SpecBridge`. The dashboard bridge's input shape
|
|
429
|
+
(`object` / `categoryField` / `valueField` / `aggregate`) is the pre-ADR-0021
|
|
430
|
+
widget model, which the strict `DashboardWidgetSchema` now rejects — so the
|
|
431
|
+
bridge could not receive a spec-valid dashboard even in principle.
|
|
432
|
+
|
|
433
|
+
Flagged dead by the metadata-liveness audit (framework #1878 / #1892). The
|
|
434
|
+
`list` and `form` bridges are unaffected and remain the live authoring path.
|
|
435
|
+
|
|
436
|
+
BREAKING CHANGE: the public exports `bridgePage`, `bridgeDashboard`, and the
|
|
437
|
+
`SpecBridge#transformPage` / `#transformDashboard` methods are removed. There
|
|
438
|
+
is no replacement — render pages and dashboards through their renderers
|
|
439
|
+
(`DashboardRenderer` / the page renderer) directly.
|
|
440
|
+
|
|
441
|
+
### Minor Changes
|
|
442
|
+
|
|
443
|
+
- 952b978: fix(detail): the approval band honors the node's `lockRecord` instead of assuming every approval locks (#2902)
|
|
444
|
+
|
|
445
|
+
A record detail page treated "a pending approval request exists" as "this
|
|
446
|
+
record is locked". An approval node declares `lockRecord` (default `true`), and
|
|
447
|
+
on `lockRecord: false` the server keeps accepting writes for the whole time
|
|
448
|
+
that node waits — so the console was asserting a lock the backend did not
|
|
449
|
+
enforce.
|
|
450
|
+
|
|
451
|
+
The label was the smaller half of it. The same conflated signal fed `canEdit`,
|
|
452
|
+
so the record-level inline-edit session was suppressed too: no pencils,
|
|
453
|
+
`enter()` a no-op. On a single-approver step — a department head or plant
|
|
454
|
+
manager, exactly the case `lockRecord: false` exists for, where the approver is
|
|
455
|
+
meant to fill in the missing detail before deciding — the capability was
|
|
456
|
+
unreachable from the UI. And a flow chaining nodes with different policies drew
|
|
457
|
+
one identical band for "edit freely" and "the server will reject your save with
|
|
458
|
+
`RECORD_LOCKED`", so the two states were indistinguishable until Save failed.
|
|
459
|
+
|
|
460
|
+
Approval state is now two signals:
|
|
461
|
+
|
|
462
|
+
- **`approvalPending`** — an approval is running. Drives the band and the recall
|
|
463
|
+
button, both meaningful whether or not the record is editable.
|
|
464
|
+
- **`locked`** — that approval also forbids edits, from the pending node's
|
|
465
|
+
`lock_record` (framework#3814, read off the same `node_config_json` snapshot
|
|
466
|
+
the server's record-lock hook reads).
|
|
467
|
+
|
|
468
|
+
The band renders two states: amber lock + "Locked for approval", or sky clock +
|
|
469
|
+
"In approval · editable", each with its own tooltip. Recall moved out of the
|
|
470
|
+
locked branch — an editable pending approval is just as recallable. Inline
|
|
471
|
+
editing stays live in the editable state.
|
|
472
|
+
|
|
473
|
+
`InlineEditProvider` takes a new optional `approvalPending` prop, defaulting to
|
|
474
|
+
`locked`, so a host that threads only `locked` renders exactly as before. The
|
|
475
|
+
record's `approval_status` field remains the fallback for backends with no
|
|
476
|
+
approvals API; it carries no node granularity, so it still reads as locked — as
|
|
477
|
+
does a pending request from a backend too old to report the policy.
|
|
478
|
+
|
|
479
|
+
New `detail.approvalPendingEditable` / `detail.approvalPendingTooltip` keys are
|
|
480
|
+
translated in all ten locales.
|
|
481
|
+
|
|
482
|
+
- 1767124: feat(grid): compute all eleven spec column summary aggregations (#2890)
|
|
483
|
+
|
|
484
|
+
`ColumnSummarySchema` accepts eleven aggregation names; `useColumnSummary` computed
|
|
485
|
+
five. The other six — `none`, `count_empty`, `count_filled`, `count_unique`,
|
|
486
|
+
`percent_empty`, `percent_filled` — passed validation at authoring time and then
|
|
487
|
+
rendered a blank footer cell, with no error raised on either side.
|
|
488
|
+
|
|
489
|
+
The computation now splits into two families. Count and percent read _raw_ cell
|
|
490
|
+
values, before the numeric parse, so they work on text, select and lookup columns and
|
|
491
|
+
a value that does not parse as a number still counts as a filled row; a cell is empty
|
|
492
|
+
when it is `null`, `undefined`, `""` or an empty array. `sum`/`avg`/`min`/`max` keep
|
|
493
|
+
the existing numeric parse and column formatting.
|
|
494
|
+
|
|
495
|
+
Two behavior changes follow from the enum carrying both `count` and `count_filled`,
|
|
496
|
+
which cannot mean the same thing:
|
|
497
|
+
|
|
498
|
+
- `count` is now every row; `count_filled` is the non-empty variant. Only a column
|
|
499
|
+
whose values are all empty renders differently than before.
|
|
500
|
+
- a zero count renders `Empty: 0` instead of collapsing to a blank cell.
|
|
501
|
+
|
|
502
|
+
Column currency/percent formatting is gated to the numeric family, so `count_unique`
|
|
503
|
+
on a currency column reads `Unique: 3` and not `$3.00`. `none` and unrecognized names
|
|
504
|
+
skip the entry entirely, so a view whose columns all opt out renders no footer row.
|
|
505
|
+
|
|
506
|
+
`ListColumnSchema`'s objectui-local `{ type, field }` arm now takes its vocabulary
|
|
507
|
+
from `SpecColumnSummarySchema` by reference — it was stuck at the same five names,
|
|
508
|
+
which left the per-column `field` override unavailable for the six new aggregations.
|
|
509
|
+
|
|
510
|
+
A parity test asserts the renderer's supported set equals the spec enum in both
|
|
511
|
+
directions: a spec name the renderer omits is the bug above, and a renderer name the
|
|
512
|
+
spec omits would be local dialect (Commandment #0).
|
|
513
|
+
|
|
514
|
+
**Removed:** `useColumnSummary` from `@object-ui/react`. It was a second, unrelated
|
|
515
|
+
hook of the same name with no callers — a different API, a comment claiming it
|
|
516
|
+
implemented spec v2.0.7, and a `distinct` aggregation that is not in the spec
|
|
517
|
+
vocabulary at all (the spec calls it `count_unique`). Use `useColumnSummary` from
|
|
518
|
+
`@object-ui/plugin-grid`, which implements the spec enum.
|
|
519
|
+
|
|
520
|
+
- c6cfdf1: feat(react)!: trim the dead device/preference delegates from
|
|
521
|
+
`useClientNotifications` (objectstack#3612 companion)
|
|
522
|
+
|
|
523
|
+
`registerDevice`, `getPreferences`, and `updatePreferences` delegated to
|
|
524
|
+
`@objectstack/client` methods that were deleted in objectstack#3612 — the
|
|
525
|
+
`/notifications/devices` and `/notifications/preferences` server routes they
|
|
526
|
+
targeted were never built, so every call already surfaced an error at
|
|
527
|
+
runtime. The hook keeps `fetchNotifications` and `markAsRead` (both
|
|
528
|
+
dispatcher-served and route-ledgered). Breaking only for code destructuring
|
|
529
|
+
the removed functions from the hook result; nothing in this repo did.
|
|
530
|
+
|
|
531
|
+
### Patch Changes
|
|
532
|
+
|
|
533
|
+
- 8ecf5a6: Command palette (⌘K) now surfaces record search hits from the platform's global
|
|
534
|
+
search endpoint (`GET /api/v1/search`).
|
|
535
|
+
|
|
536
|
+
Previously the palette only ran a per-object `find({ $search })` fanout (the
|
|
537
|
+
metadata-driven ADR-0061 search), which misses records that only the global
|
|
538
|
+
search index knows about — so typing a well-known record name returned no
|
|
539
|
+
records even though `/api/v1/search` served them. `ObjectStackAdapter` now
|
|
540
|
+
exposes a `searchAll(query, { limit, objects })` method that calls the unified
|
|
541
|
+
endpoint, `useRecordSearch` prefers it when present (falling back to the fanout
|
|
542
|
+
otherwise), and the palette renders the resulting record hits grouped by object.
|
|
543
|
+
|
|
544
|
+
- 7b35e4b: fix(dashboard,charts): resolve `{current_user_id}` in widget filters (framework #3574)
|
|
545
|
+
|
|
546
|
+
A dashboard widget filtered on `{current_user_id}` rendered `0`. The token
|
|
547
|
+
reached SQL as a literal, matched no row, and nothing was logged on the client
|
|
548
|
+
or the server — a silent zero that reads as "you have no work" rather than
|
|
549
|
+
"this filter did not resolve". The same token in a list-view filter resolved
|
|
550
|
+
correctly, so a user-scoped list and a user-scoped widget over the same data
|
|
551
|
+
disagreed.
|
|
552
|
+
|
|
553
|
+
There was no shared resolver. Three ad-hoc implementations had grown up
|
|
554
|
+
independently — `ObjectView` for list views, `ObjectDataPage` for URL filter
|
|
555
|
+
triples, `NavigationRenderer` for hrefs — and each understood only the filter
|
|
556
|
+
shape its own surface used. `ObjectView`'s opened with
|
|
557
|
+
`if (!Array.isArray(filter)) return filter`, so it could not have been reused
|
|
558
|
+
by dashboard widgets even in principle: widget filters are MongoDB-style
|
|
559
|
+
objects. Widgets therefore got no resolution at all — `DatasetWidget` called
|
|
560
|
+
`resolveDateMacros` and nothing else, which is why `{today}` worked in a widget
|
|
561
|
+
and `{current_user_id}` silently did not.
|
|
562
|
+
|
|
563
|
+
- **`@object-ui/core`** — new `utils/filter-tokens.ts` with
|
|
564
|
+
`resolveContextTokens` and `resolveFilterPlaceholders`. The latter expands
|
|
565
|
+
_every_ placeholder vocabulary in one call and is what surfaces should use;
|
|
566
|
+
resolving only some of them is the whole defect. The walk handles arrays and
|
|
567
|
+
plain objects uniformly, so one resolver covers both platform filter shapes.
|
|
568
|
+
- **`@object-ui/react`** — new `FilterScopeProvider` / `useFilterScope`. The
|
|
569
|
+
renderer packages deliberately do not depend on `@object-ui/auth`, so the
|
|
570
|
+
shell supplies the session values. This is a separate context from
|
|
571
|
+
`PredicateScopeContext`, which is the expression evaluation scope and carries
|
|
572
|
+
no organization.
|
|
573
|
+
- **`@object-ui/plugin-dashboard` / `@object-ui/plugin-charts`** — all six
|
|
574
|
+
widgets that previously resolved date macros only now resolve both
|
|
575
|
+
vocabularies: `DatasetWidget`, `ObjectMetricWidget`, `ObjectDataTable`,
|
|
576
|
+
`ObjectPivotTable`, and `ObjectChart` (dataset-bound and inline paths). The
|
|
577
|
+
chart's `compareTo` comparison filter gets the session pass too — otherwise
|
|
578
|
+
the overlay series silently ignored the owner clause the primary series
|
|
579
|
+
honoured.
|
|
580
|
+
- **`@object-ui/app-shell`** — `ObjectView`'s local `substituteFilterTokens`
|
|
581
|
+
and `ObjectDataPage`'s inline `=== '{current_user_id}'` ternary now delegate
|
|
582
|
+
to the shared resolver, so both also gain `{current_org_id}` and date macros.
|
|
583
|
+
Two of the three ad-hoc implementations are gone rather than joined by a
|
|
584
|
+
fourth.
|
|
585
|
+
|
|
586
|
+
An unresolvable token is left intact rather than dropped: leaving it yields an
|
|
587
|
+
empty result, whereas dropping the clause would _widen_ the result set and show
|
|
588
|
+
a signed-out viewer everyone's data. It is no longer silent — the resolver
|
|
589
|
+
warns, naming the token, and suggests the intended spelling for known
|
|
590
|
+
near-misses (`{current_user}`, `{user_id}`, `{organization_id}`). Authoring-time
|
|
591
|
+
enforcement lands separately as `filter-token-unknown` in `@objectstack/lint`.
|
|
592
|
+
|
|
593
|
+
- Updated dependencies [0b3be01]
|
|
594
|
+
- Updated dependencies [3c4d935]
|
|
595
|
+
- Updated dependencies [4b60d2d]
|
|
596
|
+
- Updated dependencies [952b978]
|
|
597
|
+
- Updated dependencies [de5e40c]
|
|
598
|
+
- Updated dependencies [1a03af6]
|
|
599
|
+
- Updated dependencies [3e886eb]
|
|
600
|
+
- Updated dependencies [cfc675e]
|
|
601
|
+
- Updated dependencies [20df08c]
|
|
602
|
+
- Updated dependencies [1767124]
|
|
603
|
+
- Updated dependencies [8ecf5a6]
|
|
604
|
+
- Updated dependencies [af705b9]
|
|
605
|
+
- Updated dependencies [0502a7c]
|
|
606
|
+
- Updated dependencies [7b35e4b]
|
|
607
|
+
- Updated dependencies [e16ed2d]
|
|
608
|
+
- Updated dependencies [c6fd752]
|
|
609
|
+
- Updated dependencies [f9bbddb]
|
|
610
|
+
- Updated dependencies [dfd3705]
|
|
611
|
+
- Updated dependencies [2735de6]
|
|
612
|
+
- Updated dependencies [6dee2cb]
|
|
613
|
+
- Updated dependencies [e05f052]
|
|
614
|
+
- Updated dependencies [0502a7c]
|
|
615
|
+
- Updated dependencies [faad45e]
|
|
616
|
+
- Updated dependencies [09c6a17]
|
|
617
|
+
- Updated dependencies [c7cff19]
|
|
618
|
+
- Updated dependencies [ba73a02]
|
|
619
|
+
- Updated dependencies [cd09a7b]
|
|
620
|
+
- Updated dependencies [f1abf0e]
|
|
621
|
+
- Updated dependencies [f05b84e]
|
|
622
|
+
- Updated dependencies [9b4b952]
|
|
623
|
+
- Updated dependencies [7d46648]
|
|
624
|
+
- Updated dependencies [6e8fd3c]
|
|
625
|
+
- Updated dependencies [bb4aa25]
|
|
626
|
+
- Updated dependencies [75f1cdf]
|
|
627
|
+
- Updated dependencies [662bdf9]
|
|
628
|
+
- Updated dependencies [059a052]
|
|
629
|
+
- Updated dependencies [53642d4]
|
|
630
|
+
- Updated dependencies [8aae006]
|
|
631
|
+
- Updated dependencies [d62fb1f]
|
|
632
|
+
- Updated dependencies [d147a13]
|
|
633
|
+
- Updated dependencies [c6aaed8]
|
|
634
|
+
- Updated dependencies [263f885]
|
|
635
|
+
- Updated dependencies [dc334da]
|
|
636
|
+
- @object-ui/i18n@17.0.0
|
|
637
|
+
- @object-ui/types@17.0.0
|
|
638
|
+
- @object-ui/data-objectstack@17.0.0
|
|
639
|
+
- @object-ui/core@17.0.0
|
|
640
|
+
|
|
3
641
|
## 16.1.0
|
|
4
642
|
|
|
5
643
|
### Minor Changes
|
|
@@ -63,7 +701,7 @@
|
|
|
63
701
|
|
|
64
702
|
Together with the `^15.1.1` alignment (#2662), a renderer CEL predicate now
|
|
65
703
|
reaches the identical verdict as the server — including the framework's
|
|
66
|
-
`dateField == today()` equality fix (objectstack-ai/
|
|
704
|
+
`dateField == today()` equality fix (objectstack-ai/objectstack#3205) once it
|
|
67
705
|
lands in a published 15.x. The broader home-grown-vs-canonical divergence
|
|
68
706
|
motivation is #2661.
|
|
69
707
|
|