@powerportalspro/react 5.0.0-beta.2 → 5.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/dist/index.cjs +378 -33
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +485 -310
- package/dist/index.d.ts +485 -310
- package/dist/index.js +370 -33
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,159 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import { ReactNode } from 'react';
|
|
2
|
+
import { ChangeEvent, ReactNode } from 'react';
|
|
3
3
|
import { components, TableMetadata as TableMetadata$1, ViewMetadata, CurrentUserInfo, Transport, AuthClient, PowerPortalsProClient, LoginRequest, LoginResponse, SwitchIdentityResponse, PowerPortalsProError, TableRecord, RetrieveRecordsResponse, GridDataRequest, GridDataResponse, GridFilterBase, ChartAggregation, ColumnSort, ResolvedColumn, TableSecurityPermission, ChartData, OrganizationRequest } from '@powerportalspro/core';
|
|
4
4
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
5
5
|
|
|
6
|
-
type EnvironmentFileSettings$2 = components['schemas']['EnvironmentFileSettings'];
|
|
7
6
|
/**
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* Masking strategy applied to a masked text field.
|
|
8
|
+
*
|
|
9
|
+
* Hybrid const-object + literal-union — same pattern other enums in
|
|
10
|
+
* the package follow (e.g. `GridButtonBehavior`).
|
|
11
|
+
*/
|
|
12
|
+
declare const MaskMode: {
|
|
13
|
+
/** No masking — value passes through unchanged. */
|
|
14
|
+
readonly None: "none";
|
|
15
|
+
/**
|
|
16
|
+
* Per-character allow filter. Characters that don't match
|
|
17
|
+
* {@link MaskOptions.allowedPattern} are dropped as they're typed or pasted.
|
|
18
|
+
*/
|
|
19
|
+
readonly Regex: "regex";
|
|
20
|
+
/**
|
|
21
|
+
* Slotted template (see {@link MaskOptions.pattern}) such as `(000) 000-0000`.
|
|
22
|
+
* `0` = digit, `A` = letter, `*` = alphanumeric; every other character is a
|
|
23
|
+
* literal inserted automatically.
|
|
24
|
+
*/
|
|
25
|
+
readonly Pattern: "pattern";
|
|
26
|
+
/**
|
|
27
|
+
* Live numeric grouping driven by {@link MaskOptions.numeric} — thousands
|
|
28
|
+
* separators, an optional decimal portion, and an optional leading sign.
|
|
29
|
+
*/
|
|
30
|
+
readonly Numeric: "numeric";
|
|
31
|
+
};
|
|
32
|
+
type MaskMode = (typeof MaskMode)[keyof typeof MaskMode];
|
|
33
|
+
/**
|
|
34
|
+
* Numeric masking options for {@link MaskMode.Numeric}. All separators are
|
|
35
|
+
* supplied by the caller so the field stays culture-correct (a German consumer
|
|
36
|
+
* gets `.` groups and `,` decimals).
|
|
37
|
+
*/
|
|
38
|
+
interface NumericOptions {
|
|
39
|
+
/** Character used to separate the whole and fractional parts (e.g. `.`). */
|
|
40
|
+
decimalSeparator: string;
|
|
41
|
+
/** Character inserted between thousands groups (e.g. `,`). Empty disables grouping. */
|
|
42
|
+
groupSeparator: string;
|
|
43
|
+
/** Whether a single leading minus sign is accepted. */
|
|
44
|
+
allowNegative: boolean;
|
|
45
|
+
/** Maximum fractional digits, or `null` for unlimited. */
|
|
46
|
+
maxDecimals: number | null;
|
|
47
|
+
/** Whether a decimal portion is allowed at all (integers set this false). */
|
|
48
|
+
allowDecimal: boolean;
|
|
49
|
+
}
|
|
50
|
+
/** Configuration for a single reformat call. */
|
|
51
|
+
interface MaskOptions {
|
|
52
|
+
mode: MaskMode;
|
|
53
|
+
/** Regex mode: a per-character allow test, e.g. `[0-9.]`. Chars failing it are dropped. */
|
|
54
|
+
allowedPattern: string | null;
|
|
55
|
+
/**
|
|
56
|
+
* Pattern mode: a slotted template, e.g. `(000) 000-0000`. `0`=digit, `A`=letter,
|
|
57
|
+
* `*`=alphanumeric; every other character is a literal inserted automatically.
|
|
58
|
+
*/
|
|
59
|
+
pattern: string | null;
|
|
60
|
+
/** Numeric mode: separators, sign, decimal options. */
|
|
61
|
+
numeric: NumericOptions | null;
|
|
62
|
+
/**
|
|
63
|
+
* When true, the value reported by the consumer's `onValueChange` is the
|
|
64
|
+
* masked display string (with literals/separators included); when false, the
|
|
65
|
+
* unmasked logical value (e.g. `5551234567` rather than `(555) 123-4567`).
|
|
66
|
+
* Round-trips correctly either way because reformat is idempotent.
|
|
67
|
+
*/
|
|
68
|
+
valueIncludesMask: boolean;
|
|
69
|
+
}
|
|
70
|
+
/** Output of a single reformat call. */
|
|
71
|
+
interface ReformatResult {
|
|
72
|
+
/** The string to display in the input (masked / grouped). */
|
|
73
|
+
display: string;
|
|
74
|
+
/**
|
|
75
|
+
* The logical value reported back to the consumer (group separators stripped
|
|
76
|
+
* for numeric; mask literals stripped for pattern). Drives the bound model.
|
|
77
|
+
*/
|
|
78
|
+
raw: string;
|
|
79
|
+
/** Caret offset into `display` after reformatting. */
|
|
80
|
+
caret: number;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Reformat `value` according to `options`. Pure — same input always yields the
|
|
84
|
+
* same `{ display, raw, caret }`. Caller is responsible for actually writing
|
|
85
|
+
* the new display string into the input and calling `setSelectionRange(caret,
|
|
86
|
+
* caret)`. {@link useMaskedTextField} does that wiring for React consumers.
|
|
87
|
+
*/
|
|
88
|
+
declare function reformat(value: string, caret: number, options: MaskOptions): ReformatResult;
|
|
89
|
+
|
|
90
|
+
interface UseMaskedTextFieldOptions {
|
|
91
|
+
/**
|
|
92
|
+
* Current logical value (unmasked, the way it should be stored on the
|
|
93
|
+
* bound model). The hook reformats this into the masked `displayValue` it
|
|
94
|
+
* returns. Pass `null` / `undefined` for empty.
|
|
95
|
+
*/
|
|
96
|
+
value: string | null | undefined;
|
|
97
|
+
/**
|
|
98
|
+
* Fires on every keystroke that changes the reported value. Receives the
|
|
99
|
+
* unmasked logical value (e.g. `5551234567`) when {@link valueIncludesMask}
|
|
100
|
+
* is `false`, the masked display string (e.g. `(555) 123-4567`) when `true`.
|
|
101
|
+
*/
|
|
102
|
+
onValueChange: (raw: string | null) => void;
|
|
103
|
+
/** Masking strategy. Defaults to {@link MaskMode.None}. */
|
|
104
|
+
mode?: MaskMode | undefined;
|
|
105
|
+
/** Slotted template for {@link MaskMode.Pattern} (e.g. `(000) 000-0000`). */
|
|
106
|
+
pattern?: string | null | undefined;
|
|
107
|
+
/** Per-character allow regex for {@link MaskMode.Regex} (e.g. `[A-Za-z]`). */
|
|
108
|
+
allowedPattern?: string | null | undefined;
|
|
109
|
+
/** Numeric options for {@link MaskMode.Numeric}. */
|
|
110
|
+
numeric?: NumericOptions | null | undefined;
|
|
111
|
+
/**
|
|
112
|
+
* When `true`, the value reported by `onValueChange` is the masked display
|
|
113
|
+
* string (with literals/separators); when `false` (default), the unmasked
|
|
114
|
+
* logical value. Either form round-trips correctly because reformat is
|
|
115
|
+
* idempotent.
|
|
116
|
+
*/
|
|
117
|
+
valueIncludesMask?: boolean | undefined;
|
|
118
|
+
}
|
|
119
|
+
interface UseMaskedTextFieldReturn {
|
|
120
|
+
/**
|
|
121
|
+
* Masked display string. Pass this to the consumer input's `value` prop
|
|
122
|
+
* the hook re-renders it via React state on every keystroke + external
|
|
123
|
+
* value push.
|
|
124
|
+
*/
|
|
125
|
+
displayValue: string;
|
|
126
|
+
/**
|
|
127
|
+
* Input change handler — matches Fluent v9 `<Input onChange>`'s
|
|
128
|
+
* `(event, data: { value })` shape. Reformats the typed value, updates
|
|
129
|
+
* `displayValue`, and reports the logical value via `onValueChange`.
|
|
130
|
+
*/
|
|
131
|
+
onChange: (event: ChangeEvent<HTMLInputElement>, data: {
|
|
132
|
+
value: string;
|
|
133
|
+
}) => void;
|
|
134
|
+
/**
|
|
135
|
+
* Callback ref — attach to the underlying `<input>`. The hook needs the
|
|
136
|
+
* element reference both for caret-position bookkeeping and for the
|
|
137
|
+
* focus / blur listeners that gate external value pushes.
|
|
138
|
+
*/
|
|
139
|
+
inputRef: (el: HTMLInputElement | null) => void;
|
|
140
|
+
/**
|
|
141
|
+
* Push a value into the field even while it has focus, parking the caret
|
|
142
|
+
* at the end. Used by an owning editor's spinner / stepper controls.
|
|
143
|
+
*/
|
|
144
|
+
forceValue: (value: string | null) => void;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* React hook that wires caret-safe masking onto a controlled input. Returns
|
|
148
|
+
* `displayValue` + `onChange` to spread onto a Fluent v9 `<Input>` (or any
|
|
149
|
+
* controlled `<input>`), plus an `inputRef` callback to attach to the
|
|
150
|
+
* underlying element and an imperative `forceValue` helper.
|
|
151
|
+
*/
|
|
152
|
+
declare function useMaskedTextField(opts: UseMaskedTextFieldOptions): UseMaskedTextFieldReturn;
|
|
153
|
+
|
|
154
|
+
type OrganizationSettings$2 = components['schemas']['OrganizationSettings'];
|
|
155
|
+
/**
|
|
156
|
+
* Client-side cache for table metadata.
|
|
10
157
|
*
|
|
11
158
|
* The default implementation lives in-memory (Map) with in-flight-promise
|
|
12
159
|
* dedup so N parallel `getAsync` calls for the same table share one
|
|
@@ -16,7 +163,7 @@ type EnvironmentFileSettings$2 = components['schemas']['EnvironmentFileSettings'
|
|
|
16
163
|
*
|
|
17
164
|
* Why this exists: the inline-editable grid mounts one `<RecordContext>`
|
|
18
165
|
* per visible row when the user toggles edit mode on. Each RC would
|
|
19
|
-
* otherwise fire its own `retrieveTableMetadataAsync` round-trip
|
|
166
|
+
* otherwise fire its own `retrieveTableMetadataAsync` round-trip
|
|
20
167
|
* thundering-herd against the same endpoint that produces visibly
|
|
21
168
|
* staggered row rendering as each fetch's response lands. The cache
|
|
22
169
|
* collapses that to a single fetch shared across all consumers.
|
|
@@ -40,7 +187,7 @@ interface TableMetadataCache {
|
|
|
40
187
|
}
|
|
41
188
|
/**
|
|
42
189
|
* Client-side cache for Dataverse view metadata. Same shape and
|
|
43
|
-
* rationale as {@link TableMetadataCache}
|
|
190
|
+
* rationale as {@link TableMetadataCache}
|
|
44
191
|
* `IViewMetadataCache` (in `PowerPortalsPro.Common.Services`).
|
|
45
192
|
*
|
|
46
193
|
* Keyed by view id (Dataverse GUID, hyphenated, no braces). The default
|
|
@@ -83,23 +230,33 @@ interface ViewsForTableCache {
|
|
|
83
230
|
clear(): void;
|
|
84
231
|
}
|
|
85
232
|
/**
|
|
86
|
-
* Singleton cache for the org-wide
|
|
87
|
-
*
|
|
88
|
-
* one `
|
|
233
|
+
* Singleton cache for the org-wide settings sourced from the Dataverse
|
|
234
|
+
* `organization` record — default currency plus file-upload constraints.
|
|
235
|
+
* There's only one `OrganizationSettings` per environment, so no key
|
|
236
|
+
* parameter.
|
|
237
|
+
*
|
|
238
|
+
* Two distinct consumer classes share it:
|
|
239
|
+
* - Create-mode `<MoneyEdit>` reads `defaultCurrency` so the right symbol
|
|
240
|
+
* renders on brand-new records before save.
|
|
241
|
+
* - File editors (`<FileEdit>`, `<ImageEdit>`, `<FileGrid>`) read
|
|
242
|
+
* `blockedFileExtensions` + `maxUploadFileSizeInBytes` to reject invalid
|
|
243
|
+
* uploads client-side before the round-trip.
|
|
89
244
|
*
|
|
90
|
-
*
|
|
91
|
-
* fire
|
|
92
|
-
*
|
|
93
|
-
* the
|
|
245
|
+
* Without the cache, every create-mode `<RecordContext>` mount AND every
|
|
246
|
+
* `<FileGrid>` would fire its own GET — multi-form pages and react-router
|
|
247
|
+
* navigations would generate redundant traffic even though the value is
|
|
248
|
+
* stable for the user's whole session. The server already caches the
|
|
249
|
+
* response; this cache eliminates the HTTP trips entirely.
|
|
250
|
+
*
|
|
251
|
+
* Replaces the legacy `EnvironmentFileSettingsCache`.
|
|
94
252
|
*/
|
|
95
|
-
interface
|
|
253
|
+
interface OrganizationSettingsCache {
|
|
96
254
|
/**
|
|
97
255
|
* Returns the cached settings, fetching from the server on a miss.
|
|
98
256
|
* Concurrent calls share a single in-flight promise. Returns `null`
|
|
99
|
-
* only when the server explicitly returns no settings
|
|
100
|
-
* typically the endpoint always returns a value).
|
|
257
|
+
* only when the server explicitly returns no settings.
|
|
101
258
|
*/
|
|
102
|
-
getAsync(): Promise<
|
|
259
|
+
getAsync(): Promise<OrganizationSettings$2 | null>;
|
|
103
260
|
/**
|
|
104
261
|
* Drops the cached value. The next `getAsync` re-fetches from the
|
|
105
262
|
* server.
|
|
@@ -128,7 +285,7 @@ type AuthStatus = (typeof AuthStatus)[keyof typeof AuthStatus];
|
|
|
128
285
|
* either `anonymous` or `authenticated` for the rest of the app's lifetime (until
|
|
129
286
|
* `login()` / `logout()` actions transition it).
|
|
130
287
|
*
|
|
131
|
-
* The `authenticated` branch carries the {@link CurrentUserInfo} the server returned
|
|
288
|
+
* The `authenticated` branch carries the {@link CurrentUserInfo} the server returned
|
|
132
289
|
* the auto-generated DTO from `@powerportalspro/core`, no narrowing applied. Fields
|
|
133
290
|
* like `roles` arrive as `string[] | undefined` per the wire contract; consumers
|
|
134
291
|
* coalesce to `[]` at the read site if they want a non-null array.
|
|
@@ -165,11 +322,10 @@ interface PowerPortalsProContextValue {
|
|
|
165
322
|
*/
|
|
166
323
|
readonly viewsForTableCache: ViewsForTableCache;
|
|
167
324
|
/**
|
|
168
|
-
* Client-side cache for the singleton
|
|
169
|
-
*
|
|
170
|
-
* {@link EnvironmentFileSettingsCache}.
|
|
325
|
+
* Client-side cache for the singleton organization settings (default
|
|
326
|
+
* currency plus file-upload constraints). See {@link OrganizationSettingsCache}.
|
|
171
327
|
*/
|
|
172
|
-
readonly
|
|
328
|
+
readonly organizationSettingsCache: OrganizationSettingsCache;
|
|
173
329
|
/** Current auth state. {@link useAuth} unpacks this directly. */
|
|
174
330
|
readonly authState: AuthState;
|
|
175
331
|
/** Refreshes the auth state by re-calling `/api/auth/me`. */
|
|
@@ -195,7 +351,7 @@ interface PowerPortalsProProviderProps {
|
|
|
195
351
|
/**
|
|
196
352
|
* Optional pre-constructed {@link Transport} for the AuthClient and PowerPortalsProClient
|
|
197
353
|
* to share. Pass one to set a non-default `baseUrl`, inject a custom `fetch`
|
|
198
|
-
* implementation for tests, etc. When omitted, a default transport is constructed
|
|
354
|
+
* implementation for tests, etc. When omitted, a default transport is constructed
|
|
199
355
|
* same-origin, browser fetch, cookie credentials included.
|
|
200
356
|
*
|
|
201
357
|
* The provider holds a stable reference to the transport for its lifetime — passing
|
|
@@ -254,10 +410,10 @@ interface PowerPortalsProProviderProps {
|
|
|
254
410
|
*/
|
|
255
411
|
viewsForTableCache?: ViewsForTableCache;
|
|
256
412
|
/**
|
|
257
|
-
* Custom {@link
|
|
413
|
+
* Custom {@link OrganizationSettingsCache} implementation. Same
|
|
258
414
|
* defaulting behavior as {@link tableMetadataCache}.
|
|
259
415
|
*/
|
|
260
|
-
|
|
416
|
+
organizationSettingsCache?: OrganizationSettingsCache;
|
|
261
417
|
}
|
|
262
418
|
/**
|
|
263
419
|
* Top-level provider for `@powerportalspro/react`. Constructs an {@link AuthClient}
|
|
@@ -268,14 +424,14 @@ interface PowerPortalsProProviderProps {
|
|
|
268
424
|
* Wrap the app once near the root:
|
|
269
425
|
* ```tsx
|
|
270
426
|
* <PowerPortalsProProvider>
|
|
271
|
-
*
|
|
427
|
+
* <App />
|
|
272
428
|
* </PowerPortalsProProvider>
|
|
273
429
|
* ```
|
|
274
430
|
*
|
|
275
431
|
* Hooks ({@link useAuth}, {@link usePowerPortalsPro}, {@link useRecord}, …) read from
|
|
276
432
|
* this provider's context.
|
|
277
433
|
*/
|
|
278
|
-
declare function PowerPortalsProProvider({ children, transport, localizationUrl, localizationUrls, localizationPrefixes, tableMetadataCache, viewMetadataCache, viewsForTableCache,
|
|
434
|
+
declare function PowerPortalsProProvider({ children, transport, localizationUrl, localizationUrls, localizationPrefixes, tableMetadataCache, viewMetadataCache, viewsForTableCache, organizationSettingsCache, }: PowerPortalsProProviderProps): react_jsx_runtime.JSX.Element;
|
|
279
435
|
|
|
280
436
|
/**
|
|
281
437
|
* Returns the {@link AuthClient}, {@link PowerPortalsProClient}, and underlying
|
|
@@ -296,8 +452,8 @@ declare function usePowerPortalsPro(): PowerPortalsProContextValue;
|
|
|
296
452
|
* import { AuthStatus, useAuth } from '@powerportalspro/react';
|
|
297
453
|
*
|
|
298
454
|
* const auth = useAuth();
|
|
299
|
-
* if (auth.status === AuthStatus.Loading)
|
|
300
|
-
* if (auth.status === AuthStatus.Anonymous)
|
|
455
|
+
* if (auth.status === AuthStatus.Loading) return <Spinner />;
|
|
456
|
+
* if (auth.status === AuthStatus.Anonymous) return <SignInButton onClick={() => auth.login(...)} />;
|
|
301
457
|
* if (auth.status === AuthStatus.Authenticated) return <span>Hi, {auth.user.email}</span>;
|
|
302
458
|
* ```
|
|
303
459
|
*
|
|
@@ -305,7 +461,7 @@ declare function usePowerPortalsPro(): PowerPortalsProContextValue;
|
|
|
305
461
|
* propagates via context, so all `useAuth` calls in the tree see the same value
|
|
306
462
|
* and re-render on transitions.
|
|
307
463
|
*
|
|
308
|
-
* `login` mirrors {@link AuthClient.loginAsync} — same request/response shapes
|
|
464
|
+
* `login` mirrors {@link AuthClient.loginAsync} — same request/response shapes
|
|
309
465
|
* but additionally re-fetches `/api/auth/me` on `Success` so the auth state
|
|
310
466
|
* transitions to `authenticated` without an extra round-trip from the consumer.
|
|
311
467
|
*
|
|
@@ -337,11 +493,11 @@ interface AuthorizedViewProps {
|
|
|
337
493
|
children: ReactNode;
|
|
338
494
|
/**
|
|
339
495
|
* Optional role gate. When supplied, the principal must hold AT LEAST ONE of
|
|
340
|
-
* the listed roles for the children to render
|
|
496
|
+
* the listed roles for the children to render
|
|
341
497
|
* `<AuthorizeView Roles="Admin,Manager">` (comma-separated = OR).
|
|
342
498
|
*
|
|
343
499
|
* Roles arrive on `auth.user.roles` from `/api/auth/me`. Per-role claims are
|
|
344
|
-
* only emitted for systemuser-backed principals — contacts don't have roles
|
|
500
|
+
* only emitted for systemuser-backed principals — contacts don't have roles
|
|
345
501
|
* so a role gate also implicitly limits the surface to staff users.
|
|
346
502
|
*/
|
|
347
503
|
roles?: string | readonly string[];
|
|
@@ -352,7 +508,7 @@ interface AuthorizedViewProps {
|
|
|
352
508
|
fallback?: ReactNode;
|
|
353
509
|
}
|
|
354
510
|
/**
|
|
355
|
-
* Headless auth gate —
|
|
511
|
+
* Headless auth gate — Renders
|
|
356
512
|
* {@link AuthorizedViewProps.children} only when the principal is authenticated;
|
|
357
513
|
* if {@link AuthorizedViewProps.roles} is supplied, the principal must hold at
|
|
358
514
|
* least one of the listed roles. Otherwise renders {@link AuthorizedViewProps.fallback}
|
|
@@ -365,15 +521,15 @@ interface AuthorizedViewProps {
|
|
|
365
521
|
* @example
|
|
366
522
|
* ```tsx
|
|
367
523
|
* <AuthorizedView>
|
|
368
|
-
*
|
|
524
|
+
* <Link to="/Account/Manage">Manage account</Link>
|
|
369
525
|
* </AuthorizedView>
|
|
370
526
|
*
|
|
371
527
|
* <AuthorizedView roles="SystemAdmin">
|
|
372
|
-
*
|
|
528
|
+
* <Link to="/SiteAdmin">Site admin</Link>
|
|
373
529
|
* </AuthorizedView>
|
|
374
530
|
*
|
|
375
531
|
* <AuthorizedView roles={["Admin", "Manager"]} fallback={<span>Restricted</span>}>
|
|
376
|
-
*
|
|
532
|
+
* <SensitiveTools />
|
|
377
533
|
* </AuthorizedView>
|
|
378
534
|
* ```
|
|
379
535
|
*/
|
|
@@ -469,7 +625,7 @@ interface UseFetchRecordsOptions {
|
|
|
469
625
|
}
|
|
470
626
|
/**
|
|
471
627
|
* Runs a FetchXML query. Re-runs when the `fetchXml` string changes; aborts
|
|
472
|
-
* in-flight requests on unmount. The query string is the FetchXML XML literal
|
|
628
|
+
* in-flight requests on unmount. The query string is the FetchXML XML literal
|
|
473
629
|
* the same format Dataverse natively accepts.
|
|
474
630
|
*
|
|
475
631
|
* `data.records` is the matched record list; `data.pagingCookie` and friends drive
|
|
@@ -495,10 +651,9 @@ interface UseGridDataOptions {
|
|
|
495
651
|
}
|
|
496
652
|
/**
|
|
497
653
|
* Grid-data counterpart to {@link useFetchRecords}. Calls the server's
|
|
498
|
-
* `POST /api/grids/data` endpoint, which composes the final FetchXML via
|
|
499
|
-
* shared `IFetchXmlQueryComposer` — applying search across the view's
|
|
500
|
-
* searchable columns, replacing sorts, AND-merging filters, etc.
|
|
501
|
-
* search / sort / paging semantics match the Blazor grid exactly.
|
|
654
|
+
* `POST /api/grids/data` endpoint, which composes the final FetchXML via
|
|
655
|
+
* the shared `IFetchXmlQueryComposer` — applying search across the view's
|
|
656
|
+
* searchable columns, replacing sorts, AND-merging filters, etc.
|
|
502
657
|
*
|
|
503
658
|
* Response includes both the row data (`tableRecords`, `pagingInfo`) and a
|
|
504
659
|
* server-resolved `columns` array — display names already localized, types
|
|
@@ -509,8 +664,10 @@ interface UseGridDataOptions {
|
|
|
509
664
|
* serialization — cheap, and the request is a small flat object). Aborts
|
|
510
665
|
* in-flight requests on unmount or when the request changes.
|
|
511
666
|
*
|
|
512
|
-
*
|
|
513
|
-
*
|
|
667
|
+
* At least one of `request.viewId` or `request.fetchXml` must be supplied
|
|
668
|
+
* (neither produces a 400 from the server). Both may be supplied together —
|
|
669
|
+
* the `fetchXml` is the query and the `viewId` names the view for localized
|
|
670
|
+
* column-title resolution.
|
|
514
671
|
*/
|
|
515
672
|
declare function useGridData(request: GridDataRequest, options?: UseGridDataOptions): QueryResult<GridDataResponse>;
|
|
516
673
|
|
|
@@ -532,12 +689,12 @@ interface ViewDataSourceHighlight {
|
|
|
532
689
|
* Options accepted by {@link useViewDataSource}. Split into two roles:
|
|
533
690
|
*
|
|
534
691
|
* - **Props** (forwarded straight into every request) — `viewId` /
|
|
535
|
-
*
|
|
536
|
-
*
|
|
537
|
-
*
|
|
538
|
-
* - **Initial state** (seeds once on mount, mutators take over)
|
|
539
|
-
*
|
|
540
|
-
*
|
|
692
|
+
* `fetchXml` source, `staticFilters` (always-applied, never cleared
|
|
693
|
+
* by mutators — the SubGrid relationship-filter case), `aggregations`
|
|
694
|
+
* spec, behavior knobs (`enabled`, `keepPreviousData`, `debounceMs`).
|
|
695
|
+
* - **Initial state** (seeds once on mount, mutators take over)
|
|
696
|
+
* `initialFilter`, `initialSort`, `initialSearch`, `initialPage`,
|
|
697
|
+
* `initialPageSize`, `initialHighlight`.
|
|
541
698
|
*
|
|
542
699
|
* The same datasource instance feeds a `<MainGrid>` and a
|
|
543
700
|
* `<DataverseChart>` (or two of either) — they all read the same row
|
|
@@ -546,14 +703,16 @@ interface ViewDataSourceHighlight {
|
|
|
546
703
|
*/
|
|
547
704
|
interface UseViewDataSourceOptions {
|
|
548
705
|
/**
|
|
549
|
-
* Stored Dataverse view to query.
|
|
550
|
-
*
|
|
551
|
-
*
|
|
706
|
+
* Stored Dataverse view to query. When set alongside {@link fetchXml},
|
|
707
|
+
* the FetchXML drives the query and this id only supplies the view's
|
|
708
|
+
* identity for view-specific localized column titles (no savedquery is
|
|
709
|
+
* loaded). At least one of {@link viewId} / {@link fetchXml} must be set.
|
|
552
710
|
*/
|
|
553
711
|
viewId?: string;
|
|
554
712
|
/**
|
|
555
|
-
* Caller-supplied FetchXML to query.
|
|
556
|
-
* {@link viewId}
|
|
713
|
+
* Caller-supplied FetchXML to query. Useful for custom (in-memory) views.
|
|
714
|
+
* May be combined with {@link viewId} to give such a view a stable
|
|
715
|
+
* identity for localization (see its docs).
|
|
557
716
|
*/
|
|
558
717
|
fetchXml?: string;
|
|
559
718
|
/**
|
|
@@ -699,20 +858,20 @@ interface ViewDataSource {
|
|
|
699
858
|
*
|
|
700
859
|
* ```tsx
|
|
701
860
|
* function OpportunitiesPage() {
|
|
702
|
-
*
|
|
703
|
-
*
|
|
704
|
-
*
|
|
705
|
-
*
|
|
706
|
-
*
|
|
707
|
-
*
|
|
708
|
-
*
|
|
709
|
-
*
|
|
710
|
-
*
|
|
711
|
-
*
|
|
712
|
-
*
|
|
713
|
-
*
|
|
714
|
-
*
|
|
715
|
-
*
|
|
861
|
+
* const ds = useViewDataSource({
|
|
862
|
+
* viewId: openOpportunitiesViewId,
|
|
863
|
+
* aggregations: [
|
|
864
|
+
* { groupBy: { column: 'stepname' },
|
|
865
|
+
* aggregateColumn: 'estimatedvalue',
|
|
866
|
+
* aggregate: AggregateType.Sum },
|
|
867
|
+
* ],
|
|
868
|
+
* });
|
|
869
|
+
* return (
|
|
870
|
+
* <>
|
|
871
|
+
* <DataverseChart dataSource={ds} type="bar" />
|
|
872
|
+
* <MainGrid dataSource={ds} />
|
|
873
|
+
* </>
|
|
874
|
+
* );
|
|
716
875
|
* }
|
|
717
876
|
* ```
|
|
718
877
|
*/
|
|
@@ -742,11 +901,9 @@ interface UseTablePermissionsOptions {
|
|
|
742
901
|
}
|
|
743
902
|
/**
|
|
744
903
|
* Fetches the current user's combined table-level `TableSecurityPermission`
|
|
745
|
-
* mask for one Dataverse table
|
|
746
|
-
*
|
|
747
|
-
* grid
|
|
748
|
-
* consumers can drive the same "Can the user create / delete on this
|
|
749
|
-
* table?" gates without firing a grid query.
|
|
904
|
+
* mask for one Dataverse table — exposed so consumers can drive
|
|
905
|
+
* "Can the user create / delete on this table?" gates without firing a
|
|
906
|
+
* grid query.
|
|
750
907
|
*
|
|
751
908
|
* When a `<MainGrid>` / `<SubGrid>` is on the page the grid response
|
|
752
909
|
* already carries the same value as `GridDataResponse.tablePermissions`
|
|
@@ -787,24 +944,25 @@ interface UseViewsForTableOptions {
|
|
|
787
944
|
*/
|
|
788
945
|
declare function useViewsForTable(tableLogicalName: string, options?: UseViewsForTableOptions): QueryResult<readonly ViewMetadata[]>;
|
|
789
946
|
|
|
790
|
-
type
|
|
791
|
-
interface
|
|
947
|
+
type OrganizationSettings$1 = components['schemas']['OrganizationSettings'];
|
|
948
|
+
interface UseOrganizationSettingsOptions {
|
|
792
949
|
enabled?: boolean;
|
|
793
950
|
}
|
|
794
951
|
/**
|
|
795
|
-
* Fetches the
|
|
796
|
-
*
|
|
797
|
-
* <c>IPowerPortalsProService.GetEnvironmentFileSettingsAsync</c> call.
|
|
952
|
+
* Fetches the org-wide settings (default currency, etc.) sourced from the
|
|
953
|
+
* Dataverse `organization` record.
|
|
798
954
|
*
|
|
799
|
-
* Routed through {@link
|
|
800
|
-
* concurrent callers (e.g. multiple `<
|
|
801
|
-
* share a single fetch, and the resolved value is reused
|
|
802
|
-
* mounts for the lifetime of the `PowerPortalsProClient`.
|
|
803
|
-
*
|
|
804
|
-
*
|
|
805
|
-
*
|
|
955
|
+
* Routed through {@link OrganizationSettingsCache} on the provider
|
|
956
|
+
* concurrent callers (e.g. multiple create-mode `<RecordContext>`s on the
|
|
957
|
+
* same page) share a single fetch, and the resolved value is reused
|
|
958
|
+
* across re-mounts for the lifetime of the `PowerPortalsProClient`.
|
|
959
|
+
*
|
|
960
|
+
* Primary consumer is the create-mode `<RecordContext>` seed: the framework
|
|
961
|
+
* pre-fills `record.currency` with `defaultCurrency` so `<MoneyEdit>`
|
|
962
|
+
* renders the correct symbol on brand-new records before save. Custom
|
|
963
|
+
* components that need other org-level defaults can read them here too.
|
|
806
964
|
*/
|
|
807
|
-
declare function
|
|
965
|
+
declare function useOrganizationSettings(options?: UseOrganizationSettingsOptions): QueryResult<OrganizationSettings$1>;
|
|
808
966
|
|
|
809
967
|
interface UseSupportedLocalesOptions {
|
|
810
968
|
/**
|
|
@@ -826,18 +984,16 @@ interface UseSupportedLocalesOptions {
|
|
|
826
984
|
* request on every page navigation in apps where the dropdown sits
|
|
827
985
|
* inside route-level chrome.
|
|
828
986
|
*
|
|
829
|
-
* Fallback path: when no `DefaultLocalizerProvider` is mounted (rare
|
|
987
|
+
* Fallback path: when no `DefaultLocalizerProvider` is mounted (rare
|
|
830
988
|
* consumers who wired their own i18next setup via
|
|
831
989
|
* `localizationUrl={false}`), the hook still issues its own fetch so
|
|
832
990
|
* the API works in isolation. The fallback uses the same
|
|
833
991
|
* `useAsyncResource` shape it always did, so the {@link QueryResult}
|
|
834
992
|
* surface is unchanged.
|
|
835
993
|
*
|
|
836
|
-
*
|
|
837
|
-
*
|
|
838
|
-
*
|
|
839
|
-
* manifest endpoint at `/localizations/version`. Order matches the
|
|
840
|
-
* server's configured preference, default culture first.
|
|
994
|
+
* Server-side configuration is exposed through the localization manifest
|
|
995
|
+
* endpoint at `/localizations/version`. Order matches the server's
|
|
996
|
+
* configured preference, default culture first.
|
|
841
997
|
*/
|
|
842
998
|
declare function useSupportedLocales(options?: UseSupportedLocalesOptions): QueryResult<readonly string[]>;
|
|
843
999
|
|
|
@@ -864,7 +1020,7 @@ declare function useSupportedLocales(options?: UseSupportedLocalesOptions): Quer
|
|
|
864
1020
|
*/
|
|
865
1021
|
declare function useQueryParam(name: string): string | null;
|
|
866
1022
|
|
|
867
|
-
type
|
|
1023
|
+
type OrganizationSettings = components['schemas']['OrganizationSettings'];
|
|
868
1024
|
/**
|
|
869
1025
|
* Default in-memory implementation of {@link TableMetadataCache}. Wraps
|
|
870
1026
|
* a `PowerPortalsProClient.retrieveTableMetadataAsync` call with Map-based
|
|
@@ -890,19 +1046,19 @@ declare class InMemoryViewMetadataCache implements ViewMetadataCache {
|
|
|
890
1046
|
clear(): void;
|
|
891
1047
|
}
|
|
892
1048
|
/**
|
|
893
|
-
* Default in-memory implementation of {@link
|
|
1049
|
+
* Default in-memory implementation of {@link OrganizationSettingsCache}.
|
|
894
1050
|
* Singleton-shaped: no key, just one stored value + one in-flight promise.
|
|
895
1051
|
*
|
|
896
|
-
* Implemented as a thin wrapper around the keyed {@link InMemoryCache}
|
|
897
|
-
*
|
|
898
|
-
*
|
|
899
|
-
*
|
|
1052
|
+
* Implemented as a thin wrapper around the keyed {@link InMemoryCache} with
|
|
1053
|
+
* a fixed sentinel key, so the dedup / fetch / error-eviction behaviors stay
|
|
1054
|
+
* identical to the metadata caches without re-implementing any of that
|
|
1055
|
+
* logic.
|
|
900
1056
|
*/
|
|
901
|
-
declare class
|
|
1057
|
+
declare class InMemoryOrganizationSettingsCache implements OrganizationSettingsCache {
|
|
902
1058
|
private static readonly KEY;
|
|
903
1059
|
private readonly cache;
|
|
904
1060
|
constructor(ppp: PowerPortalsProClient);
|
|
905
|
-
getAsync(): Promise<
|
|
1061
|
+
getAsync(): Promise<OrganizationSettings | null>;
|
|
906
1062
|
invalidate(): void;
|
|
907
1063
|
}
|
|
908
1064
|
/**
|
|
@@ -993,17 +1149,17 @@ interface MainContextValue {
|
|
|
993
1149
|
* Transactionally saves the entire descendant subtree:
|
|
994
1150
|
*
|
|
995
1151
|
* 1. Calls {@link MainContextProps.onBeforeSave} (if wired). Throwing
|
|
996
|
-
*
|
|
1152
|
+
* aborts the save before any server call.
|
|
997
1153
|
* 2. Runs {@link validate} across descendants; returns early without
|
|
998
|
-
*
|
|
1154
|
+
* saving when any descendant reports invalid.
|
|
999
1155
|
* 3. Collects {@link MainContextDescendant.getRequests} from every
|
|
1000
|
-
*
|
|
1156
|
+
* registered descendant.
|
|
1001
1157
|
* 4. If non-empty, ships the combined array in one
|
|
1002
|
-
*
|
|
1003
|
-
*
|
|
1158
|
+
* `executeMultipleAsync` round-trip so the operations land
|
|
1159
|
+
* transactionally on the server.
|
|
1004
1160
|
* 5. Calls {@link refreshAll} so the local state picks up server-applied
|
|
1005
|
-
*
|
|
1006
|
-
*
|
|
1161
|
+
* side-effects (computed columns, plugin defaults, the modifiedon
|
|
1162
|
+
* timestamp, etc.).
|
|
1007
1163
|
*
|
|
1008
1164
|
* Throws on the first server-side failure; later steps are skipped.
|
|
1009
1165
|
*/
|
|
@@ -1034,10 +1190,9 @@ interface MainContextValue {
|
|
|
1034
1190
|
* append extra requests before calling
|
|
1035
1191
|
* `IPowerPortalsPro.executeMultipleAsync` directly).
|
|
1036
1192
|
*
|
|
1037
|
-
*
|
|
1038
|
-
*
|
|
1039
|
-
*
|
|
1040
|
-
* is the escape hatch for the rarer dry-run / merge-with-extras case.
|
|
1193
|
+
* Walks the registered grids, child contexts, and M2M editors. Consumers
|
|
1194
|
+
* that just want to save should call {@link saveAll}; this is the escape
|
|
1195
|
+
* hatch for the rarer dry-run / merge-with-extras case.
|
|
1041
1196
|
*/
|
|
1042
1197
|
readonly getRequests: () => OrganizationRequest[];
|
|
1043
1198
|
/**
|
|
@@ -1100,10 +1255,10 @@ interface MainContextProps {
|
|
|
1100
1255
|
* Resolution rules:
|
|
1101
1256
|
* - `true` / `false` — explicit override at this level.
|
|
1102
1257
|
* - `undefined` (default) — inherit from the parent
|
|
1103
|
-
*
|
|
1104
|
-
*
|
|
1105
|
-
*
|
|
1106
|
-
*
|
|
1258
|
+
* {@link MainContext} / {@link RecordContext}, falling back to `true` at
|
|
1259
|
+
* the root. Set `false` on the outer context of e.g. a demo site to
|
|
1260
|
+
* suppress the prompt across the whole subtree without touching every
|
|
1261
|
+
* nested context.
|
|
1107
1262
|
*
|
|
1108
1263
|
* Only the **top-most** MainContext / RecordContext on the page actually
|
|
1109
1264
|
* registers the listener — when contexts nest, the inner ones skip
|
|
@@ -1126,8 +1281,8 @@ interface MainContextProps {
|
|
|
1126
1281
|
* Resolution rules (same as {@link warnOnUnsavedChanges}):
|
|
1127
1282
|
* - `true` / `false` — explicit override at this level.
|
|
1128
1283
|
* - `undefined` (default) — inherit from the parent
|
|
1129
|
-
*
|
|
1130
|
-
*
|
|
1284
|
+
* {@link MainContext} / {@link RecordContext}, falling back to `true`
|
|
1285
|
+
* at the root.
|
|
1131
1286
|
*/
|
|
1132
1287
|
forceSuccessfulValidationBeforeSave?: boolean;
|
|
1133
1288
|
}
|
|
@@ -1142,14 +1297,12 @@ interface MainContextProps {
|
|
|
1142
1297
|
* register with their nearest ancestor.
|
|
1143
1298
|
*
|
|
1144
1299
|
* Deferred surface (and how to layer it on later):
|
|
1145
|
-
* - **Dirty tracking.**
|
|
1146
|
-
*
|
|
1147
|
-
*
|
|
1148
|
-
*
|
|
1149
|
-
* plus an aggregate getter on `MainContextValue` is the natural extension.
|
|
1300
|
+
* - **Dirty tracking.** Consumers bring their own form layer (react-hook-form,
|
|
1301
|
+
* formik, vanilla state). When the dirty story solidifies in a project, an
|
|
1302
|
+
* `isDirty: () => boolean` getter on `MainContextDescendant` plus an aggregate
|
|
1303
|
+
* getter on `MainContextValue` is the natural extension.
|
|
1150
1304
|
* - **Unsaved-changes warning** dialog on navigation. Driven by dirty tracking.
|
|
1151
1305
|
* - **Validation orchestration**. Same — needs the form layer.
|
|
1152
|
-
* - **Persistent state across server↔WASM**. N/A in pure React.
|
|
1153
1306
|
*/
|
|
1154
1307
|
declare function MainContext({ children, onBeforeSave, warnOnUnsavedChanges, forceSuccessfulValidationBeforeSave, }: MainContextProps): react_jsx_runtime.JSX.Element;
|
|
1155
1308
|
/**
|
|
@@ -1162,12 +1315,11 @@ declare function useMainContext(): MainContextValue | null;
|
|
|
1162
1315
|
/**
|
|
1163
1316
|
* Provides an existing {@link MainContextValue} to a subtree. Used by
|
|
1164
1317
|
* {@link RecordContext} to expose itself as a `MainContext` for nested
|
|
1165
|
-
* descendants
|
|
1166
|
-
*
|
|
1167
|
-
* components compose multiple `MainContext` levels.
|
|
1318
|
+
* descendants — keeps the raw `MainContextContext` internal while still
|
|
1319
|
+
* letting framework components compose multiple `MainContext` levels.
|
|
1168
1320
|
*
|
|
1169
|
-
* Not generally needed by application code — use `<MainContext>` instead,
|
|
1170
|
-
* builds the value internally.
|
|
1321
|
+
* Not generally needed by application code — use `<MainContext>` instead,
|
|
1322
|
+
* which builds the value internally.
|
|
1171
1323
|
*/
|
|
1172
1324
|
declare function MainContextProvider({ value, children, }: {
|
|
1173
1325
|
value: MainContextValue;
|
|
@@ -1210,11 +1362,10 @@ interface RecordContextValue {
|
|
|
1210
1362
|
* (when dirty) followed by each nested descendant's `getRequests()`, in
|
|
1211
1363
|
* registration order. Returns an empty array when nothing is dirty.
|
|
1212
1364
|
*
|
|
1213
|
-
*
|
|
1214
|
-
*
|
|
1215
|
-
*
|
|
1216
|
-
*
|
|
1217
|
-
* Consumers that just want to persist should call {@link save}.
|
|
1365
|
+
* Use for previewing the payload {@link save} would ship, for dry-run
|
|
1366
|
+
* UIs, or to merge the records into a custom `executeMultiple` batch
|
|
1367
|
+
* alongside consumer-supplied requests. Consumers that just want to
|
|
1368
|
+
* persist should call {@link save}.
|
|
1218
1369
|
*/
|
|
1219
1370
|
readonly getRequests: () => OrganizationRequest[];
|
|
1220
1371
|
/**
|
|
@@ -1315,7 +1466,7 @@ interface RecordContextValue {
|
|
|
1315
1466
|
}
|
|
1316
1467
|
/**
|
|
1317
1468
|
* `RecordContext` extends {@link MainContextProps} because every `RecordContext`
|
|
1318
|
-
* conceptually IS-A `MainContext` —
|
|
1469
|
+
* conceptually IS-A `MainContext` — literally
|
|
1319
1470
|
* inherits from `MainContext.razor.cs` and `override`s `IsDirty` to add the
|
|
1320
1471
|
* record's own dirty state on top of the base aggregation. Inheriting the props
|
|
1321
1472
|
* means `onBeforeSave` (and any future cross-cutting `MainContextProps`) is
|
|
@@ -1420,8 +1571,7 @@ interface RecordContextProps extends MainContextProps {
|
|
|
1420
1571
|
}
|
|
1421
1572
|
/**
|
|
1422
1573
|
* Loads a single Dataverse record and provides it to descendants via React
|
|
1423
|
-
* context
|
|
1424
|
-
* {@link useRecordContext} to read the record + status.
|
|
1574
|
+
* context. Children call {@link useRecordContext} to read the record + status.
|
|
1425
1575
|
*
|
|
1426
1576
|
* Also acts as a `MainContext` for its own subtree — nested grids, M2M editors,
|
|
1427
1577
|
* and child `<RecordContext>`s register with this `RecordContext` instead of
|
|
@@ -1435,18 +1585,10 @@ interface RecordContextProps extends MainContextProps {
|
|
|
1435
1585
|
* Without a parent, `save()` and `reload()` are still callable directly from
|
|
1436
1586
|
* descendants via the context.
|
|
1437
1587
|
*
|
|
1438
|
-
*
|
|
1439
|
-
* this is the headless coordination skeleton):
|
|
1440
|
-
* - **New-record creation** (id absent → empty TableRecord). Will need a
|
|
1441
|
-
* `mode: "edit" | "create"` discriminator and dispatching `createRecordAsync`
|
|
1442
|
-
* instead of `updateRecordAsync` from `save()`.
|
|
1443
|
-
* - **Dirty tracking + EditContext-style validation**. Tied to the form layer.
|
|
1588
|
+
* Deferred surface (the headless coordination skeleton; rounded out later):
|
|
1444
1589
|
* - **`OnBeforeSave` / `OnBeforeDelete`** cancellable callbacks at this level
|
|
1445
|
-
*
|
|
1590
|
+
* (MainContext already exposes `onBeforeSave`).
|
|
1446
1591
|
* - **Delete handler** with confirmation flow.
|
|
1447
|
-
* - **URL query-parameter reading** (Blazor's `QueryParameterName`). Consumers can
|
|
1448
|
-
* pull the id from `useSearchParams()` themselves and pass it as the `id` prop.
|
|
1449
|
-
* - **PersistentComponentState** for server→WASM bridging. N/A in pure React.
|
|
1450
1592
|
*/
|
|
1451
1593
|
/**
|
|
1452
1594
|
* Wrapper that auto-mounts a {@link ValidationProvider} around the inner
|
|
@@ -1467,10 +1609,10 @@ declare function RecordContext(props: RecordContextProps): react_jsx_runtime.JSX
|
|
|
1467
1609
|
* import { QueryStatus, useRecordContext } from '@powerportalspro/react';
|
|
1468
1610
|
*
|
|
1469
1611
|
* function ContactDetails() {
|
|
1470
|
-
*
|
|
1471
|
-
*
|
|
1472
|
-
*
|
|
1473
|
-
*
|
|
1612
|
+
* const { status, record } = useRecordContext();
|
|
1613
|
+
* if (status === QueryStatus.Loading) return <Spinner />;
|
|
1614
|
+
* if (status === QueryStatus.Error) return <ErrorBanner />;
|
|
1615
|
+
* return <h1>{record!.formattedValues?.name}</h1>;
|
|
1474
1616
|
* }
|
|
1475
1617
|
* ```
|
|
1476
1618
|
*/
|
|
@@ -1495,16 +1637,14 @@ interface LookupRecordContextProps {
|
|
|
1495
1637
|
* `$type: 6`) — the component reads the lookup's `tableName` + `value`
|
|
1496
1638
|
* and spawns a nested `<RecordContext>` for the referenced record.
|
|
1497
1639
|
*
|
|
1498
|
-
* Required.
|
|
1499
|
-
* `ColumnName` parameter.
|
|
1640
|
+
* Required.
|
|
1500
1641
|
*/
|
|
1501
1642
|
columnName: string;
|
|
1502
1643
|
/**
|
|
1503
1644
|
* Optional pre-save cancellable hook forwarded to the nested
|
|
1504
1645
|
* `<RecordContext>`. Throwing (or returning a rejected promise) from
|
|
1505
1646
|
* this callback aborts the save before any server call — the same
|
|
1506
|
-
* semantic as `<RecordContext onBeforeSave={…}>` directly.
|
|
1507
|
-
* Blazor's `LookupRecordContext.OnBeforeSave` cancellable hook.
|
|
1647
|
+
* semantic as `<RecordContext onBeforeSave={…}>` directly.
|
|
1508
1648
|
*/
|
|
1509
1649
|
onBeforeSave?: () => void | Promise<void>;
|
|
1510
1650
|
/**
|
|
@@ -1519,16 +1659,15 @@ interface LookupRecordContextProps {
|
|
|
1519
1659
|
/**
|
|
1520
1660
|
* When `false`, renders nothing. Defaults to `true`. Useful for
|
|
1521
1661
|
* conditionally hiding the section without unmounting the
|
|
1522
|
-
* declaration.
|
|
1523
|
-
* components.
|
|
1662
|
+
* declaration.
|
|
1524
1663
|
*/
|
|
1525
1664
|
isVisible?: boolean;
|
|
1526
1665
|
}
|
|
1527
1666
|
/**
|
|
1528
1667
|
* Branches off into a nested `<RecordContext>` for the record referenced
|
|
1529
|
-
* by a lookup column on the surrounding `<RecordContext>`.
|
|
1530
|
-
*
|
|
1531
|
-
*
|
|
1668
|
+
* by a lookup column on the surrounding `<RecordContext>`. A thin
|
|
1669
|
+
* wrapper that resolves the lookup value, gates on its presence, and
|
|
1670
|
+
* spawns the nested context.
|
|
1532
1671
|
*
|
|
1533
1672
|
* Edit components inside the lookup context bind to columns on the
|
|
1534
1673
|
* LOOKED-UP record's table, not the parent's. Changes flow through the
|
|
@@ -1538,46 +1677,44 @@ interface LookupRecordContextProps {
|
|
|
1538
1677
|
* `<RecordContext>`-as-MainContext) and its pending edits join the
|
|
1539
1678
|
* single transactional `executeMultiple` batch on save.
|
|
1540
1679
|
*
|
|
1541
|
-
* **Conditional render
|
|
1542
|
-
*
|
|
1543
|
-
*
|
|
1544
|
-
*
|
|
1545
|
-
*
|
|
1546
|
-
*
|
|
1547
|
-
*
|
|
1548
|
-
*
|
|
1680
|
+
* **Conditional render:** the nested `<RecordContext>` is only
|
|
1681
|
+
* instantiated when the lookup actually has a value (non-null +
|
|
1682
|
+
* non-empty-GUID + has `tableName`). Empty lookups render nothing
|
|
1683
|
+
* avoids spinning up nested contexts, EditContext validators,
|
|
1684
|
+
* descendant registrations, etc. for every empty lookup column on a
|
|
1685
|
+
* form. With ~10 lookups on a complex form, the per-render lifecycle
|
|
1686
|
+
* overhead is large enough to produce a measurable freeze without this
|
|
1687
|
+
* guard.
|
|
1549
1688
|
*
|
|
1550
1689
|
* ```tsx
|
|
1551
1690
|
* <RecordContext table="account" id={accountId}>
|
|
1552
|
-
*
|
|
1553
|
-
*
|
|
1554
|
-
*
|
|
1555
|
-
*
|
|
1556
|
-
*
|
|
1557
|
-
*
|
|
1558
|
-
*
|
|
1559
|
-
*
|
|
1560
|
-
*
|
|
1561
|
-
*
|
|
1562
|
-
*
|
|
1563
|
-
*
|
|
1564
|
-
*
|
|
1565
|
-
*
|
|
1566
|
-
*
|
|
1691
|
+
* <Section>
|
|
1692
|
+
* <SectionColumn header={<Text>Account</Text>}>
|
|
1693
|
+
* <TextEdit columnName="name" />
|
|
1694
|
+
* <TextEdit columnName="accountnumber" />
|
|
1695
|
+
* </SectionColumn>
|
|
1696
|
+
*
|
|
1697
|
+
* <SectionColumn header={<Text>Primary contact</Text>}>
|
|
1698
|
+
* <LookupRecordContext columnName="primarycontactid">
|
|
1699
|
+
* {/* These edits bind to the linked CONTACT, not the account *\/}
|
|
1700
|
+
* <TextEdit columnName="firstname" />
|
|
1701
|
+
* <TextEdit columnName="lastname" />
|
|
1702
|
+
* <TextEdit columnName="emailaddress1" type="email" />
|
|
1703
|
+
* </LookupRecordContext>
|
|
1704
|
+
* </SectionColumn>
|
|
1705
|
+
* </Section>
|
|
1567
1706
|
* </RecordContext>
|
|
1568
1707
|
* ```
|
|
1569
1708
|
*
|
|
1570
1709
|
* Renders `null` when:
|
|
1571
|
-
*
|
|
1572
|
-
*
|
|
1573
|
-
*
|
|
1574
|
-
*
|
|
1710
|
+
* - the surrounding `<RecordContext>` hasn't loaded yet,
|
|
1711
|
+
* - the parent column doesn't carry a `LookupValue`,
|
|
1712
|
+
* - the lookup is the empty GUID (Dataverse's "no value" sentinel), or
|
|
1713
|
+
* - the lookup is missing its `tableName`.
|
|
1575
1714
|
*
|
|
1576
|
-
* `<LookupRecordContext>`
|
|
1577
|
-
*
|
|
1578
|
-
*
|
|
1579
|
-
* change the lookup value programmatically; `<LookupRecordContext>` is
|
|
1580
|
-
* pure read-then-branch.
|
|
1715
|
+
* `<LookupRecordContext>` is read-then-branch only — consumers who want
|
|
1716
|
+
* to change the lookup value programmatically use
|
|
1717
|
+
* `useLookupColumn(columnName)` from the parent context instead.
|
|
1581
1718
|
*/
|
|
1582
1719
|
declare function LookupRecordContext({ columnName, onBeforeSave, children, isVisible, }: LookupRecordContextProps): react_jsx_runtime.JSX.Element | null;
|
|
1583
1720
|
|
|
@@ -1590,10 +1727,9 @@ type ColumnMetadataBase = components['schemas']['ColumnMetadataBase'];
|
|
|
1590
1727
|
* - the column doesn't exist on the table.
|
|
1591
1728
|
*
|
|
1592
1729
|
* Edit components use this to auto-resolve defaults (`maxLength`, `min`,
|
|
1593
|
-
* `max`, `precision`, `required`, `readOnly`) when consumer-passed props
|
|
1594
|
-
* absent. Pass-through props always win —
|
|
1595
|
-
*
|
|
1596
|
-
* defaults when the consumer hasn't set them explicitly).
|
|
1730
|
+
* `max`, `precision`, `required`, `readOnly`) when consumer-passed props
|
|
1731
|
+
* are absent. Pass-through props always win — metadata-derived defaults
|
|
1732
|
+
* only fill the slots the consumer left unset.
|
|
1597
1733
|
*
|
|
1598
1734
|
* Throws if not used inside a `<RecordContext>`, since column metadata only
|
|
1599
1735
|
* makes sense relative to a record's table.
|
|
@@ -1608,7 +1744,7 @@ declare function useColumnMetadata(columnName: string): ColumnMetadataBase | und
|
|
|
1608
1744
|
* map for tests, or a server-driven RPC localizer all work the same way.
|
|
1609
1745
|
*
|
|
1610
1746
|
* Args use positional indexing (`args[0]` → `{0}` in the template) to match
|
|
1611
|
-
* the existing
|
|
1747
|
+
* the existing JSON format — `.NET String.Format`
|
|
1612
1748
|
* placeholders. Consumers using a named-args lib (e.g. i18next's `{{name}}`)
|
|
1613
1749
|
* adapt at the boundary.
|
|
1614
1750
|
*/
|
|
@@ -1616,7 +1752,7 @@ interface Localizer {
|
|
|
1616
1752
|
t(key: string, args?: readonly unknown[]): string;
|
|
1617
1753
|
}
|
|
1618
1754
|
/**
|
|
1619
|
-
* Reads the nearest {@link Localizer}. Throws when called outside a provider
|
|
1755
|
+
* Reads the nearest {@link Localizer}. Throws when called outside a provider
|
|
1620
1756
|
* mirrors `useDialogService`'s strict behavior. The framework auto-mounts a
|
|
1621
1757
|
* default `<DefaultLocalizerProvider>` inside `<PowerPortalsProProvider>`, so
|
|
1622
1758
|
* this only fails when neither is present (typically a misconfigured test).
|
|
@@ -1629,11 +1765,9 @@ declare function useLocalizer(): Localizer;
|
|
|
1629
1765
|
declare function useT(): Localizer['t'];
|
|
1630
1766
|
/**
|
|
1631
1767
|
* Returns a {@link Localizer.t} function with every key automatically
|
|
1632
|
-
* prepended with `{prefix}.`.
|
|
1633
|
-
*
|
|
1634
|
-
*
|
|
1635
|
-
* framework's class-scoped keys) and you don't want to repeat the
|
|
1636
|
-
* prefix at every call site.
|
|
1768
|
+
* prepended with `{prefix}.`. Use when a component consumes strings from
|
|
1769
|
+
* a known namespace and you don't want to repeat the prefix at every
|
|
1770
|
+
* call site.
|
|
1637
1771
|
*
|
|
1638
1772
|
* Pure sugar over `useT()` — relies on the same auto-mounted
|
|
1639
1773
|
* `<DefaultLocalizerProvider>` and inherits all of its behavior
|
|
@@ -1643,12 +1777,10 @@ declare function useT(): Localizer['t'];
|
|
|
1643
1777
|
*
|
|
1644
1778
|
* @example
|
|
1645
1779
|
* ```tsx
|
|
1646
|
-
* const t = usePrefixedT(
|
|
1647
|
-
*
|
|
1648
|
-
* );
|
|
1649
|
-
* t('OfficeColor.0');
|
|
1780
|
+
* const t = usePrefixedT('components.MyApp.Pages.Editors.TextEditDemoPage');
|
|
1781
|
+
* t('title');
|
|
1650
1782
|
* // → looks up
|
|
1651
|
-
* //
|
|
1783
|
+
* // 'components.MyApp.Pages.Editors.TextEditDemoPage.title'
|
|
1652
1784
|
* ```
|
|
1653
1785
|
*
|
|
1654
1786
|
* The returned function is stable per `prefix` value (memoized via
|
|
@@ -1714,12 +1846,12 @@ declare function useLocalizationPrefetcher(): LocalizationPrefetcher | null;
|
|
|
1714
1846
|
* the strings are ready.
|
|
1715
1847
|
*
|
|
1716
1848
|
* Accepts prefix or full-key shapes:
|
|
1717
|
-
*
|
|
1718
|
-
*
|
|
1719
|
-
*
|
|
1720
|
-
*
|
|
1721
|
-
*
|
|
1722
|
-
*
|
|
1849
|
+
* - `tables.{tablename}` (token) → loads `tables.<tablename>.*` strings
|
|
1850
|
+
* - `tables.account.label` (key) → coerced to `tables.account`
|
|
1851
|
+
* - `views.{viewId}` (token) → loads `views.<viewId>.*` strings
|
|
1852
|
+
* - `tables.account.views.{viewId}.foo` (key) → coerced to `views.<viewId>`
|
|
1853
|
+
* - Anything else (`app.*`, `components.*`) → silently dropped; covered
|
|
1854
|
+
* by the default bundle loaded on app boot.
|
|
1723
1855
|
*
|
|
1724
1856
|
* Re-fires only when `prefixes` changes by VALUE — passing a fresh array
|
|
1725
1857
|
* with the same content each render doesn't requeue. Already-fetched
|
|
@@ -1733,8 +1865,8 @@ declare function useLocalizationPrefetcher(): LocalizationPrefetcher | null;
|
|
|
1733
1865
|
* @example
|
|
1734
1866
|
* ```tsx
|
|
1735
1867
|
* function MyAccountPage() {
|
|
1736
|
-
*
|
|
1737
|
-
*
|
|
1868
|
+
* useLocalization(['tables.account', 'tables.contact']);
|
|
1869
|
+
* return <Form>...</Form>;
|
|
1738
1870
|
* }
|
|
1739
1871
|
* ```
|
|
1740
1872
|
*/
|
|
@@ -1752,9 +1884,9 @@ declare function useLocalization(prefixes: readonly string[]): void;
|
|
|
1752
1884
|
* @example
|
|
1753
1885
|
* ```tsx
|
|
1754
1886
|
* function MyForm() {
|
|
1755
|
-
*
|
|
1756
|
-
*
|
|
1757
|
-
*
|
|
1887
|
+
* const ready = useLocalizationLoaded(['tables.account']);
|
|
1888
|
+
* if (!ready) return <Spinner />;
|
|
1889
|
+
* return <Form>...</Form>;
|
|
1758
1890
|
* }
|
|
1759
1891
|
* ```
|
|
1760
1892
|
*/
|
|
@@ -1770,9 +1902,8 @@ declare function LocalizerProvider({ value, children, }: {
|
|
|
1770
1902
|
children: ReactNode;
|
|
1771
1903
|
}): react_jsx_runtime.JSX.Element;
|
|
1772
1904
|
/**
|
|
1773
|
-
* Flattens a nested object
|
|
1774
|
-
*
|
|
1775
|
-
* localizer's lookup).
|
|
1905
|
+
* Flattens a nested object into a flat `key.path → value` map. Drops
|
|
1906
|
+
* non-string leaves (no use for them in the localizer's lookup).
|
|
1776
1907
|
*/
|
|
1777
1908
|
declare function flattenStrings(obj: Record<string, unknown>, prefix?: string): Record<string, string>;
|
|
1778
1909
|
/**
|
|
@@ -1817,9 +1948,9 @@ declare function createLocalizer(strings: Record<string, string>, options?: Crea
|
|
|
1817
1948
|
declare function resolveLocalizationUrl(template: string, locale: string): string;
|
|
1818
1949
|
/**
|
|
1819
1950
|
* Cookie name ASP.NET Core's `CookieRequestCultureProvider` uses to persist
|
|
1820
|
-
* the active culture.
|
|
1821
|
-
*
|
|
1822
|
-
*
|
|
1951
|
+
* the active culture. Reading and writing this cookie keeps the React app
|
|
1952
|
+
* in sync with any same-origin server-rendered surface that reads its
|
|
1953
|
+
* culture from the same source.
|
|
1823
1954
|
*/
|
|
1824
1955
|
declare const ASP_NET_CULTURE_COOKIE = ".AspNetCore.Culture";
|
|
1825
1956
|
/**
|
|
@@ -1833,10 +1964,9 @@ declare const ASP_NET_CULTURE_COOKIE = ".AspNetCore.Culture";
|
|
|
1833
1964
|
declare function getAspNetCultureCookie(): string | null;
|
|
1834
1965
|
/**
|
|
1835
1966
|
* Writes the ASP.NET Core culture cookie with both `c` and `uic` segments
|
|
1836
|
-
* set to the same value.
|
|
1837
|
-
*
|
|
1838
|
-
*
|
|
1839
|
-
* origin (and vice versa).
|
|
1967
|
+
* set to the same value. A React-side locale change immediately affects
|
|
1968
|
+
* subsequent same-origin server-rendered pages that read their culture
|
|
1969
|
+
* from the same cookie (and vice versa).
|
|
1840
1970
|
*
|
|
1841
1971
|
* Defaults to `path=/`, 1-year expiry, `SameSite=Lax`. Safe to call in
|
|
1842
1972
|
* non-browser environments (no-op).
|
|
@@ -1846,7 +1976,7 @@ declare function setAspNetCultureCookie(culture: string, options?: {
|
|
|
1846
1976
|
maxAgeSeconds?: number;
|
|
1847
1977
|
}): void;
|
|
1848
1978
|
/**
|
|
1849
|
-
* Default regex matching a locale code at the start of `window.location.pathname`
|
|
1979
|
+
* Default regex matching a locale code at the start of `window.location.pathname`
|
|
1850
1980
|
* shapes like `/en`, `/en/`, `/en-US/page`, `/fr-CA/path/x`. Captures the
|
|
1851
1981
|
* locale code in group 1. Only 2-letter primary tags + optional 2–4-letter
|
|
1852
1982
|
* subtag (script / region) are recognized; arbitrary path segments don't
|
|
@@ -1861,16 +1991,52 @@ declare const DEFAULT_URL_LOCALE_PATTERN: RegExp;
|
|
|
1861
1991
|
* Safe to call in non-browser environments (returns `null`).
|
|
1862
1992
|
*/
|
|
1863
1993
|
declare function getLocaleFromUrlPath(pattern?: RegExp): string | null;
|
|
1994
|
+
/**
|
|
1995
|
+
* The server's configured URL-culture strategy, surfaced to the client through
|
|
1996
|
+
* the localization manifest (`urlCultureStrategy`). Mirrors the C#
|
|
1997
|
+
* `PowerPortalsPro.Web.Options.UrlCultureStrategy` enum names:
|
|
1998
|
+
*
|
|
1999
|
+
* - `PathPrefix` — default locale bare (`/contacts`), others prefixed (`/fr/contacts`).
|
|
2000
|
+
* - `PathPrefixAll` — every locale prefixed, including the default (`/en/contacts`).
|
|
2001
|
+
* - `CookieOnly` — the locale never appears in the URL; switching is in-place.
|
|
2002
|
+
*/
|
|
2003
|
+
type UrlCultureStrategyName = 'PathPrefix' | 'PathPrefixAll' | 'CookieOnly';
|
|
2004
|
+
/**
|
|
2005
|
+
* Whether a URL for `locale` carries a `/{locale}` path prefix under `strategy`.
|
|
2006
|
+
* Runtime mirror of the server-side `CultureUrls.ShouldPrefix` so client-built
|
|
2007
|
+
* links match the shape the LocalizationMiddleware actually serves.
|
|
2008
|
+
*/
|
|
2009
|
+
declare function shouldPrefixLocale(strategy: UrlCultureStrategyName, locale: string, defaultLocale: string): boolean;
|
|
2010
|
+
/**
|
|
2011
|
+
* Removes a leading `/{locale}` segment from `pathname` when that segment is one
|
|
2012
|
+
* of `supportedLocales`. Returns the "cultureless" path (always leading-slash,
|
|
2013
|
+
* `/` for root). Mirror of the server-side `StripCulturePrefix`.
|
|
2014
|
+
*/
|
|
2015
|
+
declare function stripLocalePrefix(pathname: string, supportedLocales: readonly string[]): string;
|
|
2016
|
+
/**
|
|
2017
|
+
* Builds the path (leading slash, no origin) at which `locale` serves the current
|
|
2018
|
+
* page under `strategy`, given the current `pathname` (which may already carry a
|
|
2019
|
+
* locale prefix) and the server's `supportedLocales`. Runtime mirror of the
|
|
2020
|
+
* server-side `CultureUrls.BuildPath`. Use it to compute the navigation target
|
|
2021
|
+
* when switching locale under a prefix strategy.
|
|
2022
|
+
*/
|
|
2023
|
+
declare function buildLocalePath(options: {
|
|
2024
|
+
strategy: UrlCultureStrategyName;
|
|
2025
|
+
locale: string;
|
|
2026
|
+
defaultLocale: string;
|
|
2027
|
+
pathname: string;
|
|
2028
|
+
supportedLocales: readonly string[];
|
|
2029
|
+
}): string;
|
|
1864
2030
|
/**
|
|
1865
2031
|
* Resolves the active locale from common sources, in order of precedence:
|
|
1866
2032
|
*
|
|
1867
2033
|
* 1. URL path segment (`/en/...`) — picked up via {@link getLocaleFromUrlPath}
|
|
1868
|
-
*
|
|
2034
|
+
* when `matchUrl` is `true` (default).
|
|
1869
2035
|
* 2. ASP.NET culture cookie (`.AspNetCore.Culture`) — picked up via
|
|
1870
|
-
*
|
|
2036
|
+
* {@link getAspNetCultureCookie}.
|
|
1871
2037
|
* 3. `navigator.language` — when `matchBrowser` is `true` (default), strips
|
|
1872
|
-
*
|
|
1873
|
-
*
|
|
2038
|
+
* the region (e.g. `en-US` → `en`) for compatibility with bundle locale
|
|
2039
|
+
* codes which are typically primary-tag only.
|
|
1874
2040
|
* 4. The supplied `fallback` (default `'en'`).
|
|
1875
2041
|
*
|
|
1876
2042
|
* Used by `<LocaleProvider>` for auto-detection; also exported for consumer
|
|
@@ -1888,6 +2054,21 @@ interface LocaleState {
|
|
|
1888
2054
|
/** Replace the active locale. Triggers re-fetch of localization JSONs. */
|
|
1889
2055
|
readonly setLocale: (locale: string) => void;
|
|
1890
2056
|
}
|
|
2057
|
+
/**
|
|
2058
|
+
* Reads the server's configured {@link UrlCultureStrategyName} from the
|
|
2059
|
+
* {@link LocalizationManifestContext} (populated by
|
|
2060
|
+
* {@link DefaultLocalizerProvider}'s manifest fetch). Returns `undefined`
|
|
2061
|
+
* before the manifest lands, or when no provider is mounted. Consumers
|
|
2062
|
+
* building a custom locale switcher use this to decide whether to navigate
|
|
2063
|
+
* to a `/{locale}` URL or switch in place.
|
|
2064
|
+
*/
|
|
2065
|
+
declare function useUrlCultureStrategy(): UrlCultureStrategyName | undefined;
|
|
2066
|
+
/**
|
|
2067
|
+
* Reads the server's default locale — the first entry of the manifest's
|
|
2068
|
+
* supported-locale list (the server emits it default-culture-first). Returns
|
|
2069
|
+
* `undefined` before the manifest lands, or when no provider is mounted.
|
|
2070
|
+
*/
|
|
2071
|
+
declare function useDefaultLocale(): string | undefined;
|
|
1891
2072
|
/**
|
|
1892
2073
|
* Reads the active locale state, falling back to `{ locale: 'en' }` when no
|
|
1893
2074
|
* `<LocaleProvider>` is mounted. Apps that don't need locale switching can
|
|
@@ -1916,11 +2097,10 @@ interface LocaleProviderProps {
|
|
|
1916
2097
|
*/
|
|
1917
2098
|
urlPattern?: RegExp | null;
|
|
1918
2099
|
/**
|
|
1919
|
-
* Persist locale changes to the ASP.NET culture cookie
|
|
1920
|
-
*
|
|
1921
|
-
* `
|
|
1922
|
-
*
|
|
1923
|
-
* (e.g. via the `onLocaleChange` callback).
|
|
2100
|
+
* Persist locale changes to the ASP.NET culture cookie. Default `true` —
|
|
2101
|
+
* keeps any same-origin server-rendered page in sync with the React-side
|
|
2102
|
+
* locale. Pass `false` to manage persistence yourself (e.g. via the
|
|
2103
|
+
* `onLocaleChange` callback).
|
|
1924
2104
|
*/
|
|
1925
2105
|
persistToCookie?: boolean;
|
|
1926
2106
|
/**
|
|
@@ -1948,9 +2128,9 @@ interface LocaleProviderProps {
|
|
|
1948
2128
|
* Example:
|
|
1949
2129
|
* ```tsx
|
|
1950
2130
|
* <LocaleProvider initialLocale="en">
|
|
1951
|
-
*
|
|
1952
|
-
*
|
|
1953
|
-
*
|
|
2131
|
+
* <PowerPortalsProProvider>
|
|
2132
|
+
* <App /> {/* useLocale() inside returns { locale: 'en', setLocale: ... } *\/}
|
|
2133
|
+
* </PowerPortalsProProvider>
|
|
1954
2134
|
* </LocaleProvider>
|
|
1955
2135
|
* ```
|
|
1956
2136
|
*/
|
|
@@ -1969,7 +2149,7 @@ interface DefaultLocalizerProviderProps {
|
|
|
1969
2149
|
*/
|
|
1970
2150
|
urls?: readonly string[];
|
|
1971
2151
|
/**
|
|
1972
|
-
* @deprecated Use {@link urls} instead. Kept for backwards compatibility
|
|
2152
|
+
* @deprecated Use {@link urls} instead. Kept for backwards compatibility
|
|
1973
2153
|
* when set, treated as `urls: [url]`.
|
|
1974
2154
|
*/
|
|
1975
2155
|
url?: string;
|
|
@@ -2054,9 +2234,9 @@ declare function DefaultLocalizerProvider({ urls, url, onMissingKey, prefixes, c
|
|
|
2054
2234
|
* dismissed the dialog (clicked the secondary button on a confirmation,
|
|
2055
2235
|
* pressed Escape, clicked the backdrop, or otherwise rejected the action).
|
|
2056
2236
|
*
|
|
2057
|
-
*
|
|
2058
|
-
*
|
|
2059
|
-
*
|
|
2237
|
+
* Kept as an object rather than a naked boolean so we can extend with
|
|
2238
|
+
* `data?` etc. when custom-content dialogs land without a wire-breaking
|
|
2239
|
+
* change.
|
|
2060
2240
|
*/
|
|
2061
2241
|
interface DialogResult {
|
|
2062
2242
|
/** True when the user dismissed/cancelled, false when they confirmed. */
|
|
@@ -2077,19 +2257,17 @@ interface ConfirmationDialogOptions extends DialogOptions {
|
|
|
2077
2257
|
secondaryText?: string;
|
|
2078
2258
|
}
|
|
2079
2259
|
/**
|
|
2080
|
-
* Headless dialog service contract
|
|
2081
|
-
*
|
|
2082
|
-
*
|
|
2083
|
-
*
|
|
2084
|
-
*
|
|
2085
|
-
*
|
|
2260
|
+
* Headless dialog service contract. The framework calls these methods to
|
|
2261
|
+
* surface success / warning / error / info messages and confirmation
|
|
2262
|
+
* prompts; consumers provide the concrete implementation via
|
|
2263
|
+
* {@link DialogServiceProvider} (typically the Fluent UI implementation
|
|
2264
|
+
* that ships with `@powerportalspro/react-fluent`, but any dialog UI
|
|
2265
|
+
* works as long as it satisfies this contract).
|
|
2086
2266
|
*
|
|
2087
|
-
* **Message format.** The `message` argument is treated as HTML
|
|
2088
|
-
*
|
|
2089
|
-
*
|
|
2090
|
-
* `<em>`
|
|
2091
|
-
* `app.messages.unsaved-changes`) rely on this. Don't pass unsanitized user
|
|
2092
|
-
* input — same constraint as Blazor.
|
|
2267
|
+
* **Message format.** The `message` argument is treated as trusted HTML
|
|
2268
|
+
* markup — the framework's bundled localization strings (e.g.
|
|
2269
|
+
* `app.messages.unsaved-changes`) rely on this for inline `<br/>`,
|
|
2270
|
+
* `<strong>`, `<em>` tags. Don't pass unsanitized user input.
|
|
2093
2271
|
*
|
|
2094
2272
|
* Each method returns a {@link DialogResult} so the same shape covers both
|
|
2095
2273
|
* single-button (always `{ cancelled: false }` once dismissed) and
|
|
@@ -2119,18 +2297,18 @@ declare function DialogServiceProvider({ value, children, }: {
|
|
|
2119
2297
|
children: ReactNode;
|
|
2120
2298
|
}): react_jsx_runtime.JSX.Element;
|
|
2121
2299
|
/**
|
|
2122
|
-
* Prompts the user about unsaved changes. Returns `true` if the user wants
|
|
2123
|
-
* continue (discarding their edits), `false` if they want to cancel and
|
|
2124
|
-
* editing.
|
|
2300
|
+
* Prompts the user about unsaved changes. Returns `true` if the user wants
|
|
2301
|
+
* to continue (discarding their edits), `false` if they want to cancel and
|
|
2302
|
+
* keep editing.
|
|
2125
2303
|
*
|
|
2126
|
-
* Used by the framework before navigation, refresh, and any other
|
|
2127
|
-
* that would discard pending edits. Application code can also
|
|
2128
|
-
* for custom flows.
|
|
2304
|
+
* Used by the framework before navigation, refresh, and any other
|
|
2305
|
+
* operation that would discard pending edits. Application code can also
|
|
2306
|
+
* call it directly for custom flows.
|
|
2129
2307
|
*
|
|
2130
2308
|
* Strings come from the supplied {@link Localizer} (default English from
|
|
2131
|
-
* the framework's bundled JSON). Keys: `app.messages.unsaved-changes`
|
|
2132
|
-
* `app.messages.unsaved-changes-title` (title),
|
|
2133
|
-
* `app.buttons.no.label` (button labels).
|
|
2309
|
+
* the framework's bundled JSON). Keys: `app.messages.unsaved-changes`
|
|
2310
|
+
* (body), `app.messages.unsaved-changes-title` (title),
|
|
2311
|
+
* `app.buttons.yes.label` / `app.buttons.no.label` (button labels).
|
|
2134
2312
|
*/
|
|
2135
2313
|
declare function warnAboutUnsavedChangesAsync(dialog: DialogService, localizer: Localizer): Promise<boolean>;
|
|
2136
2314
|
/**
|
|
@@ -2162,11 +2340,10 @@ interface OverlayInstance extends OverlayOptions {
|
|
|
2162
2340
|
readonly id: string;
|
|
2163
2341
|
}
|
|
2164
2342
|
/**
|
|
2165
|
-
* Headless overlay service contract
|
|
2166
|
-
*
|
|
2167
|
-
*
|
|
2168
|
-
*
|
|
2169
|
-
* provide the actual UI.
|
|
2343
|
+
* Headless overlay service contract. Maintains a per-target stack of
|
|
2344
|
+
* overlay instances; the topmost instance for a target is what renders.
|
|
2345
|
+
* Concrete implementations (e.g. `<FluentOverlayProvider>` from
|
|
2346
|
+
* `@powerportalspro/react-fluent`) provide the actual UI.
|
|
2170
2347
|
*
|
|
2171
2348
|
* Reads happen via the {@link useOverlayForTarget} hook — that's how
|
|
2172
2349
|
* components subscribe to "what overlay should I currently render". The
|
|
@@ -2217,9 +2394,7 @@ declare function useOverlayServiceState(): OverlayContextValue;
|
|
|
2217
2394
|
/**
|
|
2218
2395
|
* Run an async operation while showing an overlay. Hides on success or
|
|
2219
2396
|
* failure (the overlay is dismissed in `finally`, so failures don't leave a
|
|
2220
|
-
* stuck spinner).
|
|
2221
|
-
* `MainContext.SaveAsync` uses around `_overlayService.ShowOverlayAsync` /
|
|
2222
|
-
* `HideOverlayAsync`.
|
|
2397
|
+
* stuck spinner).
|
|
2223
2398
|
*/
|
|
2224
2399
|
declare function runWithOverlayAsync<T>(service: OverlayService | null, options: OverlayOptions, operation: () => Promise<T>): Promise<T>;
|
|
2225
2400
|
/**
|
|
@@ -2259,12 +2434,12 @@ declare function useUnsavedChangesWarning(): void;
|
|
|
2259
2434
|
* guard needs:
|
|
2260
2435
|
*
|
|
2261
2436
|
* - `isAnyDirty` — reactive boolean tracking whether any registered
|
|
2262
|
-
*
|
|
2263
|
-
*
|
|
2437
|
+
* top-most {@link MainContext} / {@link RecordContext} on the page is
|
|
2438
|
+
* dirty (read-through to {@link useIsAnyDirty}).
|
|
2264
2439
|
* - `warn` — async function that opens the framework confirmation dialog
|
|
2265
|
-
*
|
|
2266
|
-
*
|
|
2267
|
-
*
|
|
2440
|
+
* and resolves `true` if the user confirmed discarding the edits,
|
|
2441
|
+
* `false` if they cancelled (read-through to
|
|
2442
|
+
* {@link useWarnAboutUnsavedChanges}).
|
|
2268
2443
|
*
|
|
2269
2444
|
* Router-agnostic — this package has zero router dependencies. Pair it
|
|
2270
2445
|
* with whichever router blocker your app uses:
|
|
@@ -2276,24 +2451,24 @@ declare function useUnsavedChangesWarning(): void;
|
|
|
2276
2451
|
* ```tsx
|
|
2277
2452
|
* import { useBlocker } from 'react-router-dom';
|
|
2278
2453
|
* function MyGuard() {
|
|
2279
|
-
*
|
|
2280
|
-
*
|
|
2281
|
-
*
|
|
2282
|
-
*
|
|
2283
|
-
*
|
|
2284
|
-
*
|
|
2285
|
-
*
|
|
2286
|
-
*
|
|
2287
|
-
*
|
|
2288
|
-
*
|
|
2289
|
-
*
|
|
2290
|
-
*
|
|
2291
|
-
*
|
|
2292
|
-
*
|
|
2293
|
-
*
|
|
2294
|
-
*
|
|
2295
|
-
*
|
|
2296
|
-
*
|
|
2454
|
+
* const guard = useUnsavedChangesGuard();
|
|
2455
|
+
* const blocker = useBlocker(
|
|
2456
|
+
* ({ currentLocation, nextLocation }) =>
|
|
2457
|
+
* guard.isAnyDirty &&
|
|
2458
|
+
* currentLocation.pathname !== nextLocation.pathname,
|
|
2459
|
+
* );
|
|
2460
|
+
* useEffect(() => {
|
|
2461
|
+
* if (blocker.state !== 'blocked') return;
|
|
2462
|
+
* let cancelled = false;
|
|
2463
|
+
* (async () => {
|
|
2464
|
+
* const proceed = await guard.warn();
|
|
2465
|
+
* if (cancelled) return;
|
|
2466
|
+
* if (proceed) blocker.proceed();
|
|
2467
|
+
* else blocker.reset();
|
|
2468
|
+
* })();
|
|
2469
|
+
* return () => { cancelled = true; };
|
|
2470
|
+
* }, [blocker, guard]);
|
|
2471
|
+
* return null;
|
|
2297
2472
|
* }
|
|
2298
2473
|
* ```
|
|
2299
2474
|
*
|
|
@@ -2304,14 +2479,14 @@ declare function useUnsavedChangesWarning(): void;
|
|
|
2304
2479
|
* ```tsx
|
|
2305
2480
|
* import { useBlocker } from '@tanstack/react-router';
|
|
2306
2481
|
* function MyGuard() {
|
|
2307
|
-
*
|
|
2308
|
-
*
|
|
2309
|
-
*
|
|
2310
|
-
*
|
|
2311
|
-
*
|
|
2312
|
-
*
|
|
2313
|
-
*
|
|
2314
|
-
*
|
|
2482
|
+
* const guard = useUnsavedChangesGuard();
|
|
2483
|
+
* useBlocker({
|
|
2484
|
+
* blockerFn: async () => {
|
|
2485
|
+
* if (!guard.isAnyDirty) return true; // allow
|
|
2486
|
+
* return await guard.warn(); // user choice
|
|
2487
|
+
* },
|
|
2488
|
+
* });
|
|
2489
|
+
* return null;
|
|
2315
2490
|
* }
|
|
2316
2491
|
* ```
|
|
2317
2492
|
*
|
|
@@ -2375,11 +2550,11 @@ interface UnsavedChangesReporter {
|
|
|
2375
2550
|
* {@link PowerPortalsProProvider}; consumed by:
|
|
2376
2551
|
*
|
|
2377
2552
|
* - The auto-registration effect inside topmost
|
|
2378
|
-
*
|
|
2379
|
-
*
|
|
2553
|
+
* {@link MainContext} / {@link RecordContext}, which adds a reporter on
|
|
2554
|
+
* mount + removes it on unmount.
|
|
2380
2555
|
* - `<RouterUnsavedChangesGuard>` (in `@powerportalspro/react-fluent`),
|
|
2381
|
-
*
|
|
2382
|
-
*
|
|
2556
|
+
* which subscribes via {@link useIsAnyDirty} and gates `useBlocker` on
|
|
2557
|
+
* the aggregate.
|
|
2383
2558
|
*
|
|
2384
2559
|
* Router-agnostic by design — the registry knows nothing about
|
|
2385
2560
|
* react-router, history, or navigation events. That coupling lives in
|
|
@@ -2521,4 +2696,4 @@ declare function ValidationProvider({ children }: {
|
|
|
2521
2696
|
|
|
2522
2697
|
declare const VERSION = "0.1.0";
|
|
2523
2698
|
|
|
2524
|
-
export { ASP_NET_CULTURE_COOKIE, type AuthState, AuthStatus, AuthorizedView, type AuthorizedViewProps, type ColumnValidator, type ConfirmationDialogOptions, type CreateLocalizerOptions, DEFAULT_URL_LOCALE_PATTERN, DefaultLocalizerProvider, type DefaultLocalizerProviderProps, type DialogOptions, type DialogResult, type DialogService, DialogServiceProvider,
|
|
2699
|
+
export { ASP_NET_CULTURE_COOKIE, type AuthState, AuthStatus, AuthorizedView, type AuthorizedViewProps, type ColumnValidator, type ConfirmationDialogOptions, type CreateLocalizerOptions, DEFAULT_URL_LOCALE_PATTERN, DefaultLocalizerProvider, type DefaultLocalizerProviderProps, type DialogOptions, type DialogResult, type DialogService, DialogServiceProvider, InMemoryOrganizationSettingsCache, InMemoryTableMetadataCache, InMemoryViewMetadataCache, InMemoryViewsForTableCache, LocaleProvider, type LocaleProviderProps, type LocaleState, type LocalizationPrefetcher, type Localizer, LocalizerProvider, LookupRecordContext, type LookupRecordContextProps, MainContext, type MainContextDescendant, type MainContextProps, MainContextProvider, type MainContextValue, MaskMode, type MaskOptions, type NumericOptions, type OrganizationSettingsCache, type OverlayInstance, type OverlayOptions, type OverlayService, OverlayServiceProvider, PowerPortalsProContext, type PowerPortalsProContextValue, PowerPortalsProProvider, type PowerPortalsProProviderProps, type QueryResult, QueryStatus, RecordContext, type RecordContextProps, type RecordContextValue, type ReformatResult, type TableMetadataCache, type UnsavedChangesGuardController, type UnsavedChangesRegistry, UnsavedChangesRegistryProvider, type UnsavedChangesRegistryProviderProps, type UnsavedChangesReporter, type UrlCultureStrategyName, type UseAuthResult, type UseFetchRecordsOptions, type UseGridDataOptions, type UseMaskedTextFieldOptions, type UseMaskedTextFieldReturn, type UseOrganizationSettingsOptions, type UseRecordOptions, type UseSupportedLocalesOptions, type UseTableMetadataOptions, type UseTablePermissionsOptions, type UseViewDataSourceOptions, type UseViewMetadataOptions, type UseViewsForTableOptions, VERSION, type ValidationContextValue, ValidationProvider, type ViewDataSource, type ViewDataSourceHighlight, type ViewMetadataCache, type ViewsForTableCache, buildLocalePath, createLocalizer, detectLocale, flattenStrings, getAspNetCultureCookie, getLocaleFromUrlPath, interpolate, reformat, resolveLocalizationUrl, runWithOverlayAsync, setAspNetCultureCookie, shouldPrefixLocale, stripLocalePrefix, useAuth, useColumnMetadata, useColumnValidationErrors, useDefaultLocale, useDialogService, useFetchRecords, useGridData, useIsAnyDirty, useLocale, useLocalization, useLocalizationLoaded, useLocalizationPrefetcher, useLocalizer, useMainContext, useMaskedTextField, useOrganizationSettings, useOverlayForTarget, useOverlayService, useOverlayServiceState, usePowerPortalsPro, usePrefixedT, useQueryParam, useRecord, useRecordContext, useRecordContextOptional, useRunWithOverlay, useSupportedLocales, useT, useTableMetadata, useTablePermissions, useUnsavedChangesGuard, useUnsavedChangesRegistry, useUnsavedChangesWarning, useUrlCultureStrategy, useValidationContext, useViewDataSource, useViewMetadata, useViewsForTable, useWarnAboutUnsavedChanges, warnAboutUnsavedChangesAsync };
|