@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.cjs
CHANGED
|
@@ -4,7 +4,273 @@ var react = require('react');
|
|
|
4
4
|
var core = require('@powerportalspro/core');
|
|
5
5
|
var jsxRuntime = require('react/jsx-runtime');
|
|
6
6
|
|
|
7
|
-
// src/
|
|
7
|
+
// src/masking/reformat.ts
|
|
8
|
+
var MaskMode = {
|
|
9
|
+
/** No masking — value passes through unchanged. */
|
|
10
|
+
None: "none",
|
|
11
|
+
/**
|
|
12
|
+
* Per-character allow filter. Characters that don't match
|
|
13
|
+
* {@link MaskOptions.allowedPattern} are dropped as they're typed or pasted.
|
|
14
|
+
*/
|
|
15
|
+
Regex: "regex",
|
|
16
|
+
/**
|
|
17
|
+
* Slotted template (see {@link MaskOptions.pattern}) such as `(000) 000-0000`.
|
|
18
|
+
* `0` = digit, `A` = letter, `*` = alphanumeric; every other character is a
|
|
19
|
+
* literal inserted automatically.
|
|
20
|
+
*/
|
|
21
|
+
Pattern: "pattern",
|
|
22
|
+
/**
|
|
23
|
+
* Live numeric grouping driven by {@link MaskOptions.numeric} — thousands
|
|
24
|
+
* separators, an optional decimal portion, and an optional leading sign.
|
|
25
|
+
*/
|
|
26
|
+
Numeric: "numeric"
|
|
27
|
+
};
|
|
28
|
+
var DIGIT = /[0-9]/;
|
|
29
|
+
var LETTER = /[a-zA-Z]/;
|
|
30
|
+
var ALNUM = /[a-zA-Z0-9]/;
|
|
31
|
+
function isPatternLiteral(token) {
|
|
32
|
+
return token !== "0" && token !== "A" && token !== "*";
|
|
33
|
+
}
|
|
34
|
+
function patternTokenMatches(token, ch) {
|
|
35
|
+
if (token === "0") return DIGIT.test(ch);
|
|
36
|
+
if (token === "A") return LETTER.test(ch);
|
|
37
|
+
if (token === "*") return ALNUM.test(ch);
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
function countSignificant(source, caret, isSignificant) {
|
|
41
|
+
let n = 0;
|
|
42
|
+
for (let i = 0; i < caret && i < source.length; i++) {
|
|
43
|
+
if (isSignificant(source.charAt(i))) n++;
|
|
44
|
+
}
|
|
45
|
+
return n;
|
|
46
|
+
}
|
|
47
|
+
function caretAfterSignificant(display, target, isSignificant) {
|
|
48
|
+
if (target <= 0) {
|
|
49
|
+
let i = 0;
|
|
50
|
+
while (i < display.length && !isSignificant(display.charAt(i))) i++;
|
|
51
|
+
return i;
|
|
52
|
+
}
|
|
53
|
+
let seen = 0;
|
|
54
|
+
for (let i = 0; i < display.length; i++) {
|
|
55
|
+
if (isSignificant(display.charAt(i))) {
|
|
56
|
+
seen++;
|
|
57
|
+
if (seen === target) return i + 1;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return display.length;
|
|
61
|
+
}
|
|
62
|
+
function reformatNumeric(value, caret, o) {
|
|
63
|
+
const sigChars = (c) => DIGIT.test(c) || c === o.decimalSeparator || o.allowNegative && c === "-";
|
|
64
|
+
const sigBefore = countSignificant(value, caret, sigChars);
|
|
65
|
+
const negative = o.allowNegative && value.trimStart().startsWith("-");
|
|
66
|
+
let intPart = "";
|
|
67
|
+
let fracPart = "";
|
|
68
|
+
let sawDecimal = false;
|
|
69
|
+
for (const ch of value) {
|
|
70
|
+
if (DIGIT.test(ch)) {
|
|
71
|
+
if (sawDecimal) fracPart += ch;
|
|
72
|
+
else intPart += ch;
|
|
73
|
+
} else if (o.allowDecimal && ch === o.decimalSeparator && !sawDecimal) {
|
|
74
|
+
sawDecimal = true;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
intPart = intPart.replace(/^0+(?=\d)/, "");
|
|
78
|
+
if (o.maxDecimals !== null && fracPart.length > o.maxDecimals) {
|
|
79
|
+
fracPart = fracPart.slice(0, o.maxDecimals);
|
|
80
|
+
}
|
|
81
|
+
const grouped = o.groupSeparator ? intPart.replace(/\B(?=(\d{3})+(?!\d))/g, o.groupSeparator) : intPart;
|
|
82
|
+
const sign = negative ? "-" : "";
|
|
83
|
+
let display = sign + grouped;
|
|
84
|
+
let raw = sign + intPart;
|
|
85
|
+
if (sawDecimal) {
|
|
86
|
+
display += o.decimalSeparator + fracPart;
|
|
87
|
+
raw += o.decimalSeparator + fracPart;
|
|
88
|
+
}
|
|
89
|
+
const newCaret = caretAfterSignificant(display, sigBefore, sigChars);
|
|
90
|
+
return { display, raw, caret: newCaret };
|
|
91
|
+
}
|
|
92
|
+
function reformatPattern(value, caret, pattern) {
|
|
93
|
+
const sourceChars = [];
|
|
94
|
+
for (const ch of value) {
|
|
95
|
+
if (DIGIT.test(ch) || LETTER.test(ch)) sourceChars.push(ch);
|
|
96
|
+
}
|
|
97
|
+
const sigBefore = countSignificant(value, caret, (c) => DIGIT.test(c) || LETTER.test(c));
|
|
98
|
+
let display = "";
|
|
99
|
+
let raw = "";
|
|
100
|
+
let si = 0;
|
|
101
|
+
for (let pi = 0; pi < pattern.length && si <= sourceChars.length; pi++) {
|
|
102
|
+
const token = pattern[pi];
|
|
103
|
+
if (isPatternLiteral(token)) {
|
|
104
|
+
if (si < sourceChars.length) display += token;
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
while (si < sourceChars.length && !patternTokenMatches(token, sourceChars[si])) si++;
|
|
108
|
+
if (si < sourceChars.length) {
|
|
109
|
+
display += sourceChars[si];
|
|
110
|
+
raw += sourceChars[si];
|
|
111
|
+
si++;
|
|
112
|
+
} else {
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
const newCaret = caretAfterSignificant(display, sigBefore, (c) => DIGIT.test(c) || LETTER.test(c));
|
|
117
|
+
return { display, raw, caret: newCaret };
|
|
118
|
+
}
|
|
119
|
+
function reformatRegex(value, caret, allowedPattern) {
|
|
120
|
+
let re;
|
|
121
|
+
try {
|
|
122
|
+
re = new RegExp(allowedPattern);
|
|
123
|
+
} catch {
|
|
124
|
+
return { display: value, raw: value, caret };
|
|
125
|
+
}
|
|
126
|
+
const keep = (c) => re.test(c);
|
|
127
|
+
const sigBefore = countSignificant(value, caret, keep);
|
|
128
|
+
let display = "";
|
|
129
|
+
for (const ch of value) {
|
|
130
|
+
if (keep(ch)) display += ch;
|
|
131
|
+
}
|
|
132
|
+
const newCaret = caretAfterSignificant(display, sigBefore, keep);
|
|
133
|
+
return { display, raw: display, caret: newCaret };
|
|
134
|
+
}
|
|
135
|
+
function reformat(value, caret, options) {
|
|
136
|
+
switch (options.mode) {
|
|
137
|
+
case MaskMode.Numeric:
|
|
138
|
+
return options.numeric ? reformatNumeric(value, caret, options.numeric) : { display: value, raw: value, caret };
|
|
139
|
+
case MaskMode.Pattern:
|
|
140
|
+
return options.pattern ? reformatPattern(value, caret, options.pattern) : { display: value, raw: value, caret };
|
|
141
|
+
case MaskMode.Regex:
|
|
142
|
+
return options.allowedPattern ? reformatRegex(value, caret, options.allowedPattern) : { display: value, raw: value, caret };
|
|
143
|
+
default:
|
|
144
|
+
return { display: value, raw: value, caret };
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
function computeDisplay(value, options) {
|
|
148
|
+
if (value === null || value === void 0 || value === "") return "";
|
|
149
|
+
return reformat(value, value.length, options).display;
|
|
150
|
+
}
|
|
151
|
+
function computeReported(value, options) {
|
|
152
|
+
if (value === null || value === void 0 || value === "") return "";
|
|
153
|
+
const r = reformat(value, value.length, options);
|
|
154
|
+
return options.valueIncludesMask ? r.display : r.raw;
|
|
155
|
+
}
|
|
156
|
+
function useMaskedTextField(opts) {
|
|
157
|
+
const {
|
|
158
|
+
value,
|
|
159
|
+
onValueChange,
|
|
160
|
+
mode = MaskMode.None,
|
|
161
|
+
pattern = null,
|
|
162
|
+
allowedPattern = null,
|
|
163
|
+
numeric = null,
|
|
164
|
+
valueIncludesMask = false
|
|
165
|
+
} = opts;
|
|
166
|
+
const optionsRef = react.useRef({
|
|
167
|
+
mode,
|
|
168
|
+
pattern,
|
|
169
|
+
allowedPattern,
|
|
170
|
+
numeric,
|
|
171
|
+
valueIncludesMask
|
|
172
|
+
});
|
|
173
|
+
optionsRef.current = { mode, pattern, allowedPattern, numeric, valueIncludesMask };
|
|
174
|
+
const onValueChangeRef = react.useRef(onValueChange);
|
|
175
|
+
onValueChangeRef.current = onValueChange;
|
|
176
|
+
const elementRef = react.useRef(null);
|
|
177
|
+
const focusedRef = react.useRef(false);
|
|
178
|
+
const hasInputSinceFocusRef = react.useRef(false);
|
|
179
|
+
const lastReportedRef = react.useRef(null);
|
|
180
|
+
const pendingCaretRef = react.useRef(null);
|
|
181
|
+
const [displayValue, setDisplayValue] = react.useState(
|
|
182
|
+
() => computeDisplay(value, optionsRef.current)
|
|
183
|
+
);
|
|
184
|
+
react.useEffect(() => {
|
|
185
|
+
if (focusedRef.current && hasInputSinceFocusRef.current) return;
|
|
186
|
+
const next = computeDisplay(value, optionsRef.current);
|
|
187
|
+
setDisplayValue(next);
|
|
188
|
+
lastReportedRef.current = computeReported(value, optionsRef.current);
|
|
189
|
+
}, [value]);
|
|
190
|
+
react.useEffect(() => {
|
|
191
|
+
if (focusedRef.current && hasInputSinceFocusRef.current) return;
|
|
192
|
+
const next = computeDisplay(value, optionsRef.current);
|
|
193
|
+
setDisplayValue(next);
|
|
194
|
+
lastReportedRef.current = computeReported(value, optionsRef.current);
|
|
195
|
+
}, [mode, pattern, allowedPattern, numeric, valueIncludesMask]);
|
|
196
|
+
react.useLayoutEffect(() => {
|
|
197
|
+
const target = pendingCaretRef.current;
|
|
198
|
+
if (target === null) return;
|
|
199
|
+
const input = elementRef.current;
|
|
200
|
+
if (!input) return;
|
|
201
|
+
try {
|
|
202
|
+
input.setSelectionRange(target, target);
|
|
203
|
+
} catch {
|
|
204
|
+
}
|
|
205
|
+
pendingCaretRef.current = null;
|
|
206
|
+
});
|
|
207
|
+
const onChange = react.useCallback(
|
|
208
|
+
(_event, data) => {
|
|
209
|
+
hasInputSinceFocusRef.current = true;
|
|
210
|
+
const o = optionsRef.current;
|
|
211
|
+
const input = elementRef.current;
|
|
212
|
+
const caret = input?.selectionStart ?? data.value.length;
|
|
213
|
+
const result = reformat(data.value, caret, o);
|
|
214
|
+
setDisplayValue(result.display);
|
|
215
|
+
pendingCaretRef.current = result.caret;
|
|
216
|
+
const reported = o.valueIncludesMask ? result.display : result.raw;
|
|
217
|
+
const empty = reported === "";
|
|
218
|
+
const next = empty ? null : reported;
|
|
219
|
+
if (reported !== lastReportedRef.current) {
|
|
220
|
+
lastReportedRef.current = reported;
|
|
221
|
+
onValueChangeRef.current(next);
|
|
222
|
+
}
|
|
223
|
+
},
|
|
224
|
+
[]
|
|
225
|
+
);
|
|
226
|
+
const inputRef = react.useCallback((el) => {
|
|
227
|
+
const prev = elementRef.current;
|
|
228
|
+
if (prev && prev !== el) {
|
|
229
|
+
prev.removeEventListener("focus", handleFocusRef.current);
|
|
230
|
+
prev.removeEventListener("blur", handleBlurRef.current);
|
|
231
|
+
}
|
|
232
|
+
elementRef.current = el;
|
|
233
|
+
if (el) {
|
|
234
|
+
el.addEventListener("focus", handleFocusRef.current);
|
|
235
|
+
el.addEventListener("blur", handleBlurRef.current);
|
|
236
|
+
}
|
|
237
|
+
}, []);
|
|
238
|
+
const handleFocusRef = react.useRef(() => {
|
|
239
|
+
});
|
|
240
|
+
handleFocusRef.current = () => {
|
|
241
|
+
focusedRef.current = true;
|
|
242
|
+
hasInputSinceFocusRef.current = false;
|
|
243
|
+
};
|
|
244
|
+
const handleBlurRef = react.useRef(() => {
|
|
245
|
+
});
|
|
246
|
+
handleBlurRef.current = () => {
|
|
247
|
+
focusedRef.current = false;
|
|
248
|
+
if (!hasInputSinceFocusRef.current) {
|
|
249
|
+
const next = computeDisplay(value, optionsRef.current);
|
|
250
|
+
if (next !== displayValue) {
|
|
251
|
+
setDisplayValue(next);
|
|
252
|
+
lastReportedRef.current = computeReported(value, optionsRef.current);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
const forceValue = react.useCallback((newValue) => {
|
|
257
|
+
const o = optionsRef.current;
|
|
258
|
+
if (newValue === null || newValue === "") {
|
|
259
|
+
setDisplayValue("");
|
|
260
|
+
lastReportedRef.current = "";
|
|
261
|
+
pendingCaretRef.current = 0;
|
|
262
|
+
onValueChangeRef.current(null);
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
const result = reformat(newValue, newValue.length, o);
|
|
266
|
+
setDisplayValue(result.display);
|
|
267
|
+
pendingCaretRef.current = result.display.length;
|
|
268
|
+
const reported = o.valueIncludesMask ? result.display : result.raw;
|
|
269
|
+
lastReportedRef.current = reported;
|
|
270
|
+
onValueChangeRef.current(reported === "" ? null : reported);
|
|
271
|
+
}, []);
|
|
272
|
+
return { displayValue, onChange, inputRef, forceValue };
|
|
273
|
+
}
|
|
8
274
|
var AuthStatus = {
|
|
9
275
|
Loading: "loading",
|
|
10
276
|
Anonymous: "anonymous",
|
|
@@ -78,19 +344,19 @@ var InMemoryViewMetadataCache = class {
|
|
|
78
344
|
this.cache.clear();
|
|
79
345
|
}
|
|
80
346
|
};
|
|
81
|
-
var
|
|
82
|
-
static KEY = "
|
|
347
|
+
var InMemoryOrganizationSettingsCache = class _InMemoryOrganizationSettingsCache {
|
|
348
|
+
static KEY = "organization-settings";
|
|
83
349
|
cache;
|
|
84
350
|
constructor(ppp) {
|
|
85
351
|
this.cache = new InMemoryCache(
|
|
86
|
-
() => ppp.
|
|
352
|
+
() => ppp.getOrganizationSettingsAsync()
|
|
87
353
|
);
|
|
88
354
|
}
|
|
89
355
|
getAsync() {
|
|
90
|
-
return this.cache.getAsync(
|
|
356
|
+
return this.cache.getAsync(_InMemoryOrganizationSettingsCache.KEY);
|
|
91
357
|
}
|
|
92
358
|
invalidate() {
|
|
93
|
-
this.cache.invalidate(
|
|
359
|
+
this.cache.invalidate(_InMemoryOrganizationSettingsCache.KEY);
|
|
94
360
|
}
|
|
95
361
|
};
|
|
96
362
|
var InMemoryViewsForTableCache = class {
|
|
@@ -257,6 +523,31 @@ function getLocaleFromUrlPath(pattern = DEFAULT_URL_LOCALE_PATTERN) {
|
|
|
257
523
|
const match = window.location.pathname.match(pattern);
|
|
258
524
|
return match?.[1] ?? null;
|
|
259
525
|
}
|
|
526
|
+
function shouldPrefixLocale(strategy, locale, defaultLocale) {
|
|
527
|
+
switch (strategy) {
|
|
528
|
+
case "CookieOnly":
|
|
529
|
+
return false;
|
|
530
|
+
case "PathPrefixAll":
|
|
531
|
+
return true;
|
|
532
|
+
default:
|
|
533
|
+
return locale.toLowerCase() !== defaultLocale.toLowerCase();
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
function stripLocalePrefix(pathname, supportedLocales) {
|
|
537
|
+
const trimmed = pathname.replace(/^\/+/, "");
|
|
538
|
+
if (trimmed.length === 0) return "/";
|
|
539
|
+
const slash = trimmed.indexOf("/");
|
|
540
|
+
const first = slash < 0 ? trimmed : trimmed.slice(0, slash);
|
|
541
|
+
const isLocale = supportedLocales.some((l) => l.toLowerCase() === first.toLowerCase());
|
|
542
|
+
if (!isLocale) return pathname.startsWith("/") ? pathname : `/${pathname}`;
|
|
543
|
+
const rest = slash < 0 ? "" : trimmed.slice(slash);
|
|
544
|
+
return rest.length === 0 ? "/" : rest;
|
|
545
|
+
}
|
|
546
|
+
function buildLocalePath(options) {
|
|
547
|
+
const { strategy, locale, defaultLocale, pathname, supportedLocales } = options;
|
|
548
|
+
const cultureless = stripLocalePrefix(pathname, supportedLocales);
|
|
549
|
+
return shouldPrefixLocale(strategy, locale, defaultLocale) ? `/${locale}${cultureless}` : cultureless;
|
|
550
|
+
}
|
|
260
551
|
function detectLocale(options) {
|
|
261
552
|
const {
|
|
262
553
|
matchUrl = true,
|
|
@@ -311,6 +602,12 @@ var LocaleContext = react.createContext(null);
|
|
|
311
602
|
LocaleContext.displayName = "Locale";
|
|
312
603
|
var LocalizationManifestContext = react.createContext(null);
|
|
313
604
|
LocalizationManifestContext.displayName = "LocalizationManifest";
|
|
605
|
+
function useUrlCultureStrategy() {
|
|
606
|
+
return react.useContext(LocalizationManifestContext)?.urlCultureStrategy;
|
|
607
|
+
}
|
|
608
|
+
function useDefaultLocale() {
|
|
609
|
+
return react.useContext(LocalizationManifestContext)?.supportedLocales?.[0];
|
|
610
|
+
}
|
|
314
611
|
function useLocale() {
|
|
315
612
|
const ctx = react.useContext(LocaleContext);
|
|
316
613
|
return ctx ?? { locale: "en", setLocale: noopSetLocale };
|
|
@@ -358,6 +655,9 @@ function DefaultLocalizerProvider({
|
|
|
358
655
|
}) {
|
|
359
656
|
const [cache, setCache] = react.useState({});
|
|
360
657
|
const [supportedLocales, setSupportedLocales] = react.useState(void 0);
|
|
658
|
+
const [urlCultureStrategy, setUrlCultureStrategy] = react.useState(
|
|
659
|
+
void 0
|
|
660
|
+
);
|
|
361
661
|
const { locale } = useLocale();
|
|
362
662
|
const { ppp } = usePowerPortalsPro();
|
|
363
663
|
const localeRef = react.useRef(locale);
|
|
@@ -427,6 +727,7 @@ function DefaultLocalizerProvider({
|
|
|
427
727
|
const manifest = await pppRef.current.retrieveLocalizationBundleManifestAsync();
|
|
428
728
|
if (cancelled) return;
|
|
429
729
|
setSupportedLocales(manifest.supportedLocales);
|
|
730
|
+
setUrlCultureStrategy(manifest.urlCultureStrategy);
|
|
430
731
|
const resolvedLocale = manifest.supportedLocales.includes(locale) ? locale : manifest.supportedLocales[0] ?? locale;
|
|
431
732
|
const thumbs = await pppRef.current.retrieveLocalizationThumbprintsAsync(resolvedLocale);
|
|
432
733
|
if (cancelled) return;
|
|
@@ -615,8 +916,8 @@ function DefaultLocalizerProvider({
|
|
|
615
916
|
[flushPending]
|
|
616
917
|
);
|
|
617
918
|
const manifestContextValue = react.useMemo(
|
|
618
|
-
() => ({ supportedLocales }),
|
|
619
|
-
[supportedLocales]
|
|
919
|
+
() => ({ supportedLocales, urlCultureStrategy }),
|
|
920
|
+
[supportedLocales, urlCultureStrategy]
|
|
620
921
|
);
|
|
621
922
|
return /* @__PURE__ */ jsxRuntime.jsx(LocalizationManifestContext.Provider, { value: manifestContextValue, children: /* @__PURE__ */ jsxRuntime.jsx(LocalizationPrefetcherContext.Provider, { value: prefetcher, children: /* @__PURE__ */ jsxRuntime.jsx(LocalizerProvider, { value: localizer, children }) }) });
|
|
622
923
|
}
|
|
@@ -685,7 +986,7 @@ function PowerPortalsProProvider({
|
|
|
685
986
|
tableMetadataCache,
|
|
686
987
|
viewMetadataCache,
|
|
687
988
|
viewsForTableCache,
|
|
688
|
-
|
|
989
|
+
organizationSettingsCache
|
|
689
990
|
}) {
|
|
690
991
|
const transportRef = react.useRef(null);
|
|
691
992
|
if (transportRef.current === null) {
|
|
@@ -706,9 +1007,9 @@ function PowerPortalsProProvider({
|
|
|
706
1007
|
() => viewsForTableCache ?? new InMemoryViewsForTableCache(ppp),
|
|
707
1008
|
[ppp, viewsForTableCache]
|
|
708
1009
|
);
|
|
709
|
-
const
|
|
710
|
-
() =>
|
|
711
|
-
[ppp,
|
|
1010
|
+
const resolvedOrganizationSettingsCache = react.useMemo(
|
|
1011
|
+
() => organizationSettingsCache ?? new InMemoryOrganizationSettingsCache(ppp),
|
|
1012
|
+
[ppp, organizationSettingsCache]
|
|
712
1013
|
);
|
|
713
1014
|
const [authState, setAuthState] = react.useState({ status: AuthStatus.Loading });
|
|
714
1015
|
const refreshAuth = react.useCallback(async () => {
|
|
@@ -755,7 +1056,7 @@ function PowerPortalsProProvider({
|
|
|
755
1056
|
tableMetadataCache: resolvedTableMetadataCache,
|
|
756
1057
|
viewMetadataCache: resolvedViewMetadataCache,
|
|
757
1058
|
viewsForTableCache: resolvedViewsForTableCache,
|
|
758
|
-
|
|
1059
|
+
organizationSettingsCache: resolvedOrganizationSettingsCache,
|
|
759
1060
|
authState,
|
|
760
1061
|
refreshAuth,
|
|
761
1062
|
login,
|
|
@@ -769,7 +1070,7 @@ function PowerPortalsProProvider({
|
|
|
769
1070
|
resolvedTableMetadataCache,
|
|
770
1071
|
resolvedViewMetadataCache,
|
|
771
1072
|
resolvedViewsForTableCache,
|
|
772
|
-
|
|
1073
|
+
resolvedOrganizationSettingsCache,
|
|
773
1074
|
authState,
|
|
774
1075
|
refreshAuth,
|
|
775
1076
|
login,
|
|
@@ -804,7 +1105,7 @@ function CacheLocaleSync() {
|
|
|
804
1105
|
tableMetadataCache,
|
|
805
1106
|
viewMetadataCache,
|
|
806
1107
|
viewsForTableCache,
|
|
807
|
-
|
|
1108
|
+
organizationSettingsCache
|
|
808
1109
|
} = usePowerPortalsPro();
|
|
809
1110
|
const isFirstRun = react.useRef(true);
|
|
810
1111
|
react.useEffect(() => {
|
|
@@ -815,13 +1116,13 @@ function CacheLocaleSync() {
|
|
|
815
1116
|
tableMetadataCache.clear();
|
|
816
1117
|
viewMetadataCache.clear();
|
|
817
1118
|
viewsForTableCache.clear();
|
|
818
|
-
|
|
1119
|
+
organizationSettingsCache.invalidate();
|
|
819
1120
|
}, [
|
|
820
1121
|
locale,
|
|
821
1122
|
tableMetadataCache,
|
|
822
1123
|
viewMetadataCache,
|
|
823
1124
|
viewsForTableCache,
|
|
824
|
-
|
|
1125
|
+
organizationSettingsCache
|
|
825
1126
|
]);
|
|
826
1127
|
return null;
|
|
827
1128
|
}
|
|
@@ -1230,16 +1531,16 @@ function useViewsForTable(tableLogicalName, options) {
|
|
|
1230
1531
|
);
|
|
1231
1532
|
}
|
|
1232
1533
|
|
|
1233
|
-
// src/use-
|
|
1234
|
-
function
|
|
1235
|
-
const {
|
|
1534
|
+
// src/use-organization-settings.ts
|
|
1535
|
+
function useOrganizationSettings(options) {
|
|
1536
|
+
const { organizationSettingsCache } = usePowerPortalsPro();
|
|
1236
1537
|
const enabled = options?.enabled ?? true;
|
|
1237
1538
|
return useAsyncResource(
|
|
1238
1539
|
async () => {
|
|
1239
|
-
const result = await
|
|
1540
|
+
const result = await organizationSettingsCache.getAsync();
|
|
1240
1541
|
return result ?? void 0;
|
|
1241
1542
|
},
|
|
1242
|
-
[
|
|
1543
|
+
[organizationSettingsCache],
|
|
1243
1544
|
enabled
|
|
1244
1545
|
);
|
|
1245
1546
|
}
|
|
@@ -1623,10 +1924,8 @@ function valuesEqual(a, b) {
|
|
|
1623
1924
|
var GUID_PATTERN = /^\{?[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\}?$/i;
|
|
1624
1925
|
function parseQueryDefault(metadata, rawValue) {
|
|
1625
1926
|
switch (metadata.$type) {
|
|
1626
|
-
// StringMetadata + MemoMetadata both ride on StringValue.
|
|
1627
|
-
//
|
|
1628
|
-
// pattern catches both; in TS the discriminators are distinct so we
|
|
1629
|
-
// list both arms.
|
|
1927
|
+
// StringMetadata + MemoMetadata both ride on StringValue. The TS
|
|
1928
|
+
// discriminators are distinct so we list both arms.
|
|
1630
1929
|
case 14:
|
|
1631
1930
|
case 7:
|
|
1632
1931
|
return { $type: 14, value: rawValue };
|
|
@@ -1757,7 +2056,7 @@ function RecordContextInner({
|
|
|
1757
2056
|
}, [resolvedId, propIsEmptyId]);
|
|
1758
2057
|
const isCreateMode = effectiveId === void 0;
|
|
1759
2058
|
const isSkipFetchMode = !isCreateMode && loadedRecordProp !== void 0;
|
|
1760
|
-
const { ppp } = usePowerPortalsPro();
|
|
2059
|
+
const { ppp, organizationSettingsCache } = usePowerPortalsPro();
|
|
1761
2060
|
const mainContext = useMainContext();
|
|
1762
2061
|
const validation = useValidationContext();
|
|
1763
2062
|
const isTopMost = mainContext === null;
|
|
@@ -1833,6 +2132,44 @@ function RecordContextInner({
|
|
|
1833
2132
|
(current) => current ? { ...current, properties: nextProperties } : current
|
|
1834
2133
|
);
|
|
1835
2134
|
}, [isCreateMode, queryParameterName, metadataQuery.data, loadedRecord]);
|
|
2135
|
+
react.useEffect(() => {
|
|
2136
|
+
if (!isCreateMode) return;
|
|
2137
|
+
if (!metadataQuery.data) return;
|
|
2138
|
+
if (!loadedRecord) return;
|
|
2139
|
+
if (pendingChangesRef.current.size > 0) return;
|
|
2140
|
+
if (loadedRecord.currency) return;
|
|
2141
|
+
let cancelled = false;
|
|
2142
|
+
(async () => {
|
|
2143
|
+
try {
|
|
2144
|
+
const settings = await organizationSettingsCache.getAsync();
|
|
2145
|
+
if (cancelled) return;
|
|
2146
|
+
const defaultCurrency = settings?.defaultCurrency;
|
|
2147
|
+
if (!defaultCurrency) return;
|
|
2148
|
+
const tableHasCurrencyLookup = metadataQuery.data.columns?.some((c) => c.columnName === "transactioncurrencyid") ?? false;
|
|
2149
|
+
setLoadedRecord((current) => {
|
|
2150
|
+
if (!current) return current;
|
|
2151
|
+
if (current.currency) return current;
|
|
2152
|
+
const nextProperties = {
|
|
2153
|
+
...current.properties ?? {}
|
|
2154
|
+
};
|
|
2155
|
+
if (tableHasCurrencyLookup && !nextProperties["transactioncurrencyid"]) {
|
|
2156
|
+
nextProperties["transactioncurrencyid"] = {
|
|
2157
|
+
$type: 6,
|
|
2158
|
+
// ColumnType.Lookup — matches the discriminator on LookupValue
|
|
2159
|
+
value: defaultCurrency.id,
|
|
2160
|
+
tableName: "transactioncurrency",
|
|
2161
|
+
name: defaultCurrency.name
|
|
2162
|
+
};
|
|
2163
|
+
}
|
|
2164
|
+
return { ...current, currency: defaultCurrency, properties: nextProperties };
|
|
2165
|
+
});
|
|
2166
|
+
} catch {
|
|
2167
|
+
}
|
|
2168
|
+
})();
|
|
2169
|
+
return () => {
|
|
2170
|
+
cancelled = true;
|
|
2171
|
+
};
|
|
2172
|
+
}, [isCreateMode, metadataQuery.data, loadedRecord, organizationSettingsCache]);
|
|
1836
2173
|
react.useEffect(() => {
|
|
1837
2174
|
if (!isSkipFetchMode || !loadedRecordProp) return;
|
|
1838
2175
|
setLoadedRecord(loadedRecordProp);
|
|
@@ -1905,10 +2242,10 @@ function RecordContextInner({
|
|
|
1905
2242
|
record: {
|
|
1906
2243
|
tableName: current.tableName,
|
|
1907
2244
|
// Include the client-pre-generated GUID. The seed effect writes
|
|
1908
|
-
// it into `_idForCreate
|
|
1909
|
-
//
|
|
1910
|
-
//
|
|
1911
|
-
//
|
|
2245
|
+
// it into `_idForCreate`; the server's in-batch resolver matches
|
|
2246
|
+
// AssociateRequest / child-FK references against either `id` or
|
|
2247
|
+
// `_idForCreate`, so a Create + Associate pair within one
|
|
2248
|
+
// `ExecuteMultiple` resolves to the same record.
|
|
1912
2249
|
// `id` is also forwarded when the consumer supplied an explicit
|
|
1913
2250
|
// one via `initialRecord` (rare — pre-assigned ids on data
|
|
1914
2251
|
// import).
|
|
@@ -2266,7 +2603,7 @@ exports.AuthorizedView = AuthorizedView;
|
|
|
2266
2603
|
exports.DEFAULT_URL_LOCALE_PATTERN = DEFAULT_URL_LOCALE_PATTERN;
|
|
2267
2604
|
exports.DefaultLocalizerProvider = DefaultLocalizerProvider;
|
|
2268
2605
|
exports.DialogServiceProvider = DialogServiceProvider;
|
|
2269
|
-
exports.
|
|
2606
|
+
exports.InMemoryOrganizationSettingsCache = InMemoryOrganizationSettingsCache;
|
|
2270
2607
|
exports.InMemoryTableMetadataCache = InMemoryTableMetadataCache;
|
|
2271
2608
|
exports.InMemoryViewMetadataCache = InMemoryViewMetadataCache;
|
|
2272
2609
|
exports.InMemoryViewsForTableCache = InMemoryViewsForTableCache;
|
|
@@ -2275,6 +2612,7 @@ exports.LocalizerProvider = LocalizerProvider;
|
|
|
2275
2612
|
exports.LookupRecordContext = LookupRecordContext;
|
|
2276
2613
|
exports.MainContext = MainContext;
|
|
2277
2614
|
exports.MainContextProvider = MainContextProvider;
|
|
2615
|
+
exports.MaskMode = MaskMode;
|
|
2278
2616
|
exports.OverlayServiceProvider = OverlayServiceProvider;
|
|
2279
2617
|
exports.PowerPortalsProContext = PowerPortalsProContext;
|
|
2280
2618
|
exports.PowerPortalsProProvider = PowerPortalsProProvider;
|
|
@@ -2283,20 +2621,24 @@ exports.RecordContext = RecordContext;
|
|
|
2283
2621
|
exports.UnsavedChangesRegistryProvider = UnsavedChangesRegistryProvider;
|
|
2284
2622
|
exports.VERSION = VERSION;
|
|
2285
2623
|
exports.ValidationProvider = ValidationProvider;
|
|
2624
|
+
exports.buildLocalePath = buildLocalePath;
|
|
2286
2625
|
exports.createLocalizer = createLocalizer;
|
|
2287
2626
|
exports.detectLocale = detectLocale;
|
|
2288
2627
|
exports.flattenStrings = flattenStrings;
|
|
2289
2628
|
exports.getAspNetCultureCookie = getAspNetCultureCookie;
|
|
2290
2629
|
exports.getLocaleFromUrlPath = getLocaleFromUrlPath;
|
|
2291
2630
|
exports.interpolate = interpolate;
|
|
2631
|
+
exports.reformat = reformat;
|
|
2292
2632
|
exports.resolveLocalizationUrl = resolveLocalizationUrl;
|
|
2293
2633
|
exports.runWithOverlayAsync = runWithOverlayAsync;
|
|
2294
2634
|
exports.setAspNetCultureCookie = setAspNetCultureCookie;
|
|
2635
|
+
exports.shouldPrefixLocale = shouldPrefixLocale;
|
|
2636
|
+
exports.stripLocalePrefix = stripLocalePrefix;
|
|
2295
2637
|
exports.useAuth = useAuth;
|
|
2296
2638
|
exports.useColumnMetadata = useColumnMetadata;
|
|
2297
2639
|
exports.useColumnValidationErrors = useColumnValidationErrors;
|
|
2640
|
+
exports.useDefaultLocale = useDefaultLocale;
|
|
2298
2641
|
exports.useDialogService = useDialogService;
|
|
2299
|
-
exports.useEnvironmentFileSettings = useEnvironmentFileSettings;
|
|
2300
2642
|
exports.useFetchRecords = useFetchRecords;
|
|
2301
2643
|
exports.useGridData = useGridData;
|
|
2302
2644
|
exports.useIsAnyDirty = useIsAnyDirty;
|
|
@@ -2306,6 +2648,8 @@ exports.useLocalizationLoaded = useLocalizationLoaded;
|
|
|
2306
2648
|
exports.useLocalizationPrefetcher = useLocalizationPrefetcher;
|
|
2307
2649
|
exports.useLocalizer = useLocalizer;
|
|
2308
2650
|
exports.useMainContext = useMainContext;
|
|
2651
|
+
exports.useMaskedTextField = useMaskedTextField;
|
|
2652
|
+
exports.useOrganizationSettings = useOrganizationSettings;
|
|
2309
2653
|
exports.useOverlayForTarget = useOverlayForTarget;
|
|
2310
2654
|
exports.useOverlayService = useOverlayService;
|
|
2311
2655
|
exports.useOverlayServiceState = useOverlayServiceState;
|
|
@@ -2323,6 +2667,7 @@ exports.useTablePermissions = useTablePermissions;
|
|
|
2323
2667
|
exports.useUnsavedChangesGuard = useUnsavedChangesGuard;
|
|
2324
2668
|
exports.useUnsavedChangesRegistry = useUnsavedChangesRegistry;
|
|
2325
2669
|
exports.useUnsavedChangesWarning = useUnsavedChangesWarning;
|
|
2670
|
+
exports.useUrlCultureStrategy = useUrlCultureStrategy;
|
|
2326
2671
|
exports.useValidationContext = useValidationContext;
|
|
2327
2672
|
exports.useViewDataSource = useViewDataSource;
|
|
2328
2673
|
exports.useViewMetadata = useViewMetadata;
|