@object-ui/components 17.1.0 → 17.2.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 +295 -0
- package/dist/custom/field.d.ts +20 -2
- package/dist/custom/filter-builder.d.ts +20 -4
- package/dist/custom/sort-builder.d.ts +14 -3
- package/dist/index.css +3 -0
- package/dist/index.js +3065 -3044
- package/dist/index.umd.cjs +5 -5
- package/dist/share/ShareDialog.d.ts +23 -27
- package/package.json +11 -10
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,300 @@
|
|
|
1
1
|
# @object-ui/components
|
|
2
2
|
|
|
3
|
+
## 17.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 4ae0ac4: One placement rule for action `locations` (objectui#3142).
|
|
8
|
+
|
|
9
|
+
**Breaking for metadata**: an action that declares no `locations` (missing key
|
|
10
|
+
or `[]`) no longer renders in a located surface. FROM: omitting `locations`
|
|
11
|
+
made an action appear on the list toolbar, the record header, and every
|
|
12
|
+
metadata-admin toolbar. TO: declare where it belongs —
|
|
13
|
+
`locations: ['record_header']` for the record header, `['list_toolbar']` for
|
|
14
|
+
the list toolbar, and so on. Nothing else changes; actions that already
|
|
15
|
+
declare a location are untouched.
|
|
16
|
+
|
|
17
|
+
Four renderers each answered "where does an action with no `locations` go?"
|
|
18
|
+
differently — `action:bar` and metadata-admin showed it EVERYWHERE,
|
|
19
|
+
`page:header` showed it on the header, `action:group` showed it for
|
|
20
|
+
`undefined` but hid it for `[]` — while `ActionEngine`, `RecordDetailView`,
|
|
21
|
+
`DeclaredActionsBar`, the related-list bridge and the environment toolbar all
|
|
22
|
+
showed it NOWHERE. The same action therefore appeared or vanished depending on
|
|
23
|
+
which component happened to draw it. All eight now go through one exported
|
|
24
|
+
predicate, `actionRendersAt(action, location)` from `@object-ui/types`: an
|
|
25
|
+
action renders at a location only if it declares that location.
|
|
26
|
+
|
|
27
|
+
The strict reading is the platform's own — ADR-0078 lists "an `action` with no
|
|
28
|
+
`locations`" as a verified inert shape, and the detail-page synthesizer already
|
|
29
|
+
documented "must include `locations: ['record_header']` to render". The
|
|
30
|
+
leniency contradicted both, and it is what let an aggregate-only bulk action
|
|
31
|
+
(objectui#3139) — one with no single-record placement by construction — mint a
|
|
32
|
+
list-toolbar button whose dispatch could only fail.
|
|
33
|
+
|
|
34
|
+
Two placements are declared elsewhere and need no `locations`, both unchanged:
|
|
35
|
+
host-injected chrome in the `systemActions` / `headerSystemActions` slot (now
|
|
36
|
+
consistently exempt on `page:header` too, where it used to be filtered), and an
|
|
37
|
+
action named in a view's `bulkActions` / `bulkActionDefs`.
|
|
38
|
+
|
|
39
|
+
Authoring side: Studio seeds `locations: ['record_header']` on a new action
|
|
40
|
+
instead of minting one that renders nowhere, and the action inspector says so
|
|
41
|
+
when no placement is ticked. The `ActionSchema.locations` JSDoc claimed a
|
|
42
|
+
`['record_header']` default that no renderer ever implemented — corrected.
|
|
43
|
+
|
|
44
|
+
- 09d30a4: Stop declaring 18 `@object-ui/auth` / `@object-ui/components` / `@object-ui/react`
|
|
45
|
+
symbols under names `@objectstack/spec` owns (objectui#3159, objectstack#4115
|
|
46
|
+
batch 5).
|
|
47
|
+
|
|
48
|
+
**Breaking for importers of all three packages** — six exported names changed,
|
|
49
|
+
because the spec exports the same name for a _different_ thing:
|
|
50
|
+
|
|
51
|
+
| package | was | now | what the spec's same-named export actually is |
|
|
52
|
+
| :----------- | :--------------------------- | :----------------------- | :----------------------------------------------------------------------------- |
|
|
53
|
+
| `auth` | `AuthSession` | `AuthClientSession` | the SERVER's session record (`{ id, userId, expiresAt: ISO string, token? }`) |
|
|
54
|
+
| `auth` | `AuthProviderConfig` | `AuthProviderOptions` | an OAuth/OIDC provider registration (`{ id, clientId, clientSecret, scope? }`) |
|
|
55
|
+
| `components` | `FilterCondition` | `FilterBuilderCondition` | the recursive ObjectQL predicate AST (`$and`/`$or`/`$not`) |
|
|
56
|
+
| `components` | `Field` | `FieldContainer` | an object FIELD's metadata and its builder namespace |
|
|
57
|
+
| `react` | `ConflictResolutionStrategy` | `ConflictResolution` | the metadata-MERGE policy (`error \| priority \| first-wins \| last-wins`) |
|
|
58
|
+
|
|
59
|
+
The `react` rename is the odd one out: the new name is the **spec's own** name
|
|
60
|
+
for the union that hook always used, so it is a re-export rather than a dialect.
|
|
61
|
+
|
|
62
|
+
Eleven more keep their names and are now **imported or derived from the spec**
|
|
63
|
+
instead of re-declared: `TenancyPosture`, `DelegableScope` (+`DelegableAdminScope`),
|
|
64
|
+
`AuthUser`, `ShareLinkPermission`, `ShareLinkAudience`, `ShareLink`, `SortItem`,
|
|
65
|
+
`OfflineStrategy`, `OfflineCacheConfig`, `OfflineSyncConfig`, `OfflineConfig`,
|
|
66
|
+
`NavigationConfig`.
|
|
67
|
+
|
|
68
|
+
**Three of the copies were losing information, not just duplicating it.**
|
|
69
|
+
|
|
70
|
+
- `AuthUser` never declared the spec's `positions` or `tenantId` — the
|
|
71
|
+
authorization inputs. Its `[key: string]: unknown` index signature meant the
|
|
72
|
+
omission was invisible at every call site _and_ to any structural comparison
|
|
73
|
+
(the objectstack#4075 mechanism). It now `extends` the spec principal, so the
|
|
74
|
+
display-only fields (`image`, `role`, `roles`, `emailVerified`) are the delta
|
|
75
|
+
and the spec's keys arrive on their own.
|
|
76
|
+
- `useNavigationOverlay`'s copy carried the note _"inline … to avoid importing
|
|
77
|
+
from `@object-ui/types` (which may not be a direct dependency of
|
|
78
|
+
`@object-ui/react`)"_. The vocabulary belongs to `@objectstack/spec`, which
|
|
79
|
+
**is** a direct dependency — the same expired "kept local to avoid a
|
|
80
|
+
dependency" comment objectui#3169 found in `@object-ui/app-shell`.
|
|
81
|
+
- `useOffline` and `usePerformance` both opened with _"Types aligned with
|
|
82
|
+
`@objectstack/spec` v2.0.7"_. The installed spec is 17.0.0-rc.1.
|
|
83
|
+
|
|
84
|
+
`ShareLink` derives from the spec row **minus `password_hash`** — omitted rather
|
|
85
|
+
than optional, because it is the credential itself and typing it in a browser
|
|
86
|
+
package is an invitation to render it. `password_protected` (the boolean the UI
|
|
87
|
+
needs in its place) is the one local addition.
|
|
88
|
+
|
|
89
|
+
The config types derive from each schema's **input** side, not `z.infer`.
|
|
90
|
+
`useOffline(config: OfflineConfig = {})` defaults to the empty object, which the
|
|
91
|
+
output type — every `.default()`ed key required — would reject outright.
|
|
92
|
+
|
|
93
|
+
`@objectstack/spec` moves from `devDependencies` to `dependencies` in
|
|
94
|
+
`@object-ui/components`: its public type surface now references the spec.
|
|
95
|
+
|
|
96
|
+
Scored `minor`, not `major`, per this repo's fixed-group rule — objectui's major
|
|
97
|
+
tracks `@objectstack`, so breaking changes of our own ship as minor with the
|
|
98
|
+
semantics spelled out above (see AGENTS.md §版本号策略). A `major` here would carry
|
|
99
|
+
all 39 packages of the fixed group to `18.0.0` and off objectstack's 17.x line.
|
|
100
|
+
|
|
101
|
+
- 726b89c: `@object-ui/types` stops declaring sixteen symbols under names `@objectstack/spec` owns (objectui#3156, objectstack#4115).
|
|
102
|
+
|
|
103
|
+
Seven are now **derived** from the spec, nine are **renamed** to the local
|
|
104
|
+
dialect they always were. Both halves remove the same hazard: a local
|
|
105
|
+
declaration under a spec export's name reads as the spec's own definition to
|
|
106
|
+
the next reader, so a copy that is merely _correct today_ is a planted premise
|
|
107
|
+
tomorrow.
|
|
108
|
+
|
|
109
|
+
**Derived** — the spec now supplies the keys, by reference:
|
|
110
|
+
|
|
111
|
+
| symbol | derivation |
|
|
112
|
+
| :----------------------- | :-------------------------------------------------------------------------------- |
|
|
113
|
+
| `ActionParam` | `z.input<typeof ActionParamSchema>`, `type` widened to the local legacy spellings |
|
|
114
|
+
| `CreateExportJobRequest` | `Omit<CreateExportJobInput, 'object'>` (`object` is the method argument) |
|
|
115
|
+
| `CreateExportJobResult` | re-export from `@objectstack/spec/contracts` |
|
|
116
|
+
| `ImportRowResult` | re-export from `@objectstack/spec/api` |
|
|
117
|
+
| `NavigationArea` | spec keys, with `navigation` / `visible` pinned locally |
|
|
118
|
+
| `NavigationAreaSchema` | `specFieldsExcept(NavigationAreaSchema.shape, …)` |
|
|
119
|
+
| `Theme` | re-export of the spec's `ThemeInput` (the authoring shape) |
|
|
120
|
+
| `ExportJobFormat` | re-export of the spec's `ExportFormat` |
|
|
121
|
+
|
|
122
|
+
Four of these close real gaps rather than tidy names. `ActionParam` never
|
|
123
|
+
declared `reference` — the key `resolveActionParams()` actually reads for an
|
|
124
|
+
inline lookup target — nor `defaultFromRow`, which the metadata designer's own
|
|
125
|
+
inspector writes; it also narrowed `visible` to a bare string although the
|
|
126
|
+
resolver has always accepted the `{ dialect, source }` envelope too.
|
|
127
|
+
`CreateExportJobResult.createdAt` and `ImportRowResult.action` were optional
|
|
128
|
+
here and required by the server, leaving every consumer a branch that could
|
|
129
|
+
never run. And `NavigationArea`'s `id` now carries the spec's own length rule
|
|
130
|
+
instead of accepting any string.
|
|
131
|
+
|
|
132
|
+
**Renamed** — same word, different concept:
|
|
133
|
+
|
|
134
|
+
| was | now | why |
|
|
135
|
+
| :----------------- | :----------------------- | :----------------------------------------------------------------------------------------------------------------------------- |
|
|
136
|
+
| `FileMetadata` | `UploadedFileMetadata` | field-VALUE payload (`url`, `original_name`), not the storage file record |
|
|
137
|
+
| `GestureType` | `TouchGestureType` | direction-fused (`swipe-left`), not the spec's type+direction pair |
|
|
138
|
+
| `GestureConfig` | `TouchGestureConfig` | gesture→`action` binding, not per-gesture tuning |
|
|
139
|
+
| `OfflineConfig` | `PWAOfflineConfig` | service-worker route caching, not the offline data/sync model |
|
|
140
|
+
| `PageRegion` | `PageNodeRegion` | region of the renderer page NODE, holding `SchemaNode`s |
|
|
141
|
+
| `PageRegionSchema` | `PageNodeRegionSchema` | zod twin of the above |
|
|
142
|
+
| `ResponsiveConfig` | `MobileResponsiveConfig` | mobile box config, not the spec's SDUI grid contract |
|
|
143
|
+
| `WidgetManifest` | `RuntimeWidgetManifest` | SDUI component manifest, not the field-widget plugin manifest |
|
|
144
|
+
| `WidgetSource` | `RuntimeWidgetSource` | `module`/`inline`/`registry` loader union — and its `inline` carries a resolved component where the spec's carries source code |
|
|
145
|
+
|
|
146
|
+
**Migration**: the old names are gone, not deprecated — an alias would preserve
|
|
147
|
+
exactly the ambiguity being removed. Import the new name; nothing about the
|
|
148
|
+
shapes changed. `@object-ui/types` already re-exports the spec's own
|
|
149
|
+
`SpecResponsiveConfig`, and `@object-ui/react`'s `useOffline` config remains the
|
|
150
|
+
spec-shaped `OfflineConfig`, so both concepts stay reachable under
|
|
151
|
+
distinguishable names.
|
|
152
|
+
|
|
153
|
+
Each rename carries a bidirectional tripwire
|
|
154
|
+
(`packages/types/src/__tests__/page-nav-misc-spec-parity.test.ts`): it fails if
|
|
155
|
+
the spec ever claims the new name, and also if the spec retires the old one —
|
|
156
|
+
at which point the natural name can be taken back rather than the workaround
|
|
157
|
+
outliving its reason.
|
|
158
|
+
|
|
159
|
+
### Patch Changes
|
|
160
|
+
|
|
161
|
+
- cb82705: A standalone grid's search box searches the list, not the page you can see (objectui#3118).
|
|
162
|
+
|
|
163
|
+
Under server-side pagination a standalone `ObjectGrid` rendered `data-table`'s
|
|
164
|
+
built-in search box, and that box filtered the rows the table was holding —
|
|
165
|
+
which is one page. The user read "2 results for X in this list" while 3075 rows
|
|
166
|
+
never participated, with the pager beside it still reading `1 / 63`. Every piece
|
|
167
|
+
was individually correct: `searchable` defaults to true, `manualPagination` is
|
|
168
|
+
true, and the two are declared next to each other in the same object literal.
|
|
169
|
+
|
|
170
|
+
This is objectui#3106 one axis over — sort there, filter here — and it takes the
|
|
171
|
+
same shape. `DataTable` gains `manualSearch` + a controlled `search` +
|
|
172
|
+
`onSearchChange`. In that mode it filters nothing, reports the typed term, and
|
|
173
|
+
renders `search` as the box's value, holding **no** term of its own: a private
|
|
174
|
+
copy beside a controlled prop is the shape the defect had. `ObjectGrid` turns
|
|
175
|
+
that term into a `$search` on the refetch — the server picks the matching fields
|
|
176
|
+
from the object's metadata (ADR-0061), the same channel the ListView toolbar has
|
|
177
|
+
always used — and returns to page 1, since a new term makes the old page index a
|
|
178
|
+
different set of rows (usually no rows at all). `$searchFields` rides along only
|
|
179
|
+
when the view declared `searchableFields`, which can narrow the server-resolved
|
|
180
|
+
set and never widen it.
|
|
181
|
+
|
|
182
|
+
Two things worth naming:
|
|
183
|
+
|
|
184
|
+
- Both paths are never live at once. The server's answer is the answer; a client
|
|
185
|
+
pass left running underneath would silently re-narrow it to whichever returned
|
|
186
|
+
rows happen to contain the term as _rendered text_, overruling the server's
|
|
187
|
+
own notion of which fields are searchable.
|
|
188
|
+
- Under `manualSearch` a table with no `onSearchChange` renders **no** search
|
|
189
|
+
box. The sort axis could degrade to inert headers; here there is no honest
|
|
190
|
+
local behaviour to fall back to, because the rows to search are not in the
|
|
191
|
+
browser.
|
|
192
|
+
|
|
193
|
+
Client-paginated grids are untouched: inline, bound and grouped grids hold every
|
|
194
|
+
row they display, so their box keeps filtering in memory, where the count it
|
|
195
|
+
produces is true. The ListView path was never affected — it passes
|
|
196
|
+
`showSearch: false` and searches from its own toolbar.
|
|
197
|
+
|
|
198
|
+
- f6e8d78: Lookup search inside a create/edit modal is typeable again (objectui#3183).
|
|
199
|
+
|
|
200
|
+
In every production console build, the search input of a lookup field's
|
|
201
|
+
quick-select popover — and the nested Record Picker dialog — could not take
|
|
202
|
+
focus while the form modal was open: every click/focus was synchronously
|
|
203
|
+
yanked back to the field trigger, so a lookup could not be searched while
|
|
204
|
+
creating a record.
|
|
205
|
+
|
|
206
|
+
Root cause is a race in stock `@radix-ui/react-focus-scope@1.1.16`: the
|
|
207
|
+
focus-scopes stack effect's cleanup schedules `focusScopesStack.remove(scope)`
|
|
208
|
+
in a `setTimeout(0)`. When the effect re-runs for a still-mounted scope (a
|
|
209
|
+
`container` ref flicker), the re-run re-`add`s the scope and the stale timeout
|
|
210
|
+
then evicts it — the dialog's trap listeners stay active but its scope is no
|
|
211
|
+
longer in the stack, so an opening popover pauses nothing and the trap yanks
|
|
212
|
+
focus out of the popover forever.
|
|
213
|
+
|
|
214
|
+
Fixed via `patches/@radix-ui__react-focus-scope.patch`: an effect re-run for a
|
|
215
|
+
live scope cancels the pending eviction; a real unmount still runs the full
|
|
216
|
+
delayed cleanup (autofocus-on-unmount + stack removal). Regression-tested in
|
|
217
|
+
`packages/components` with a deterministic reproduction of the race.
|
|
218
|
+
|
|
219
|
+
- a8ad6c0: A required boolean must be savable in its UNCHECKED state — `false` and `0` are values.
|
|
220
|
+
|
|
221
|
+
Reported against an AI-built task tracker whose 任务 object has a required
|
|
222
|
+
`是否完成` boolean: the create form showed the switch OFF, answered "是否完成不能
|
|
223
|
+
为空", and saved instantly once the switch was turned ON. The app could only ever
|
|
224
|
+
create ALREADY-DONE tasks — the one state the control shows by default was the
|
|
225
|
+
one value it refused to save (cloud#972).
|
|
226
|
+
|
|
227
|
+
Two defects stacked, and either alone is enough to break it:
|
|
228
|
+
|
|
229
|
+
**The `required` verdict read truthiness, not presence.** `@objectstack/spec`
|
|
230
|
+
FieldSchema.required (ADR-0113) is "an insert must provide a NON-NULL value",
|
|
231
|
+
and objectql's record validator implements exactly that. react-hook-form's
|
|
232
|
+
built-in rule instead fails whenever `isBoolean(value) && !value` — its
|
|
233
|
+
accept-the-terms checkbox heritage — silently redefining every required boolean
|
|
234
|
+
as "must be TRUE", including a select whose chosen option value is `false`. It
|
|
235
|
+
also disagreed the other way, letting a whitespace-only string through for the
|
|
236
|
+
server to reject with a 400. The form renderer no longer hands RHF its own
|
|
237
|
+
`required`: the check is now a `validate` entry keyed `required` (so the error
|
|
238
|
+
still surfaces as `type: 'required'`, which the conditional-required cleanup
|
|
239
|
+
keys on) backed by a new shared `isMissingForRequired` in `@object-ui/core`, a
|
|
240
|
+
deliberate mirror of objectql `record-validator.isMissing` — `undefined`,
|
|
241
|
+
`null`, blank-after-trim string, empty array. Deleting the inherited rule also
|
|
242
|
+
stops a `required` that rode in on `validation` from outliving a `requiredWhen`
|
|
243
|
+
that resolved to FALSE.
|
|
244
|
+
|
|
245
|
+
**A boolean field held `undefined` while displaying "off".** A two-state control
|
|
246
|
+
has no third state, but a field with no entry in `defaultValues` rendered an OFF
|
|
247
|
+
switch backed by nothing: the create payload omitted the column (it lands null,
|
|
248
|
+
which reads as unchecked but isn't) and the presence check above would still
|
|
249
|
+
refuse it. The form renderer now folds `false` into `defaultValues` for every
|
|
250
|
+
boolean-widget field the caller left unset — in `defaultValues` itself, not
|
|
251
|
+
per-Controller, because that object is also the dirty-check baseline and what
|
|
252
|
+
the defaults-reset window replays. Every surface gets it, including the
|
|
253
|
+
modal/drawer create dialogs that start from a bare `{}`. An authored default
|
|
254
|
+
(or a loaded record, `null` included) still wins.
|
|
255
|
+
|
|
256
|
+
`WizardForm`'s cross-step gate had its own copy of the empty-value predicate; it
|
|
257
|
+
now imports the shared one so it cannot drift from the per-field verdict. And
|
|
258
|
+
the field-demo renderer read `schema.defaultValue || schema.value`, throwing
|
|
259
|
+
away an authored default of `false` / `0` / `''` — same falsy-as-empty class,
|
|
260
|
+
now `??`.
|
|
261
|
+
|
|
262
|
+
Verified end to end on a local stack against the exact metadata shape
|
|
263
|
+
`apply_blueprint` materializes (`{ type: 'boolean', required: true }`, no
|
|
264
|
+
default): a 是否完成 = 否 task with 工时 = 0 now creates and persists as
|
|
265
|
+
`{ hours: 0, is_done: false }`, turning the switch on still stores `true`, and a
|
|
266
|
+
blank required text is still refused.
|
|
267
|
+
|
|
268
|
+
- Updated dependencies [4ae0ac4]
|
|
269
|
+
- Updated dependencies [696e3c1]
|
|
270
|
+
- Updated dependencies [bca45cc]
|
|
271
|
+
- Updated dependencies [a889e31]
|
|
272
|
+
- Updated dependencies [09d30a4]
|
|
273
|
+
- Updated dependencies [4bf612c]
|
|
274
|
+
- Updated dependencies [335041c]
|
|
275
|
+
- Updated dependencies [b414983]
|
|
276
|
+
- Updated dependencies [256f8cc]
|
|
277
|
+
- Updated dependencies [d9668a7]
|
|
278
|
+
- Updated dependencies [4b470b9]
|
|
279
|
+
- Updated dependencies [cb82705]
|
|
280
|
+
- Updated dependencies [f572849]
|
|
281
|
+
- Updated dependencies [4a51e77]
|
|
282
|
+
- Updated dependencies [ea96284]
|
|
283
|
+
- Updated dependencies [d3584c6]
|
|
284
|
+
- Updated dependencies [cc70b8f]
|
|
285
|
+
- Updated dependencies [a8ad6c0]
|
|
286
|
+
- Updated dependencies [444457c]
|
|
287
|
+
- Updated dependencies [850033c]
|
|
288
|
+
- Updated dependencies [022e4c3]
|
|
289
|
+
- Updated dependencies [009e25d]
|
|
290
|
+
- Updated dependencies [726b89c]
|
|
291
|
+
- @object-ui/types@17.2.0
|
|
292
|
+
- @object-ui/core@17.2.0
|
|
293
|
+
- @object-ui/react@17.2.0
|
|
294
|
+
- @object-ui/i18n@17.2.0
|
|
295
|
+
- @object-ui/sdui-parser@17.2.0
|
|
296
|
+
- @object-ui/react-runtime@17.2.0
|
|
297
|
+
|
|
3
298
|
## 17.1.0
|
|
4
299
|
|
|
5
300
|
### Minor Changes
|
package/dist/custom/field.d.ts
CHANGED
|
@@ -8,6 +8,12 @@ import { VariantProps } from 'class-variance-authority';
|
|
|
8
8
|
*/
|
|
9
9
|
import * as React from "react";
|
|
10
10
|
declare const fieldVariants: (props?: import('class-variance-authority/types').ClassProp | undefined) => string;
|
|
11
|
+
/**
|
|
12
|
+
* Props for {@link FieldContainer}.
|
|
13
|
+
*
|
|
14
|
+
* Note this one keeps its natural name: the spec does not export `FieldProps`.
|
|
15
|
+
* Only the component itself had to move — see the note on `FieldContainer`.
|
|
16
|
+
*/
|
|
11
17
|
export interface FieldProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof fieldVariants> {
|
|
12
18
|
label?: React.ReactNode;
|
|
13
19
|
description?: React.ReactNode;
|
|
@@ -15,5 +21,17 @@ export interface FieldProps extends React.HTMLAttributes<HTMLDivElement>, Varian
|
|
|
15
21
|
required?: boolean;
|
|
16
22
|
htmlFor?: string;
|
|
17
23
|
}
|
|
18
|
-
|
|
19
|
-
|
|
24
|
+
/**
|
|
25
|
+
* A labelled form-control wrapper: label, slotted control, description, error.
|
|
26
|
+
*
|
|
27
|
+
* Named `FieldContainer`, not `Field` (objectstack#4115): `@objectstack/spec/data`
|
|
28
|
+
* exports `Field` — an object FIELD's metadata (type, reference_to, options,
|
|
29
|
+
* permissions, …) and its builder namespace — which has nothing to do with this
|
|
30
|
+
* `<div>`. Two unrelated things under one name is the defect that issue exists
|
|
31
|
+
* to remove; `@object-ui/app-shell` already renamed the same kind of collision
|
|
32
|
+
* (`FieldInput` → `ScreenFieldInput`, objectui#3169) for the same reason.
|
|
33
|
+
* `__tests__/share-filter-sort-spec-parity.test.ts` pins that the spec does not
|
|
34
|
+
* own the new name.
|
|
35
|
+
*/
|
|
36
|
+
declare const FieldContainer: React.ForwardRefExoticComponent<FieldProps & React.RefAttributes<HTMLDivElement>>;
|
|
37
|
+
export { FieldContainer };
|
|
@@ -6,7 +6,23 @@
|
|
|
6
6
|
* LICENSE file in the root directory of this source tree.
|
|
7
7
|
*/
|
|
8
8
|
import * as React from "react";
|
|
9
|
-
|
|
9
|
+
/**
|
|
10
|
+
* One row of the FilterBuilder UI.
|
|
11
|
+
*
|
|
12
|
+
* Deliberately NOT `FilterCondition` (objectstack#4115): the spec owns that
|
|
13
|
+
* name for the RECURSIVE ObjectQL predicate AST — `{ [field]: FieldOperators }`
|
|
14
|
+
* with `$and` / `$or` / `$not` branches — which is a query, not a row. This is
|
|
15
|
+
* one flat `{ field, operator, value }` line plus the React key the list needs,
|
|
16
|
+
* and `operator` here is the builder's own dropdown vocabulary
|
|
17
|
+
* (`FILTER_BUILDER_OPERATORS`), not the spec's `$`-tokens.
|
|
18
|
+
*
|
|
19
|
+
* `@object-ui/types` already renamed its identical concept to
|
|
20
|
+
* `FilterBuilderCondition` (objectui#3068); this is the same thing, so it takes
|
|
21
|
+
* the same name rather than inventing a second dialect. Note the same name is
|
|
22
|
+
* NOT the right answer everywhere: `@object-ui/app-shell`'s `FilterCondition`
|
|
23
|
+
* really was the spec's ObjectQL AST and was re-exported (objectui#3169).
|
|
24
|
+
*/
|
|
25
|
+
export interface FilterBuilderCondition {
|
|
10
26
|
id: string;
|
|
11
27
|
field: string;
|
|
12
28
|
operator: string;
|
|
@@ -15,7 +31,7 @@ export interface FilterCondition {
|
|
|
15
31
|
export interface FilterGroup {
|
|
16
32
|
id: string;
|
|
17
33
|
logic: "and" | "or";
|
|
18
|
-
conditions:
|
|
34
|
+
conditions: FilterBuilderCondition[];
|
|
19
35
|
}
|
|
20
36
|
export interface FilterBuilderProps {
|
|
21
37
|
fields?: Array<{
|
|
@@ -129,9 +145,9 @@ interface LookupValuePickerProps {
|
|
|
129
145
|
displayField?: string;
|
|
130
146
|
idField?: string;
|
|
131
147
|
};
|
|
132
|
-
value:
|
|
148
|
+
value: FilterBuilderCondition["value"];
|
|
133
149
|
multiple: boolean;
|
|
134
|
-
onChange: (value:
|
|
150
|
+
onChange: (value: FilterBuilderCondition["value"]) => void;
|
|
135
151
|
}
|
|
136
152
|
declare function LookupValuePicker({ field, value, multiple, onChange }: LookupValuePickerProps): React.JSX.Element;
|
|
137
153
|
export { FilterBuilder, LookupValuePicker };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SortItem as SpecSortItem } from '@objectstack/spec/shared';
|
|
1
2
|
/**
|
|
2
3
|
* ObjectUI
|
|
3
4
|
* Copyright (c) 2024-present ObjectStack Inc.
|
|
@@ -6,10 +7,20 @@
|
|
|
6
7
|
* LICENSE file in the root directory of this source tree.
|
|
7
8
|
*/
|
|
8
9
|
import * as React from "react";
|
|
9
|
-
|
|
10
|
+
/**
|
|
11
|
+
* One row of the SortBuilder UI: the spec's `SortItem` (`{ field, order }`)
|
|
12
|
+
* plus the React key this list needs.
|
|
13
|
+
*
|
|
14
|
+
* Derived rather than re-declared (objectstack#4115). The old hand copy agreed
|
|
15
|
+
* with the spec key-for-key, which is the state one spec release away from
|
|
16
|
+
* drifting — a new sort key (`nulls`, say) would have appeared in the spec and
|
|
17
|
+
* silently gone missing here. `id` is the ONE local addition and it is
|
|
18
|
+
* synthetic: `normalize()` mints it, and `SortBuilder`'s change comparison
|
|
19
|
+
* strips it before diffing precisely because it is not part of the contract.
|
|
20
|
+
*/
|
|
21
|
+
export interface SortItem extends SpecSortItem {
|
|
22
|
+
/** React key for the row. Synthetic — never part of the emitted sort. */
|
|
10
23
|
id: string;
|
|
11
|
-
field: string;
|
|
12
|
-
order: 'asc' | 'desc';
|
|
13
24
|
}
|
|
14
25
|
export interface SortBuilderProps {
|
|
15
26
|
fields?: Array<{
|