@object-ui/fields 17.7.0 → 18.0.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 +792 -0
- package/README.md +146 -4
- package/dist/fieldHelpText.d.ts +41 -0
- package/dist/index.cjs +4 -4
- package/dist/index.css +42 -3
- package/dist/index.d.ts +219 -14
- package/dist/index.js +4090 -3009
- package/dist/resolveActionParams.d.ts +259 -0
- package/dist/widgets/FormulaField.d.ts +41 -0
- package/dist/widgets/GridField.d.ts +12 -4
- package/dist/widgets/RecipientPickerField.d.ts +32 -0
- package/dist/widgets/RegistryRefField.d.ts +77 -0
- package/dist/widgets/SummaryField.d.ts +30 -0
- package/dist/widgets/booleanValueLabel.d.ts +18 -0
- package/dist/widgets/date-picker/DatePickerField.d.ts +40 -0
- package/dist/widgets/date-picker/localeDateText.d.ts +39 -0
- package/dist/widgets/deriveLookupColumns.d.ts +1 -1
- package/dist/widgets/file-affordance.d.ts +30 -0
- package/dist/widgets/file-refused.d.ts +17 -0
- package/dist/widgets/file-value.d.ts +11 -0
- package/dist/widgets/longTextCarrierHandoff.d.ts +35 -0
- package/dist/widgets/lookupColumnDisplay.d.ts +2 -2
- package/dist/widgets/objectRefLabel.d.ts +16 -0
- package/dist/widgets/recipientKinds.d.ts +85 -0
- package/dist/widgets/richTextDisplay.d.ts +0 -17
- package/dist/widgets/searchOffer.d.ts +8 -0
- package/dist/widgets/toDomProps.d.ts +16 -3
- package/dist/widgets/useRecordQuery.d.ts +13 -0
- package/package.json +9 -9
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import { ActionParamDef, ActionParamOption } from '@object-ui/core';
|
|
2
|
+
import { I18nLabel } from '@objectstack/spec/ui';
|
|
3
|
+
/**
|
|
4
|
+
* Resolve a param `type` to the form widget key that renders it — the fold from
|
|
5
|
+
* a PARAM type spelling to its widget, the one alias table, read rather than
|
|
6
|
+
* restated (see `isLookupResolvedType` below, and app-shell's `paramToField`,
|
|
7
|
+
* which asks the same question one step later). Any type in `FORM_FIELD_TYPES`
|
|
8
|
+
* resolves to itself (identity — asserted by app-shell's drift test); aliases
|
|
9
|
+
* and unknown types resolve through the same fallback chain the form applies
|
|
10
|
+
* (unknown → `text`).
|
|
11
|
+
*/
|
|
12
|
+
export declare function resolveParamWidgetType(paramType: string): string;
|
|
13
|
+
/**
|
|
14
|
+
* Resolved params keep raw `FieldType` values (`text` / `email` / `select` /
|
|
15
|
+
* `file` / …), matching the `FieldType` enum in `@objectstack/spec`. **Do
|
|
16
|
+
* not** translate into the FormField widget vocabulary (`field:select`, …)
|
|
17
|
+
* here — `ActionParamDialog` owns that translation via its `paramToField()`
|
|
18
|
+
* adapter (ADR-0059).
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* One option as AUTHORED on an action param — {@link ActionParamOption} with
|
|
22
|
+
* the label on the authoring side of rc.6's `I18nLabel` widening.
|
|
23
|
+
*
|
|
24
|
+
* The distinction is the whole point of the authored/resolved split: an author
|
|
25
|
+
* may write `{ value: 'high', label: { en: 'High', 'zh-CN': '高' } }`, and
|
|
26
|
+
* `ActionParamDialog` reads `ActionParamOption.label` as a plain `string`. Left
|
|
27
|
+
* un-narrowed, the map would ride an INLINE option list straight through to the
|
|
28
|
+
* select widget (inline options pass through verbatim — see `resolvedOptions`),
|
|
29
|
+
* and render as `[object Object]` with no diagnostic anywhere. So the two types
|
|
30
|
+
* are kept apart and {@link resolveOptionLabels} is the one crossing point.
|
|
31
|
+
*
|
|
32
|
+
* Spelled out rather than `Omit<ActionParamOption, 'label'> & { … }`: `Omit`
|
|
33
|
+
* over a type carrying `[key: string]: unknown` resolves `Exclude<keyof T,
|
|
34
|
+
* 'label'>` back to `string | number`, so it drops `value`'s type AND keeps
|
|
35
|
+
* `label` as `unknown` — the derivation silently erases exactly the two keys it
|
|
36
|
+
* is supposed to be about.
|
|
37
|
+
*/
|
|
38
|
+
export type RawActionParamOption = {
|
|
39
|
+
/** Authored label — a plain string, or rc.6's inline per-locale map. */
|
|
40
|
+
label?: I18nLabel;
|
|
41
|
+
value: string;
|
|
42
|
+
/**
|
|
43
|
+
* Everything else an option declares (`visibleWhen` / `color` / `icon` /
|
|
44
|
+
* `disabled`), preserved verbatim — `fbc23e094`.
|
|
45
|
+
*/
|
|
46
|
+
[key: string]: unknown;
|
|
47
|
+
};
|
|
48
|
+
/** Raw param as authored on a schema action (post-zod). */
|
|
49
|
+
export interface RawActionParam {
|
|
50
|
+
name?: string;
|
|
51
|
+
field?: string;
|
|
52
|
+
objectOverride?: string;
|
|
53
|
+
/**
|
|
54
|
+
* Display label, as authored. `@objectstack/spec` 17.0.0-rc.6 widened
|
|
55
|
+
* `I18nLabel` from `string` to `string | Record<string, string>`, so an
|
|
56
|
+
* author may inline a per-locale map here
|
|
57
|
+
* (`label: { en: 'Reason', 'zh-CN': '原因' }`) — the same widening the spec's
|
|
58
|
+
* `ActionParamSchema.label` carries.
|
|
59
|
+
*
|
|
60
|
+
* This restatement is the load-bearing half (objectui#3174): when it drifts
|
|
61
|
+
* from what `@object-ui/types`' `ActionParam` says an author may write, this
|
|
62
|
+
* resolver stops accepting the public authoring type. That drift is exactly
|
|
63
|
+
* what a widened `I18nLabel` produced, and it is why the fix belongs on this
|
|
64
|
+
* DECLARATION rather than on the test that surfaced it.
|
|
65
|
+
*
|
|
66
|
+
* `resolveActionParams` emits `ActionParamDef.label`, which is a plain
|
|
67
|
+
* `string` — so the map is resolved on the way out (see {@link
|
|
68
|
+
* ResolveActionParamsContext.locale}), never forwarded.
|
|
69
|
+
*/
|
|
70
|
+
label?: I18nLabel;
|
|
71
|
+
type?: string;
|
|
72
|
+
required?: boolean;
|
|
73
|
+
/**
|
|
74
|
+
* Option list authored inline on the param. Speaks the same vocabulary as the
|
|
75
|
+
* resolved side ({@link ActionParamOption}): the two keys this resolver reads
|
|
76
|
+
* plus a catch-all for whatever else an option declares (`visibleWhen`,
|
|
77
|
+
* `color`, `icon`, `disabled`) — `fbc23e094`.
|
|
78
|
+
*
|
|
79
|
+
* One key differs, and it is the same rc.6 widening as {@link
|
|
80
|
+
* RawActionParam.label} one level down: an option's `label` is authored as
|
|
81
|
+
* `I18nLabel` and RESOLVED to a `string` before it reaches
|
|
82
|
+
* `ActionParamOption`. See {@link RawActionParamOption}.
|
|
83
|
+
*/
|
|
84
|
+
options?: RawActionParamOption[];
|
|
85
|
+
placeholder?: string;
|
|
86
|
+
helpText?: string;
|
|
87
|
+
defaultValue?: unknown;
|
|
88
|
+
/** When true, seed defaultValue from the row record using the field name. */
|
|
89
|
+
defaultFromRow?: boolean;
|
|
90
|
+
/**
|
|
91
|
+
* Carry-over declaration — the spec's `ActionParamSchema.carryOver`
|
|
92
|
+
* (objectui#6246): seeded from the row, rendered read-only, submitted
|
|
93
|
+
* verbatim. Copied onto `ActionParamDef.carryOver` unchanged on every branch
|
|
94
|
+
* below; `ActionParamDialog` is what honours it.
|
|
95
|
+
*/
|
|
96
|
+
carryOver?: boolean;
|
|
97
|
+
/** Allow multiple values (file/image/lookup/user params → array value). */
|
|
98
|
+
multiple?: boolean;
|
|
99
|
+
/** Accepted upload types (MIME types / extensions) for `file`/`image` params. */
|
|
100
|
+
accept?: string[];
|
|
101
|
+
/** Max upload size in bytes for `file`/`image` params. */
|
|
102
|
+
maxSize?: number;
|
|
103
|
+
/**
|
|
104
|
+
* Reference target for an INLINE `lookup`/`master_detail` param (objectstack-ai/objectstack#3405) —
|
|
105
|
+
* the object whose records the picker searches. Field-backed params inherit
|
|
106
|
+
* it from the referenced field instead (see `lookupExtras` below). Spelled
|
|
107
|
+
* `reference` to match `FieldSchema.reference` / `ActionParamSchema.reference`.
|
|
108
|
+
*/
|
|
109
|
+
reference?: string;
|
|
110
|
+
/**
|
|
111
|
+
* Visibility predicate (CEL) — mirrors the spec `ActionParamSchema.visible`.
|
|
112
|
+
* The server serialises it through `ExpressionInputSchema` as an
|
|
113
|
+
* `{ dialect, source }` envelope, so accept both the raw string and the
|
|
114
|
+
* envelope. Propagated to `ActionParamDef.visible` so `ActionParamDialog`
|
|
115
|
+
* can gate the param (e.g. hide `phoneNumber` unless `features.phoneNumber`).
|
|
116
|
+
* Absent = always visible.
|
|
117
|
+
*/
|
|
118
|
+
visible?: string | {
|
|
119
|
+
dialect?: string;
|
|
120
|
+
source?: string;
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Keys of the RESOLVED `ActionParamDef` that are not authorable on a raw param,
|
|
125
|
+
* mapped to the prescription an author needs (objectui#3174).
|
|
126
|
+
*
|
|
127
|
+
* They are deliberately ABSENT from `RawActionParam` above rather than declared
|
|
128
|
+
* and ignored: the whole defect this table exists for is that
|
|
129
|
+
* `@object-ui/types`' public `ActionParam` declared them "for parity with the
|
|
130
|
+
* resolved shape", so `{ name: 'account_id', type: 'lookup', referenceTo:
|
|
131
|
+
* 'account' }` type-checked, lost its picker target here, and rendered as a
|
|
132
|
+
* plain record-id text box. `ActionParamSchema` in `@objectstack/spec` is
|
|
133
|
+
* `.strict()` and rejects every one of them at parse time — `referenceTo` by
|
|
134
|
+
* name, with `reference` as the suggestion — so resolving them here would make
|
|
135
|
+
* objectui accept metadata the platform itself refuses to store. That is a
|
|
136
|
+
* second de-facto contract, not a kindness (AGENTS.md "contract-first"): such a
|
|
137
|
+
* param would work in a locally-authored TS action and fail at publish.
|
|
138
|
+
*
|
|
139
|
+
* So the disposition is: recognise, name, and refuse — never silently drop, and
|
|
140
|
+
* never quietly honour.
|
|
141
|
+
*/
|
|
142
|
+
export declare const RESOLVED_ONLY_PARAM_KEYS: Readonly<Record<string, string>>;
|
|
143
|
+
/** Field metadata as exposed by `useMetadata().objects[].fields`. */
|
|
144
|
+
interface RuntimeField {
|
|
145
|
+
type?: string;
|
|
146
|
+
label?: string;
|
|
147
|
+
required?: boolean;
|
|
148
|
+
placeholder?: string;
|
|
149
|
+
/**
|
|
150
|
+
* `@objectstack/spec`'s `FieldSchema.inlineHelpText`, the help line drawn
|
|
151
|
+
* under the field's control (objectui#12213). Read first for a field-backed
|
|
152
|
+
* param's `helpText`, through `fieldHelpText`, the read the record form
|
|
153
|
+
* shares.
|
|
154
|
+
*/
|
|
155
|
+
inlineHelpText?: string;
|
|
156
|
+
/**
|
|
157
|
+
* The help line's fallback, read second through `fieldHelpText`. An
|
|
158
|
+
* objectstack server on `@objectstack/spec` 17.7.0 or later serves a field's
|
|
159
|
+
* translated help text here.
|
|
160
|
+
*/
|
|
161
|
+
description?: string;
|
|
162
|
+
/**
|
|
163
|
+
* The field's own option list — `select` / `radio` / `checkboxes` metadata as
|
|
164
|
+
* `@objectstack/spec`'s `SelectOptionSchema` declares it, so entries may carry
|
|
165
|
+
* `visibleWhen` / `color` / `icon` / `disabled` alongside label and value. A
|
|
166
|
+
* bare string is shorthand for `{ label: s, value: s }`.
|
|
167
|
+
*/
|
|
168
|
+
options?: Array<ActionParamOption | string>;
|
|
169
|
+
multiple?: boolean;
|
|
170
|
+
defaultValue?: unknown;
|
|
171
|
+
accept?: string[];
|
|
172
|
+
maxSize?: number;
|
|
173
|
+
reference?: string;
|
|
174
|
+
displayField?: string;
|
|
175
|
+
reference_field?: string;
|
|
176
|
+
id_field?: string;
|
|
177
|
+
descriptionField?: string;
|
|
178
|
+
description_field?: string;
|
|
179
|
+
title_format?: string;
|
|
180
|
+
lookupColumns?: unknown[];
|
|
181
|
+
lookupFilters?: unknown[];
|
|
182
|
+
lookup_filters?: unknown[];
|
|
183
|
+
lookupPageSize?: number;
|
|
184
|
+
dependsOn?: unknown[];
|
|
185
|
+
}
|
|
186
|
+
interface RuntimeObject {
|
|
187
|
+
name?: string;
|
|
188
|
+
fields?: Record<string, RuntimeField>;
|
|
189
|
+
}
|
|
190
|
+
export interface ResolveActionParamsContext {
|
|
191
|
+
/** Default object name when a param's `objectOverride` is absent. */
|
|
192
|
+
objectName: string;
|
|
193
|
+
/** All known runtime objects (`useMetadata().objects`). */
|
|
194
|
+
objects: RuntimeObject[];
|
|
195
|
+
/** i18n resolver — `useObjectLabel().fieldLabel`. */
|
|
196
|
+
fieldLabel: (objectName: string, fieldName: string, fallback: string) => string;
|
|
197
|
+
/** Optional option-label translator — `useObjectLabel().fieldOptionLabel`. */
|
|
198
|
+
fieldOptionLabel?: (objectName: string, fieldName: string, optionValue: string, fallback: string) => string;
|
|
199
|
+
/**
|
|
200
|
+
* Row record providing default values for params with `defaultFromRow` set.
|
|
201
|
+
* Used by list_item actions (edit/delete dialogs) so the dialog opens with
|
|
202
|
+
* the row's current values pre-filled.
|
|
203
|
+
*/
|
|
204
|
+
row?: Record<string, unknown>;
|
|
205
|
+
/**
|
|
206
|
+
* Active UI language (BCP-47) used to resolve an inline per-locale
|
|
207
|
+
* {@link RawActionParam.label} down to the one string `ActionParamDef.label`
|
|
208
|
+
* can carry. Both callers thread `useObjectTranslation().language`.
|
|
209
|
+
*
|
|
210
|
+
* Optional and nullish-tolerant: omitted means "no locale known", which the
|
|
211
|
+
* spec's resolver documents as resolving to `en`. It is a context field
|
|
212
|
+
* rather than a hook read because this is a pure function — the caller is
|
|
213
|
+
* the component that already knows the language.
|
|
214
|
+
*/
|
|
215
|
+
locale?: string;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Resolve a single raw param against object metadata. Inline params pass
|
|
219
|
+
* through (with safe defaults); field-backed params inherit from the
|
|
220
|
+
* referenced field and accept inline overrides on top.
|
|
221
|
+
*/
|
|
222
|
+
export declare function resolveActionParam(param: RawActionParam, ctx: ResolveActionParamsContext): ActionParamDef;
|
|
223
|
+
/**
|
|
224
|
+
* Union the objects a CALLER holds with the ones the console's metadata store
|
|
225
|
+
* holds, caller first — the object list `resolveActionParams()` should be given.
|
|
226
|
+
*
|
|
227
|
+
* ## Why a union and not simply the store (`6cc910b6d`)
|
|
228
|
+
*
|
|
229
|
+
* The two lists answer different questions and neither contains the other.
|
|
230
|
+
* The caller's list is the world that caller is rendering: `ObjectView` passes
|
|
231
|
+
* the full published set, `DeclaredActionsBar` passes the ONE object it is
|
|
232
|
+
* drawing a toolbar for, `ConsoleShell`'s root runtime passes none, and a
|
|
233
|
+
* preview/draft host passes an overlaid world whose defs deliberately differ
|
|
234
|
+
* from the published ones. The store's list is every object the session has
|
|
235
|
+
* loaded. A caller that carries a def must keep it — replacing it would make a
|
|
236
|
+
* draft overlay render its published twin — so the caller is ranked FIRST and
|
|
237
|
+
* `resolveActionParam`'s `find()` takes the first match by name.
|
|
238
|
+
*
|
|
239
|
+
* What the store adds is the objects the caller never had: the owner of a
|
|
240
|
+
* `{ field }` param dispatched from a surface that is not scoped to that object
|
|
241
|
+
* at all, and the `objectOverride` target of a cross-object param. Before this,
|
|
242
|
+
* such a param resolved against a list that could not contain its owner and
|
|
243
|
+
* degraded — for a field-backed param, which carries no inline `type`, into a
|
|
244
|
+
* bare `text` param: an empty box, no dropdown, no request for the referenced
|
|
245
|
+
* object on the wire, while the identical field rendered a real picker on a
|
|
246
|
+
* record form off this very store.
|
|
247
|
+
*
|
|
248
|
+
* ⛔ Not a lenient fallback in the AGENTS.md #0.1 sense: no dialect is being
|
|
249
|
+
* tolerated and no shape coerced. The metadata is spec-compliant and already in
|
|
250
|
+
* the client; this is the seam that was not handing it over.
|
|
251
|
+
*
|
|
252
|
+
* Pure, and deduplicated by object `name` so a def cannot be resolved twice.
|
|
253
|
+
* Entries with no usable `name` are carried through from the caller's list
|
|
254
|
+
* (they are that caller's business) and skipped from the store's.
|
|
255
|
+
*/
|
|
256
|
+
export declare function withKnownObjects<T>(supplied: readonly T[] | undefined, stored: readonly T[] | undefined): T[];
|
|
257
|
+
/** Resolve an array of raw action params. */
|
|
258
|
+
export declare function resolveActionParams(params: RawActionParam[] | undefined, ctx: ResolveActionParamsContext): ActionParamDef[];
|
|
259
|
+
export {};
|
|
@@ -3,5 +3,46 @@ import { FieldWidgetComponentProps } from './types.js';
|
|
|
3
3
|
/**
|
|
4
4
|
* FormulaField - Read-only computed field
|
|
5
5
|
* Values are computed on the backend and cannot be edited
|
|
6
|
+
*
|
|
7
|
+
* ## One value, one reading (objectui#11748)
|
|
8
|
+
*
|
|
9
|
+
* This is the read-only FORM face of a formula; `FormulaCellRenderer` in this
|
|
10
|
+
* package's barrel is its TABLE face. The two used to format the value each by
|
|
11
|
+
* itself, so one stored value read two ways: a number here was `200000` (no
|
|
12
|
+
* `returnType`) or `200000.00` (a `toFixed(2)`), in monospace, beside the
|
|
13
|
+
* cell's `200,000`; a declared boolean or date read `Yes` / `Jul 4` here and
|
|
14
|
+
* `true` / `2026-07-04` in the cell.
|
|
15
|
+
*
|
|
16
|
+
* Both faces now read the SAME rule and draw each type through the calls the
|
|
17
|
+
* matching field type's faces make, so they agree on every value:
|
|
18
|
+
*
|
|
19
|
+
* - which type: the declared `returnType`; with none, a JS number is a
|
|
20
|
+
* number and anything else is text. ⛔ Nothing is inferred from the
|
|
21
|
+
* expression: the spec's own field form says consumers read `returnType`
|
|
22
|
+
* "instead of re-parsing the expression".
|
|
23
|
+
* - number: `formatNumberFieldValue`, the one call every number face makes
|
|
24
|
+
* (the locale's grouping, the width `resolveFieldScale` answers for a
|
|
25
|
+
* declared `scale`). The value is read the way the formula cell reads it
|
|
26
|
+
* (objectui#11683): blank is empty, and a declared number held as a
|
|
27
|
+
* numeric string is a number.
|
|
28
|
+
* - currency: money, through the currency field's own faces (`CurrencyField`
|
|
29
|
+
* read-only here, `CurrencyCellRenderer` in the cell), reading the
|
|
30
|
+
* formula's own `currencyConfig` as they read a currency field's
|
|
31
|
+
* (objectui#12111).
|
|
32
|
+
* - boolean: the locale's word, as `BooleanField`'s read-only branch draws
|
|
33
|
+
* it; only a JS boolean is a boolean, as there (objectui#8593).
|
|
34
|
+
* - date: `formatDate`'s DEFAULT face, as `DateField`'s read-only branch
|
|
35
|
+
* draws it (objectui#8194).
|
|
36
|
+
* - text: the value as the cell prints it, in the font `TextField`'s
|
|
37
|
+
* read-only branch draws (objectui#12357), declared `text` or not.
|
|
38
|
+
*
|
|
39
|
+
* Both faces also share the emptiness floor (`isEmptyValue` on the coerced
|
|
40
|
+
* value), so an empty value reads the shared affordance in both.
|
|
41
|
+
*
|
|
42
|
+
* The rule is spelled here and in the cell, because the barrel and this lazily
|
|
43
|
+
* loaded widget may not import each other (the reason `number-format.ts`
|
|
44
|
+
* gives). `__tests__/formulaFaces.returnType-11748.test.tsx` draws every
|
|
45
|
+
* declared type in both faces and compares the two texts, so neither can move
|
|
46
|
+
* alone.
|
|
6
47
|
*/
|
|
7
48
|
export declare function FormulaField({ value, field, ...props }: FieldWidgetComponentProps<any>): React.JSX.Element;
|
|
@@ -52,8 +52,10 @@ import { InlineGridColumn } from '@objectstack/spec/data';
|
|
|
52
52
|
*
|
|
53
53
|
* Field-level config: the keys `GridFieldMetadata` (`@object-ui/types`)
|
|
54
54
|
* declares, each read under that one spelling (objectui#11070 round 8), and
|
|
55
|
-
* no other key: `
|
|
56
|
-
* is declared there too (objectui#11070 round 9).
|
|
55
|
+
* no other key: `sortField`, the last key read before any face declared it,
|
|
56
|
+
* is declared there too (objectui#11070 round 9). objectui#11610 renamed all
|
|
57
|
+
* eight from snake_case to camelCase; a field still carrying a snake_case
|
|
58
|
+
* spelling is refused by name instead of drawn (`RetiredGridFieldKeys`).
|
|
57
59
|
*/
|
|
58
60
|
/**
|
|
59
61
|
* One grid column — `@objectstack/spec`'s inline grid column
|
|
@@ -130,7 +132,7 @@ export declare function lookupAutofillPatch(columns: GridColumn[], col: GridColu
|
|
|
130
132
|
export declare function computeRow(columns: GridColumn[], row: Row, tenantCurrency?: string): Row;
|
|
131
133
|
/** Sum a numeric column across rows (ignoring blanks/NaN). */
|
|
132
134
|
export declare function sumColumn(rows: Row[], field: string): number;
|
|
133
|
-
|
|
135
|
+
type GridFieldProps = FieldWidgetComponentProps<Row[]> & {
|
|
134
136
|
/** When provided, each row shows an "expand" button that opens the row in a
|
|
135
137
|
* full form (the host — e.g. MasterDetailForm — renders the drawer/modal and
|
|
136
138
|
* writes the edited values back). Lets a "fat" child be edited in a real form
|
|
@@ -147,7 +149,13 @@ export declare function GridField({ value, onChange, field, readonly, disabled,
|
|
|
147
149
|
* `readonlyWhen` / `requiredWhen` CEL predicate — so a line cell can react to
|
|
148
150
|
* the header (`parent.status == 'paid'`). Supplied by MasterDetailForm. */
|
|
149
151
|
contextRecord?: Record<string, unknown>;
|
|
150
|
-
}
|
|
152
|
+
};
|
|
153
|
+
/**
|
|
154
|
+
* The `grid` field widget. A field whose metadata carries one of the retired
|
|
155
|
+
* snake_case keys is refused by name ({@link RetiredGridFieldKeys}); any other
|
|
156
|
+
* field draws the grid.
|
|
157
|
+
*/
|
|
158
|
+
export declare function GridField(props: GridFieldProps): React.JSX.Element;
|
|
151
159
|
/** Semantic alias — the master-detail subform's child grid. */
|
|
152
160
|
export declare const LineItemsField: typeof GridField;
|
|
153
161
|
export {};
|
|
@@ -1,5 +1,37 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
2
|
import { FieldWidgetComponentProps } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* RecipientPickerField — dependent record picker for a polymorphic recipient
|
|
5
|
+
* reference (e.g. `sys_sharing_rule.recipient_id`), whose target object is
|
|
6
|
+
* decided by a sibling `recipient_type` select.
|
|
7
|
+
*
|
|
8
|
+
* Reached via the field `widget: 'recipient-picker'` hint (resolves as
|
|
9
|
+
* `field:recipient-picker`). Reads the live `recipient_type` from
|
|
10
|
+
* `dependentValues` (the form record), loads candidate records of the mapped
|
|
11
|
+
* object via `dataSource.find(...)`, and stores the value the sharing evaluator
|
|
12
|
+
* expects for that type:
|
|
13
|
+
*
|
|
14
|
+
* user → sys_user, store `id`
|
|
15
|
+
* team → sys_team, store `id`
|
|
16
|
+
* business_unit → sys_business_unit, store `id`
|
|
17
|
+
* unit_and_subordinates → sys_business_unit, store `id`
|
|
18
|
+
*
|
|
19
|
+
* One kind lists CATALOG ITEMS instead of records (objectui#7611, ADR-0131
|
|
20
|
+
* D3/D7): its candidates are the `position` items of the environment registry,
|
|
21
|
+
* read through the console's metadata store, and the picker stores the item's
|
|
22
|
+
* `name` (matched against `sys_user_position.position` at evaluation time):
|
|
23
|
+
*
|
|
24
|
+
* position → the `position` registry, store `name`
|
|
25
|
+
*
|
|
26
|
+
* One kind is NOT a record picker and therefore has no row above:
|
|
27
|
+
*
|
|
28
|
+
* field → a user-valued COLUMN of the shared object, store
|
|
29
|
+
* the column's `name` (see FIELD_RECIPIENT_TYPE)
|
|
30
|
+
*
|
|
31
|
+
* When `recipient_type` changes after mount the stored id is reset (an id valid
|
|
32
|
+
* for one type is meaningless for another). Unknown types degrade to a plain
|
|
33
|
+
* text input so nothing breaks.
|
|
34
|
+
*/
|
|
3
35
|
/** A user-valued column offered by the `field` recipient mode. */
|
|
4
36
|
interface UserFieldDef {
|
|
5
37
|
/** The machine name — this is what gets stored in `recipient_id`. */
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
import { FieldWidgetComponentProps } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* RegistryRefField — a record-form field that names ONE item of ONE metadata
|
|
5
|
+
* registry type by its machine name (objectui#7611, ruling B2 on
|
|
6
|
+
* objectstack#22865).
|
|
7
|
+
*
|
|
8
|
+
* The record-form face of the mechanism the metadata forms already have
|
|
9
|
+
* (`ref-multi:permission`, objectui#12126): the registry's items are listed by
|
|
10
|
+
* name, with the author's label beside the name, and the value written is the
|
|
11
|
+
* NAME — one string, never an id, never a row. A grant names its position or
|
|
12
|
+
* its permission set that way (ADR-0131 D4), and the server refuses a name the
|
|
13
|
+
* registry does not hold, so this widget only has to make the right name easy
|
|
14
|
+
* to pick.
|
|
15
|
+
*
|
|
16
|
+
* Reached through a field's `widget:` hint, which the form renderer looks up as
|
|
17
|
+
* `field:<widget>` (the spec's `FieldSchema.widget`). One registration per
|
|
18
|
+
* registry type, with the type in the key, as `object-ref` carries `object`:
|
|
19
|
+
*
|
|
20
|
+
* position-ref → `GET /api/v1/meta/position`
|
|
21
|
+
* permission-ref → `GET /api/v1/meta/permission`
|
|
22
|
+
*
|
|
23
|
+
* The catalog comes from `DataSource.listMetadataItems`, which rejects on a
|
|
24
|
+
* failure rather than answering `[]`, so its four arms are told apart the way
|
|
25
|
+
* the metadata forms' `ref:dataset` / `ref-multi:<type>` pickers tell them
|
|
26
|
+
* apart:
|
|
27
|
+
*
|
|
28
|
+
* - IDLE — no data source, or one that cannot enumerate a registry: a text
|
|
29
|
+
* box that writes the typed name;
|
|
30
|
+
* - LOADING — the stored name in a disabled box;
|
|
31
|
+
* - FAILED — a notice naming the failure and its cause, beside a text box that
|
|
32
|
+
* stays enabled, so a failed catalog does not also block the edit;
|
|
33
|
+
* - LOADED — nothing a grant can name: the same text box as IDLE; otherwise
|
|
34
|
+
* a searchable picker. A stored name the catalog does not list stays
|
|
35
|
+
* selectable as its own option, flagged "not found", so it is neither
|
|
36
|
+
* dropped nor read as a listed item. The flag is a claim about the
|
|
37
|
+
* registry's answer, so it is made only once the catalog has answered.
|
|
38
|
+
*
|
|
39
|
+
* The picker OFFERS only what a grant can name (objectui#12200). A position
|
|
40
|
+
* grant cannot name an audience anchor — `everyone` or `guest` (ADR-0090
|
|
41
|
+
* D5/D9), held implicitly by every authenticated or anonymous principal — and
|
|
42
|
+
* the server refuses a `sys_user_position` row that does. So `position-ref`
|
|
43
|
+
* leaves the anchors out of its options ({@link nonGrantableNames}). A stored
|
|
44
|
+
* anchor is still the row's value: it stays on screen as its own option, by its
|
|
45
|
+
* label beside its name, and it is not flagged "not found", because the
|
|
46
|
+
* registry does list it.
|
|
47
|
+
*
|
|
48
|
+
* ⛔ No arm writes anything but a name the person picked or typed: no label,
|
|
49
|
+
* no id, no first-item default.
|
|
50
|
+
*/
|
|
51
|
+
/** One listed item of a registry: the name stored, the label shown beside it. */
|
|
52
|
+
export interface RegistryItemHeader {
|
|
53
|
+
name: string;
|
|
54
|
+
label?: string;
|
|
55
|
+
}
|
|
56
|
+
/** The catalog, in whichever of its four states the load is actually in. */
|
|
57
|
+
export type RegistryCatalogState = {
|
|
58
|
+
status: 'idle';
|
|
59
|
+
} | {
|
|
60
|
+
status: 'loading';
|
|
61
|
+
} | {
|
|
62
|
+
status: 'error';
|
|
63
|
+
message: string;
|
|
64
|
+
} | {
|
|
65
|
+
status: 'loaded';
|
|
66
|
+
items: RegistryItemHeader[];
|
|
67
|
+
};
|
|
68
|
+
export interface RegistryRefFieldProps extends FieldWidgetComponentProps<string> {
|
|
69
|
+
/** The registry type whose items this field names (`position`, `permission`). */
|
|
70
|
+
registryType: string;
|
|
71
|
+
}
|
|
72
|
+
export declare function RegistryRefField({ registryType, value, onChange, readonly, className, error, ...props }: RegistryRefFieldProps): React.JSX.Element;
|
|
73
|
+
/** `position-ref`: names one position of the position registry. */
|
|
74
|
+
export declare function PositionRefField(props: FieldWidgetComponentProps<string>): React.JSX.Element;
|
|
75
|
+
/** `permission-ref`: names one permission set of the `permission` registry. */
|
|
76
|
+
export declare function PermissionRefField(props: FieldWidgetComponentProps<string>): React.JSX.Element;
|
|
77
|
+
export default RegistryRefField;
|
|
@@ -3,5 +3,35 @@ import { FieldWidgetComponentProps } from './types.js';
|
|
|
3
3
|
/**
|
|
4
4
|
* SummaryField - Read-only aggregation field
|
|
5
5
|
* Values are aggregated from related records and cannot be edited
|
|
6
|
+
*
|
|
7
|
+
* ## One value, one reading (objectui#11752)
|
|
8
|
+
*
|
|
9
|
+
* This is the read-only FORM face of a roll-up; its TABLE face is the formula
|
|
10
|
+
* cell, `FormulaCellRenderer` in this package's barrel, which `summary` is
|
|
11
|
+
* registered to. The two used to format the value each by itself, so one
|
|
12
|
+
* stored value read two ways: this face picked a format by the roll-up's
|
|
13
|
+
* aggregation `function` (`count` as it arrived, the other four at two fixed
|
|
14
|
+
* decimals), so a `sum` over `15750.5` read `15750.50`, ungrouped and in every
|
|
15
|
+
* locale, beside the cell's `15,750.5`.
|
|
16
|
+
*
|
|
17
|
+
* This face now reads the value the way the cell reads a summary's value,
|
|
18
|
+
* whatever the function:
|
|
19
|
+
*
|
|
20
|
+
* - the emptiness FLOOR (`isEmptyValue`) on the coerced value, as the cell
|
|
21
|
+
* takes it, so `''` and `[]` read the shared affordance in both faces;
|
|
22
|
+
* - a JS number: `formatNumberFieldValue`, the one call every number face
|
|
23
|
+
* makes (the display locale's grouping, the width `resolveFieldScale`
|
|
24
|
+
* answers for a declared `scale`, the value's natural precision when none
|
|
25
|
+
* is declared). A `count` is a whole number, so it reads whole; an author
|
|
26
|
+
* who wants a fixed width on a `sum` or an `avg` declares `scale`, and both
|
|
27
|
+
* faces honour it.
|
|
28
|
+
* - anything else: the coerced value as text, as the cell prints it. A
|
|
29
|
+
* summary declares no `returnType`, so a string of digits is not a number.
|
|
30
|
+
*
|
|
31
|
+
* The rule is spelled here and in the cell, because the barrel and this lazily
|
|
32
|
+
* loaded widget may not import each other (the reason `number-format.ts`
|
|
33
|
+
* gives). `__tests__/summaryFaces.numberFace-11752.test.tsx` draws every
|
|
34
|
+
* aggregation function in both faces and compares the two texts, so neither
|
|
35
|
+
* can move alone.
|
|
6
36
|
*/
|
|
7
37
|
export declare function SummaryField({ value, field, ...props }: FieldWidgetComponentProps<any>): React.JSX.Element;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
/** Draws a boolean value as the current locale's word for it. */
|
|
3
|
+
export type BooleanValueLabel = (value: boolean) => string;
|
|
4
|
+
/**
|
|
5
|
+
* The current locale's word for a boolean value: `common.yes` for `true`,
|
|
6
|
+
* `common.no` for `false`.
|
|
7
|
+
*
|
|
8
|
+
* The caller decides WHICH values are booleans; this only names them. Call it
|
|
9
|
+
* once at the top of a component and use the returned function in the render.
|
|
10
|
+
*/
|
|
11
|
+
export declare function useBooleanValueLabel(): BooleanValueLabel;
|
|
12
|
+
/**
|
|
13
|
+
* The same word as a node, for a caller that is a plain function and cannot
|
|
14
|
+
* call a hook itself (`renderLookupColumnValue`).
|
|
15
|
+
*/
|
|
16
|
+
export declare function BooleanValueText({ value }: {
|
|
17
|
+
value: boolean;
|
|
18
|
+
}): React.ReactElement;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
import { FieldWidgetComponentProps } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* The `date` and date-time controls of the form field widgets
|
|
5
|
+
* (objectui#12622, objectui#12642).
|
|
6
|
+
*
|
|
7
|
+
* `fieldWidgetMap`'s `date` / `datetime` widgets — what a record form resolves
|
|
8
|
+
* `field:date` / `field:datetime` to, and what `getLazyFieldWidget` hands the
|
|
9
|
+
* action-param and bulk-action dialogs — draw the platform picker instead of
|
|
10
|
+
* the browser's native input: a text box in the display locale's format (keyboard
|
|
11
|
+
* entry), a calendar popover (the same `Calendar` the calendar view's date
|
|
12
|
+
* popover opens, localized by the same resolver), a clear button, and
|
|
13
|
+
* today / tomorrow shortcuts.
|
|
14
|
+
*
|
|
15
|
+
* ## The value written is unchanged
|
|
16
|
+
*
|
|
17
|
+
* Both faces go through the native adapters `DateField` / `DateTimeField` use
|
|
18
|
+
* (`toDateInputValue`, `toDateTimeInputValue`, `fromDateTimeInputValue`), so a
|
|
19
|
+
* `date` field writes `YYYY-MM-DD` and a `datetime` field writes an ISO
|
|
20
|
+
* instant, exactly as the native inputs did; clearing writes `''` as the
|
|
21
|
+
* native inputs did.
|
|
22
|
+
*
|
|
23
|
+
* ## Where the native input stays
|
|
24
|
+
*
|
|
25
|
+
* - The read-only face is `DateField` / `DateTimeField`'s own, rendered as is.
|
|
26
|
+
* - `FieldEditWidget` (the grid's inline cell editor and the kanban
|
|
27
|
+
* required-fields dialog) draws THIS picker since objectui#12664, loaded
|
|
28
|
+
* lazily so it stays in its own chunk; the grid's cell seam blurs the
|
|
29
|
+
* control before Enter or a click outside commits, and that blur is where
|
|
30
|
+
* the typed text is read. plugin-detail's `InlineFieldInput` (the record
|
|
31
|
+
* page's details and highlights) delegates `date` and `datetime` to
|
|
32
|
+
* `FieldEditWidget` too since objectui#12759. The list filter rows are
|
|
33
|
+
* objectui#12743.
|
|
34
|
+
* - A form whose `field:date` widget is not registered (no
|
|
35
|
+
* `@object-ui/fields` loaded) falls back to the form renderer's own
|
|
36
|
+
* `<input type={inputType}>`, with the `inputType` `ObjectForm` maps.
|
|
37
|
+
*/
|
|
38
|
+
export declare function DatePickerField(props: FieldWidgetComponentProps<string>): React.JSX.Element;
|
|
39
|
+
/** The `datetime` face of {@link DatePickerField}. */
|
|
40
|
+
export declare function DateTimePickerField(props: FieldWidgetComponentProps<string>): React.JSX.Element;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ObjectUI
|
|
3
|
+
* Copyright (c) 2024-present ObjectStack Inc.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* The display text for a native-shaped value (`YYYY-MM-DD`, or
|
|
10
|
+
* `YYYY-MM-DDTHH:mm` when `withTime`). `''` for an empty or unreadable value.
|
|
11
|
+
*/
|
|
12
|
+
export declare function formatLocaleDateText(value: string, locale: string, withTime: boolean): string;
|
|
13
|
+
/**
|
|
14
|
+
* The pattern the text box expects, for its placeholder: the locale's own
|
|
15
|
+
* order and separators with `YYYY` / `MM` / `DD` (and `HH` / `mm`) in place of
|
|
16
|
+
* the digits.
|
|
17
|
+
*/
|
|
18
|
+
export declare function localeDatePattern(locale: string, withTime: boolean): string;
|
|
19
|
+
/**
|
|
20
|
+
* Reads what was typed into the text box.
|
|
21
|
+
*
|
|
22
|
+
* Returns `''` for blank text, the native-shaped value for a real day (and a
|
|
23
|
+
* real clock time when `withTime`), and `null` for text that names no real
|
|
24
|
+
* date. Accepted:
|
|
25
|
+
*
|
|
26
|
+
* - the locale's own digit order, with any separators (`10/16/2026` in `en`,
|
|
27
|
+
* `2026/10/16` in `zh`, `16.10.2026` in `de`);
|
|
28
|
+
* - an ISO date `2026-10-16`, in every locale (a four-digit first group is
|
|
29
|
+
* read as the year);
|
|
30
|
+
* - a two-digit year, read in this century;
|
|
31
|
+
* - with `withTime`: an hour and minute after the date, 24-hour, or 12-hour
|
|
32
|
+
* with `AM` / `PM` or the locale's own afternoon marker. With no time, the
|
|
33
|
+
* time is midnight.
|
|
34
|
+
*/
|
|
35
|
+
export declare function parseLocaleDateText(text: string, locale: string, withTime: boolean): string | null;
|
|
36
|
+
/** The local calendar day of `d` as `YYYY-MM-DD`. */
|
|
37
|
+
export declare function toLocalDay(d: Date): string;
|
|
38
|
+
/** Local midnight of a `YYYY-MM-DD` day, for the calendar to select. */
|
|
39
|
+
export declare function fromLocalDay(day: string): Date | undefined;
|
|
@@ -24,7 +24,7 @@ interface ObjectSchemaLike {
|
|
|
24
24
|
}
|
|
25
25
|
/**
|
|
26
26
|
* Derive sensible Record Picker columns from a referenced object's schema when
|
|
27
|
-
* a lookup field declares no explicit `
|
|
27
|
+
* a lookup field declares no explicit `lookupColumns`.
|
|
28
28
|
*
|
|
29
29
|
* Priority:
|
|
30
30
|
* 1. The referenced object's ADR-0085 `highlightFields` — the canonical
|
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
2
|
import { FileValueView } from './file-value.js';
|
|
3
|
+
/**
|
|
4
|
+
* The translated label and hint for a file the reader may not open
|
|
5
|
+
* (objectui#12339): a value that arrived as the refused marker
|
|
6
|
+
* `{ id, metadataRefused: true }` carries no name of its own, and drawing the
|
|
7
|
+
* generic `fields.file.fileFallback` for it would read as an ordinary file.
|
|
8
|
+
*/
|
|
9
|
+
export declare function useRestrictedFileText(): {
|
|
10
|
+
label: string;
|
|
11
|
+
hint: string;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* The restricted state of one file value (`view.metadataRefused`): a lock
|
|
15
|
+
* and the translated "Restricted file" label instead of a name, and ⛔ no
|
|
16
|
+
* thumbnail — no MIME type was served, so there is nothing to decide one on.
|
|
17
|
+
*
|
|
18
|
+
* It stays an anchor to the view's id-derived URL: whether this reader may
|
|
19
|
+
* download the file is the download endpoint's own decision, and it may
|
|
20
|
+
* answer `403 FILE_DOWNLOAD_DENIED`. The accessible name is the visible
|
|
21
|
+
* label; the hint rides on `title`.
|
|
22
|
+
*
|
|
23
|
+
* `compact` draws the lock alone, for a cell or tile that has no room for
|
|
24
|
+
* the label — the label then becomes the anchor's `aria-label`.
|
|
25
|
+
*/
|
|
26
|
+
export declare function RestrictedFileAffordance({ view, className, compact, icon, }: {
|
|
27
|
+
view: FileValueView;
|
|
28
|
+
className?: string;
|
|
29
|
+
compact?: boolean;
|
|
30
|
+
/** Suppressed where the row already draws its own icon to the left. */
|
|
31
|
+
icon?: boolean;
|
|
32
|
+
}): React.ReactElement;
|
|
3
33
|
/**
|
|
4
34
|
* One file: a keyboard-reachable view/download link when it resolves, and the
|
|
5
35
|
* caller's own `fallback` text when it does not.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { FileRefusedValue } from '@objectstack/spec/data';
|
|
2
|
+
/**
|
|
3
|
+
* Is this value the platform's refused marker `{ id, metadataRefused: true }`?
|
|
4
|
+
*
|
|
5
|
+
* Judged by the spec's own closed `FileRefusedValueSchema`, not by a second
|
|
6
|
+
* hand-written shape here: an object with any other key is not the marker,
|
|
7
|
+
* and reads through `readFileValue`'s ordinary object arm.
|
|
8
|
+
*/
|
|
9
|
+
export declare function isFileRefusedValue(value: unknown): value is FileRefusedValue;
|
|
10
|
+
/**
|
|
11
|
+
* One element of a field value as an editable widget re-submits it beside or
|
|
12
|
+
* after an edit (append, remove, crop): the refused marker is reduced to its
|
|
13
|
+
* bare `sys_file` id — the stored form — and ⛔ never sent back as the marker
|
|
14
|
+
* object, which is a read form no record write accepts. Every other element
|
|
15
|
+
* passes through untouched, as before.
|
|
16
|
+
*/
|
|
17
|
+
export declare function fileValueForResubmit(value: unknown): unknown;
|