@object-ui/components 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 CHANGED
@@ -1,5 +1,234 @@
1
1
  # @object-ui/components
2
2
 
3
+ ## 14.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - dea65f7: Unify the list-view conditional tier onto the canonical CEL engine (#1584).
8
+
9
+ Conditional formatting (list / grid / kanban) and row-action `visible` /
10
+ `disabled` predicates are now evaluated by `@objectstack/formula`'s
11
+ `ExpressionEngine` — the same engine the server uses — instead of the legacy
12
+ JS-dialect `ExpressionEvaluator`, matching how `@objectstack/spec` already types
13
+ these surfaces (`ExpressionInputSchema` / CEL). The whole platform now speaks one
14
+ expression dialect (framework ADR-0058).
15
+
16
+ - `@object-ui/core`: new `evalRowPredicate` + `resolveConditionalFormatting`
17
+ helpers (next to `evalFieldPredicate`). One implementation of all three
18
+ formatting rule shapes; dialect routing (a `{ dialect: 'cel' }` envelope is
19
+ always CEL; a bare string is CEL unless it carries legacy-only syntax
20
+ (`${…}` / `===` / `?.` / `.includes()`), which routes to the old engine with a
21
+ one-time deprecation warning); the native `{ field, operator, value }` form is
22
+ translated to CEL.
23
+ - `@object-ui/react`: new `useRowPredicate` hook (canonical CEL, ambient
24
+ predicate scope merged).
25
+ - Consumers converged: `ListView.evaluateConditionalFormatting` (thin wrapper,
26
+ export kept), `ObjectGrid` row styling (inline copy removed), kanban card
27
+ styles, and the grid / data-table row-action menus. `plugin-view`'s kanban
28
+ branch now forwards top-level `conditionalFormatting` (previously dropped).
29
+ - Row-action `visible` fails **closed** (broken predicate → hidden + warn);
30
+ `disabled` fails soft. The CEL `in` operator (and list membership) now work in
31
+ row predicates — the legacy engine could not parse them.
32
+ - The legacy `FormField.condition: { field, equals/notEquals/in }` is retired to
33
+ a CEL translation (back-compat preserved); `FieldDesigner` migrated to
34
+ `visibleWhen`.
35
+
36
+ Fully back-compat: existing conditional-formatting rules, row-action predicates,
37
+ and form `condition` metadata keep working (translated / routed as needed).
38
+
39
+ - 073e7aa: Conditional tabs (framework#2606): the `page:tabs` renderer honors an item-level
40
+ `visibleWhen` CEL predicate — when it evaluates FALSE the WHOLE tab (header +
41
+ panel) is omitted from the strip, unlike a child component's own `visibleWhen`,
42
+ which hides only the panel content and leaves an empty tab header behind. The
43
+ predicate binds the same environment as page-component `visibleWhen` (record
44
+ fields bare and via `record.`/`data.`, `user`/`current_user`, and page state as
45
+ `page.<var>`) and re-evaluates live as page variables change. The strip is now
46
+ controlled: when the ACTIVE tab's predicate flips false, selection falls back to
47
+ the first visible tab instead of leaving a blank panel, and the user's own
48
+ selection is restored if the tab becomes visible again. Canonical ADR-0089 key
49
+ only — the deprecated `visibility`/`visibleOn` aliases are not read on this new
50
+ surface. Items without `visibleWhen` behave exactly as before.
51
+ - 6c0135c: feat(page-header): metadata-driven multi-button record header (#2361)
52
+
53
+ The record detail page header no longer hardcodes a single inline primary
54
+ button (`INLINE_MAX = 1`). It now renders up to `maxVisible` actions
55
+ side-by-side (default 3 desktop / 1 mobile, overridable via
56
+ `maxVisible` / `mobileMaxVisible` on the `page:header` schema) — the same
57
+ contract as `action:bar` — so multi-action objects (e.g. Lead: Convert /
58
+ Assign / Return) can surface several primary buttons at once.
59
+
60
+ Which actions claim the inline slots is declared in metadata, mirroring the
61
+ `action:bar` #2339 rules:
62
+
63
+ - `order` ascending (unset = 0; lower = more prominent), stable sort;
64
+ - `variant: 'primary'` as a tie-break within equal order (also mapped to the
65
+ Shadcn `default` Button variant instead of leaking through);
66
+ - `component: 'action:menu'` pins an action inside the `⋯` overflow menu
67
+ regardless of the action count.
68
+
69
+ The synthesized system actions declare their placement accordingly:
70
+ `sys_edit` gets `order: 100` (behind every authored business action, but
71
+ still inline when slots remain), while `sys_share` / `sys_delete` are pinned
72
+ into the `⋯` menu via `component: 'action:menu'` — Delete never surfaces as
73
+ an inline red button just because an object has few actions.
74
+
75
+ ### Patch Changes
76
+
77
+ - 055e1d2: fix(components): exit inline edit mode for injected cell editors (#2321)
78
+
79
+ Non-discrete inline-edit cells (text, number, date, lookup, user, currency,
80
+ percent, …) got permanently stuck in edit mode: the host-injected `@object-ui/fields`
81
+ widget staged its value on every change but had no way to leave edit mode, so
82
+ clicking outside, pressing Enter, and the row Save button all failed to dismiss
83
+ the editor. Only discrete pickers (select/boolean/radio/rating), which commit on
84
+ selection, exited correctly.
85
+
86
+ The DataTable now gives injected widget editors the same exit affordances the
87
+ built-in `<input>` editors have:
88
+
89
+ - **Click-outside** commits the staged value and exits, via a capture-phase
90
+ document `pointerdown` listener. It is portal-aware — clicking inside a lookup
91
+ popover / record-picker dialog the widget itself opened does not exit, and a
92
+ modal that merely hosts the grid does not suppress the commit.
93
+ - **Enter** commits and exits (a multi-line `textarea` keeps inserting newlines).
94
+ - **Escape** reverts this session's staged changes and exits.
95
+
96
+ Keys that bubble up through a React portal from the widget's own popover keep
97
+ driving that popover rather than the cell. Built-in editors are untouched.
98
+
99
+ - f30ff68: fix(components): keep the list-view horizontal scrollbar pinned to the viewport bottom
100
+
101
+ In a list/grid view with many columns, the horizontal scrollbar was only
102
+ reachable after scrolling all the way to the last row. Root cause: the shadcn
103
+ `<Table>` wraps its `<table>` in a `overflow-auto` scroll `<div>`. When
104
+ `DataTable` already renders the table inside a _bounded_
105
+ `flex-1 min-h-0 overflow-auto` region, that default wrapper became a SECOND,
106
+ height-unbounded scroll container — it stretched to the full table height, so
107
+ its horizontal scrollbar sat at the bottom of _all_ rows.
108
+
109
+ - `Table` gains an optional `containerClassName` prop that overrides the
110
+ scroll-wrapper `<div>`'s classes (default behavior unchanged).
111
+ - `DataTable` passes `containerClassName="overflow-visible"` so the outer
112
+ bounded container owns both axes and the horizontal scrollbar stays pinned to
113
+ the viewport bottom — reachable from any scroll position, no need to scroll to
114
+ the last row.
115
+
116
+ Verified end-to-end against the running console (data-table with 60+ rows × 19
117
+ columns): the horizontal scroller is now the bounded `flex-1 min-h-0
118
+ overflow-auto` region (bottom on-screen, within the viewport) and the table can
119
+ be scrolled fully right while still at the top row.
120
+
121
+ - 4afb251: Record-level inline edit polish (objectui#2572, follow-up to #2407) — the five
122
+ rough edges from the live showcase verification pass:
123
+
124
+ - **Expanded reference values pass through to the picker.** `InlineFieldInput`
125
+ no longer collapses an `$expand`-ed record object to a bare id before
126
+ handing it to `LookupField` / `UserField` — the picker resolves the display
127
+ name it already carries instead of re-fetching the referenced record via
128
+ `findOne` (or sticking on the placeholder when it can't). `LookupField`
129
+ still hands its Level-2 pickers (PeoplePicker / RecordPickerDialog) bare
130
+ ids, collapsed via the existing `normalizeId`.
131
+ - **Approval-lock preflight.** The record page now re-reads the approval
132
+ state whenever the record is invalidated (a save can _trigger_ an approval
133
+ flow that locks the record), derives one `approvalLocked` signal
134
+ (`approval_status` pending/in_approval OR an open pending request), gates
135
+ the inline-edit session's `canEdit` with it — hiding the pencil affordances
136
+ and no-op'ing `enter()` on a locked record — and drives the save bar's
137
+ `locked`/`lockedHint` so users can't type into a draft that Save would
138
+ reject with `RECORD_LOCKED`.
139
+ - **Numeric field types edit with the real numeric widgets.** `number` /
140
+ `currency` / `percent` route to `NumberField` / `CurrencyField` /
141
+ `PercentField` (the same widgets the form uses) instead of a free-text
142
+ input: numeric keyboard, symbol adornment, fraction↔percent display
143
+ conversion, and numbers (not strings) into the draft. `NumberField` and
144
+ `CurrencyField` now surface metadata `min`/`max` on the input, `NumberField`
145
+ honors an explicit `step` and steps by 1 for `scale: 0` (previously fell
146
+ back to `any`).
147
+ - **Header Edit CTA stands down during an inline session.** The synthesized
148
+ `sys_edit` action carries `disableDuringInlineEdit`, and the `page:header`
149
+ renderer greys such actions out while `InlineEditContext.editing` — the
150
+ classic form-edit surface can no longer be stacked on top of a live inline
151
+ draft.
152
+ - **Keyboard shortcuts for the shared edit session.** `InlineEditSaveBar`
153
+ binds **Esc → cancel** (deferring to any open Radix layer — popover /
154
+ select / dialog — which owns Escape for "close") and **Cmd/Ctrl+Enter →
155
+ save**, both respecting `saving`/`locked`.
156
+
157
+ - Updated dependencies [82441e4]
158
+ - Updated dependencies [2efa9fd]
159
+ - Updated dependencies [0890fa7]
160
+ - Updated dependencies [2ded18c]
161
+ - Updated dependencies [e628d1f]
162
+ - Updated dependencies [5523fc4]
163
+ - Updated dependencies [887062c]
164
+ - Updated dependencies [23d65c3]
165
+ - Updated dependencies [9e2d58f]
166
+ - Updated dependencies [dea65f7]
167
+ - Updated dependencies [5b52624]
168
+ - Updated dependencies [d5b1bc0]
169
+ - Updated dependencies [f94905d]
170
+ - Updated dependencies [f0f10f5]
171
+ - @object-ui/i18n@14.1.0
172
+ - @object-ui/core@14.1.0
173
+ - @object-ui/types@14.1.0
174
+ - @object-ui/react@14.1.0
175
+ - @object-ui/react-runtime@14.1.0
176
+ - @object-ui/sdui-parser@14.1.0
177
+
178
+ ## 14.0.0
179
+
180
+ ### Minor Changes
181
+
182
+ - 6a74160: Sharing-rule form: pick, don't type. Three new widget-hint field components make
183
+ the generic object form render pickers where an admin previously had to type
184
+ machine data (driven by the framework `widget` hints on `sys_sharing_rule`;
185
+ generalizes the `capability-multiselect` pattern). All degrade to the underlying
186
+ `type` renderer when a widget is unregistered.
187
+
188
+ - **`object-ref`** — choose a registered object by name (searchable `Combobox`),
189
+ backed by the new `DataSource.getObjects()` (`ObjectStackAdapter` lists code-
190
+ and DB-defined objects via `/api/v1/meta/object`), falling back to a
191
+ `sys_metadata` query. Stores the object's `name`.
192
+ - **`filter-condition`** — a visual criteria builder (`FilterBuilder`) scoped to
193
+ the fields of the object chosen in a sibling field (via `getObjectSchema`),
194
+ round-tripping the stored **MongoDB-style** FilterCondition JSON. Criteria the
195
+ builder can't represent (or invalid JSON) fall back to a raw-JSON editor, with
196
+ an always-available "Edit as JSON" toggle — nothing is hidden or lost.
197
+ - **`recipient-picker`** — a record picker whose target object follows a sibling
198
+ `recipient_type` (`user`→sys_user, `team`→sys_team, `business_unit`/
199
+ `unit_and_subordinates`→sys_business_unit, `position`→sys_position), storing the
200
+ value the evaluator matches on (a record id, or the position **name**). Resets
201
+ the stored id when the type changes.
202
+
203
+ Wiring: the three keys join `DATA_SOURCE_FIELD_TYPES` (form.tsx) so the form
204
+ threads `dataSource` + `dependentValues` to them, and `INLINE_EXCLUDED_FIELD_TYPES`
205
+ (they're authored in the record form, not a grid cell). `DataSource.getObjects()`
206
+ is optional on the interface; the ObjectStack adapter implements it.
207
+
208
+ ### Patch Changes
209
+
210
+ - a44e7b6: Form fields honor their object-schema `widget` render hint on the field-group /
211
+ section layout path. `ObjectForm` renders objects that declare field groups
212
+ (e.g. `sys_sharing_rule`) via an auto-derived section layout that passed each
213
+ field's metadata through without hoisting its `widget` override to the top-level
214
+ form-field config, so a field with `widget: 'object-ref'` (or `filter-condition`
215
+ / `recipient-picker`) degraded to its bare `type` input — an admin was asked to
216
+ hand-type an object name instead of picking it. The form renderer now falls back
217
+ to the field metadata's own `widget` when no top-level override is present, so
218
+ the pickers render on sectioned forms just as they do on flat ones.
219
+ - Updated dependencies [443360a]
220
+ - Updated dependencies [c70bca7]
221
+ - Updated dependencies [86c69c3]
222
+ - Updated dependencies [05e56ca]
223
+ - Updated dependencies [5971cc4]
224
+ - Updated dependencies [6a74160]
225
+ - @object-ui/core@14.0.0
226
+ - @object-ui/i18n@14.0.0
227
+ - @object-ui/react@14.0.0
228
+ - @object-ui/types@14.0.0
229
+ - @object-ui/react-runtime@14.0.0
230
+ - @object-ui/sdui-parser@14.0.0
231
+
3
232
  ## 13.2.0
4
233
 
5
234
  ### Patch Changes
package/dist/index.css CHANGED
@@ -2651,6 +2651,9 @@
2651
2651
  .\[-webkit-overflow-scrolling\:touch\] {
2652
2652
  -webkit-overflow-scrolling: touch;
2653
2653
  }
2654
+ .\[page\:header\] {
2655
+ page: header;
2656
+ }
2654
2657
  .duration-75 {
2655
2658
  animation-duration: 75ms;
2656
2659
  }