@powerportalspro/react-fluent 6.0.0 → 7.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 +603 -122
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +99 -4
- package/dist/index.d.ts +99 -4
- package/dist/index.js +606 -127
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { makeStyles, mergeClasses, Input, tokens, Toolbar, ToolbarButton, ToolbarDivider, Menu, MenuTrigger, MenuPopover, MenuList, MenuItemRadio, Button, createLightTheme, createDarkTheme, makeStaticStyles, MessageBar, MessageBarBody, Dropdown, Option, Spinner, Field, Textarea, Switch, Checkbox, Label, TabList, Tab, Tooltip, Dialog, DialogSurface, DialogBody, DialogTitle, DialogContent, DialogActions, RadioGroup, Radio, useId as useId$1, Text, Overflow, OverflowItem, SearchBox, CounterBadge, Popover, PopoverTrigger, PopoverSurface, MenuItem, Combobox, TagPicker, TagPickerControl, TagPickerGroup, Tag, TagPickerInput, TagPickerList, TagPickerOption, webDarkTheme, webLightTheme, teamsDarkTheme, teamsLightTheme, FluentProvider, Avatar, Divider, OverlayDrawer, DrawerHeader, DrawerHeaderTitle, DrawerBody, useOverflowMenu, useIsOverflowItemVisible, Title3, Table, TableHeader, TableRow, TableHeaderCell, TableBody, TableCell, createTableColumn, DataGrid, DataGridHeader, DataGridRow, DataGridHeaderCell, DataGridBody, DataGridCell,
|
|
2
|
-
import { MaskMode, useMaskedTextField, useT, usePowerPortalsPro, useRecordContext, useColumnMetadata, useLocale, MainContext, useTableMetadata, useWarnAboutUnsavedChanges, useMainContext, useViewsForTable, useViewMetadata, QueryStatus, useGridData, RecordContext, DialogServiceProvider, useUrlCultureStrategy, useDefaultLocale, useSupportedLocales, setAspNetCultureCookie, buildLocalePath, useAuth, AuthStatus, useOverlayServiceState, OverlayServiceProvider, useOverlayForTarget, useLocalization, useLocalizationLoaded, useValidationContext, useDialogService, useRunWithOverlay,
|
|
1
|
+
import { makeStyles, mergeClasses, Input, tokens, Toolbar, ToolbarButton, ToolbarDivider, Menu, MenuTrigger, MenuPopover, MenuList, MenuItemRadio, Button, createLightTheme, createDarkTheme, makeStaticStyles, MessageBar, MessageBarBody, Dropdown, Option, Spinner, Field, Textarea, Switch, Checkbox, Label, TabList, Tab, Tooltip, Dialog, DialogSurface, DialogBody, DialogTitle, DialogContent, DialogActions, RadioGroup, Radio, useId as useId$1, Text, Overflow, OverflowItem, SearchBox, CounterBadge, Popover, PopoverTrigger, PopoverSurface, MenuItem, Combobox, TagPicker, TagPickerControl, TagPickerGroup, Tag, TagPickerInput, TagPickerList, TagPickerOption, webDarkTheme, webLightTheme, teamsDarkTheme, teamsLightTheme, FluentProvider, Avatar, Divider, MessageBarTitle, MessageBarActions, OverlayDrawer, DrawerHeader, DrawerHeaderTitle, DrawerBody, useOverflowMenu, useIsOverflowItemVisible, Title3, Table, TableHeader, TableRow, TableHeaderCell, TableBody, TableCell, createTableColumn, DataGrid, DataGridHeader, DataGridRow, DataGridHeaderCell, DataGridBody, DataGridCell, DialogTrigger } from '@fluentui/react-components';
|
|
2
|
+
import { MaskMode, useMaskedTextField, useT, usePowerPortalsPro, useRecordContext, useColumnMetadata, useLocale, useRecordContextOptional, MainContext, useTableMetadata, useWarnAboutUnsavedChanges, useMainContext, useViewsForTable, useViewMetadata, QueryStatus, useGridData, RecordContext, DialogServiceProvider, useUrlCultureStrategy, useDefaultLocale, useSupportedLocales, setAspNetCultureCookie, buildLocalePath, useAuth, AuthStatus, useOverlayServiceState, OverlayServiceProvider, useOverlayForTarget, useLocalization, useLocalizationLoaded, useValidationContext, useDialogService, useRunWithOverlay, useOrganizationSettings, useUnsavedChangesGuard, useColumnValidationErrors, isKeyModeEnabled } from '@powerportalspro/react';
|
|
3
3
|
import { forwardRef, useRef, useImperativeHandle, useState, useEffect, useCallback, createContext, useMemo, useId, useLayoutEffect, useContext, useTransition, Children, isValidElement } from 'react';
|
|
4
4
|
import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
|
|
5
|
-
import { ArrowRotateCounterclockwise20Regular, ArrowRotateClockwise20Regular, FlipHorizontal20Regular, FlipVertical20Regular, ZoomIn20Regular, ZoomOut20Regular, ArrowReset20Regular, ChevronDown16Regular, Grid20Regular, Crop20Regular, FullScreenMinimize20Regular, FullScreenMaximize20Regular, ArrowDownload20Regular, Prohibited20Regular, Checkmark20Filled, ArrowDownload24Regular, ArrowClockwise24Regular, ChevronUp12Regular, ChevronDown12Regular, DocumentArrowLeft24Regular, ChevronDown20Regular, ChevronRight20Regular, Folder20Regular, Document20Regular, ErrorCircle20Regular, Eye20Regular, Dismiss20Regular, Edit20Regular, Add16Regular, Edit16Regular, LinkAdd16Regular, LinkDismiss16Regular, Delete16Regular, Settings20Regular, Search20Regular, ArrowClockwise20Regular, ArrowSortDown16Regular, ArrowSortUp16Regular, Dismiss24Regular, LinkAdd20Regular, QuestionCircle24Regular, Info24Regular, DismissCircle24Regular, Warning24Regular, CheckmarkCircle24Regular, ArrowExit20Regular, PersonEdit20Regular, ArrowSwap20Regular, SignOut20Regular, MoreVerticalRegular, ArrowSyncRegular, EyeRegular, ArrowDownloadRegular, SearchRegular, DismissRegular, Save24Regular, Delete24Regular, Add20Regular, Delete20Regular, LinkDismiss20Regular, ArrowUpload32Regular, ArrowUpload24Regular, ArrowSync24Regular, DrawerArrowDownload24Regular, Money20Regular, ErrorCircle12Filled, DocumentText20Regular, FolderZip20Regular, MusicNote220Regular, Video20Regular, Image20Regular, SlideText20Regular, DocumentTable20Regular, DocumentPdf20Regular, MoreHorizontal20Regular, ChevronDoubleLeft20Regular, ChevronLeft20Regular, ChevronDoubleRight20Regular, Info12Regular, Checkmark16Regular, Dismiss16Regular } from '@fluentui/react-icons';
|
|
6
|
-
import { RequiredLevel, DateTimeBehavior, getRecordReferenceId, RelationshipFilterMode, SwitchIdentityResult, TableSecurityPermission } from '@powerportalspro/core';
|
|
5
|
+
import { ArrowRotateCounterclockwise20Regular, ArrowRotateClockwise20Regular, FlipHorizontal20Regular, FlipVertical20Regular, ZoomIn20Regular, ZoomOut20Regular, ArrowReset20Regular, ChevronDown16Regular, Grid20Regular, Crop20Regular, FullScreenMinimize20Regular, FullScreenMaximize20Regular, ArrowDownload20Regular, Prohibited20Regular, Checkmark20Filled, ArrowDownload24Regular, ArrowClockwise24Regular, ChevronUp12Regular, ChevronDown12Regular, DocumentArrowLeft24Regular, ChevronDown20Regular, ChevronRight20Regular, Folder20Regular, Document20Regular, ErrorCircle20Regular, Eye20Regular, Dismiss20Regular, Edit20Regular, Add16Regular, Edit16Regular, LinkAdd16Regular, LinkDismiss16Regular, Delete16Regular, Settings20Regular, Search20Regular, ArrowClockwise20Regular, ArrowSortDown16Regular, ArrowSortUp16Regular, Dismiss24Regular, LinkAdd20Regular, QuestionCircle24Regular, Info24Regular, DismissCircle24Regular, Warning24Regular, CheckmarkCircle24Regular, Person20Regular, Warning20Regular, EyeTracking20Regular, ArrowExit20Regular, PersonEdit20Regular, ArrowSwap20Regular, SignOut20Regular, MoreVerticalRegular, ArrowSyncRegular, EyeRegular, ArrowDownloadRegular, SearchRegular, DismissRegular, Save24Regular, Delete24Regular, Add20Regular, Delete20Regular, LinkDismiss20Regular, ArrowUpload32Regular, ArrowUpload24Regular, ArrowSync24Regular, DrawerArrowDownload24Regular, Money20Regular, ErrorCircle12Filled, DocumentText20Regular, FolderZip20Regular, MusicNote220Regular, Video20Regular, Image20Regular, SlideText20Regular, DocumentTable20Regular, DocumentPdf20Regular, MoreHorizontal20Regular, ChevronDoubleLeft20Regular, ChevronLeft20Regular, ChevronDoubleRight20Regular, Info12Regular, Checkmark16Regular, Dismiss16Regular } from '@fluentui/react-icons';
|
|
6
|
+
import { RequiredLevel, DateTimeBehavior, canReadColumn, getRecordReferenceId, RelationshipFilterMode, ImpersonateResult, SwitchIdentityResult, PortalUserType, TableSecurityPermission, canWriteColumn } from '@powerportalspro/core';
|
|
7
7
|
import { DatePicker } from '@fluentui/react-datepicker-compat';
|
|
8
8
|
import { TimePicker } from '@fluentui/react-timepicker-compat';
|
|
9
9
|
import { unzipSync } from 'fflate';
|
|
@@ -289,8 +289,12 @@ function isRecordWriteDenied(record) {
|
|
|
289
289
|
const perms = record.permissions ?? 0;
|
|
290
290
|
return (perms & TableSecurityPermission.Write) === 0;
|
|
291
291
|
}
|
|
292
|
-
function
|
|
293
|
-
if (
|
|
292
|
+
function isColumnWriteDenied(record, columnName) {
|
|
293
|
+
if (!record || !columnName) return false;
|
|
294
|
+
return !canWriteColumn(record, columnName);
|
|
295
|
+
}
|
|
296
|
+
function resolveEditState(metadata, record, explicitReadOnly, explicitDisabled, columnName) {
|
|
297
|
+
if (isRecordWriteDenied(record) || isColumnWriteDenied(record, columnName)) {
|
|
294
298
|
return { readOnly: true, disabled: true };
|
|
295
299
|
}
|
|
296
300
|
return {
|
|
@@ -718,7 +722,8 @@ function TextEdit({
|
|
|
718
722
|
metadata,
|
|
719
723
|
record,
|
|
720
724
|
readOnly,
|
|
721
|
-
disabled
|
|
725
|
+
disabled,
|
|
726
|
+
columnName
|
|
722
727
|
);
|
|
723
728
|
const setValue = useGuardedSetValue(rawSetValue, resolvedReadOnly, resolvedDisabled);
|
|
724
729
|
const validationErrors = useColumnValidation(
|
|
@@ -812,7 +817,8 @@ function MemoEdit({
|
|
|
812
817
|
metadata,
|
|
813
818
|
record,
|
|
814
819
|
readOnly,
|
|
815
|
-
disabled
|
|
820
|
+
disabled,
|
|
821
|
+
columnName
|
|
816
822
|
);
|
|
817
823
|
const setValue = useGuardedSetValue(rawSetValue, resolvedReadOnly, resolvedDisabled);
|
|
818
824
|
const validationErrors = useColumnValidation(
|
|
@@ -926,7 +932,8 @@ function BoolEdit({
|
|
|
926
932
|
metadata,
|
|
927
933
|
record,
|
|
928
934
|
readOnly,
|
|
929
|
-
disabled
|
|
935
|
+
disabled,
|
|
936
|
+
columnName
|
|
930
937
|
);
|
|
931
938
|
const setValue = useGuardedSetValue(rawSetValue, resolvedReadOnly, resolvedDisabled);
|
|
932
939
|
const isInactive = resolvedDisabled || resolvedReadOnly;
|
|
@@ -1102,7 +1109,8 @@ function NumberEdit({
|
|
|
1102
1109
|
metadata,
|
|
1103
1110
|
record,
|
|
1104
1111
|
readOnly,
|
|
1105
|
-
disabled
|
|
1112
|
+
disabled,
|
|
1113
|
+
columnName
|
|
1106
1114
|
);
|
|
1107
1115
|
const setValue = useGuardedSetValue(rawSetValue, resolvedReadOnly, resolvedDisabled);
|
|
1108
1116
|
const validationErrors = useColumnValidation(
|
|
@@ -1546,7 +1554,8 @@ function MoneyEdit({
|
|
|
1546
1554
|
metadata,
|
|
1547
1555
|
record,
|
|
1548
1556
|
readOnly,
|
|
1549
|
-
disabled
|
|
1557
|
+
disabled,
|
|
1558
|
+
columnName
|
|
1550
1559
|
);
|
|
1551
1560
|
const setValue = useGuardedSetValue(rawSetValue, resolvedReadOnly, resolvedDisabled);
|
|
1552
1561
|
const validationErrors = useColumnValidation(
|
|
@@ -1960,7 +1969,8 @@ function DateTimeEdit({
|
|
|
1960
1969
|
metadata,
|
|
1961
1970
|
record,
|
|
1962
1971
|
readOnly,
|
|
1963
|
-
disabled
|
|
1972
|
+
disabled,
|
|
1973
|
+
columnName
|
|
1964
1974
|
);
|
|
1965
1975
|
const setValue = useGuardedSetValue(rawSetValue, resolvedReadOnly, resolvedDisabled);
|
|
1966
1976
|
const resolvedEditorType = editorType ?? resolveEditorTypeFromMetadata(metadata);
|
|
@@ -5351,7 +5361,8 @@ function FileEdit({
|
|
|
5351
5361
|
metadata,
|
|
5352
5362
|
record,
|
|
5353
5363
|
readOnly,
|
|
5354
|
-
disabled
|
|
5364
|
+
disabled,
|
|
5365
|
+
columnName
|
|
5355
5366
|
);
|
|
5356
5367
|
const setValue = useGuardedSetValue(rawSetValue, resolvedReadOnly, resolvedDisabled);
|
|
5357
5368
|
const isInteractable = !resolvedReadOnly && !resolvedDisabled;
|
|
@@ -5668,7 +5679,8 @@ function ImageEdit({
|
|
|
5668
5679
|
metadata,
|
|
5669
5680
|
record,
|
|
5670
5681
|
readOnly,
|
|
5671
|
-
disabled
|
|
5682
|
+
disabled,
|
|
5683
|
+
columnName
|
|
5672
5684
|
);
|
|
5673
5685
|
const setValue = useGuardedSetValue(rawSetValue, resolvedReadOnly, resolvedDisabled);
|
|
5674
5686
|
const isInteractable = !resolvedReadOnly && !resolvedDisabled;
|
|
@@ -6148,7 +6160,8 @@ function ChoiceEdit({
|
|
|
6148
6160
|
metadata,
|
|
6149
6161
|
record,
|
|
6150
6162
|
readOnly,
|
|
6151
|
-
disabled
|
|
6163
|
+
disabled,
|
|
6164
|
+
columnName
|
|
6152
6165
|
);
|
|
6153
6166
|
const setValue = useGuardedSetValue(rawSetValue, resolvedReadOnly, resolvedDisabled);
|
|
6154
6167
|
const choiceMeta = getChoiceMetadata(metadata);
|
|
@@ -6368,7 +6381,8 @@ function MultiSelectChoiceEdit({
|
|
|
6368
6381
|
metadata,
|
|
6369
6382
|
record,
|
|
6370
6383
|
readOnly,
|
|
6371
|
-
disabled
|
|
6384
|
+
disabled,
|
|
6385
|
+
columnName
|
|
6372
6386
|
);
|
|
6373
6387
|
const setValue = useGuardedSetValue(rawSetValue, resolvedReadOnly, resolvedDisabled);
|
|
6374
6388
|
const choiceMeta = getChoiceMetadata(metadata);
|
|
@@ -6490,30 +6504,30 @@ function foldString(s, caseSensitive) {
|
|
|
6490
6504
|
function tokenizeSearch(search, delimiters) {
|
|
6491
6505
|
if (!delimiters) return [search];
|
|
6492
6506
|
const delim = new Set(Array.from(delimiters));
|
|
6493
|
-
const
|
|
6507
|
+
const tokens44 = [];
|
|
6494
6508
|
let current = "";
|
|
6495
6509
|
for (const ch of search) {
|
|
6496
6510
|
if (delim.has(ch)) {
|
|
6497
6511
|
if (current.length > 0) {
|
|
6498
|
-
|
|
6512
|
+
tokens44.push(current);
|
|
6499
6513
|
current = "";
|
|
6500
6514
|
}
|
|
6501
6515
|
} else {
|
|
6502
6516
|
current += ch;
|
|
6503
6517
|
}
|
|
6504
6518
|
}
|
|
6505
|
-
if (current.length > 0)
|
|
6506
|
-
return
|
|
6519
|
+
if (current.length > 0) tokens44.push(current);
|
|
6520
|
+
return tokens44;
|
|
6507
6521
|
}
|
|
6508
6522
|
function splitHighlightSegments(text, search, options) {
|
|
6509
6523
|
if (!text || !search) return [];
|
|
6510
6524
|
const caseSensitive = options?.caseSensitive ?? false;
|
|
6511
6525
|
const delimiters = options?.delimiters ?? "";
|
|
6512
|
-
const
|
|
6513
|
-
if (
|
|
6526
|
+
const tokens44 = tokenizeSearch(search, delimiters);
|
|
6527
|
+
if (tokens44.length === 0) return [{ text, isMatch: false }];
|
|
6514
6528
|
const folded = foldString(text, caseSensitive);
|
|
6515
6529
|
const ranges = [];
|
|
6516
|
-
for (const token of
|
|
6530
|
+
for (const token of tokens44) {
|
|
6517
6531
|
const tokenFolded = foldString(token, caseSensitive).folded;
|
|
6518
6532
|
if (tokenFolded.length === 0) continue;
|
|
6519
6533
|
let cursor2 = 0;
|
|
@@ -7284,7 +7298,11 @@ function getRendererTypeForCode(typeCode) {
|
|
|
7284
7298
|
}
|
|
7285
7299
|
function ColumnEdit(props) {
|
|
7286
7300
|
const metadata = useColumnMetadata(props.columnName);
|
|
7301
|
+
const record = useRecordContextOptional()?.record;
|
|
7287
7302
|
const typeCode = metadata?.$type;
|
|
7303
|
+
if (record && !canReadColumn(record, props.columnName)) {
|
|
7304
|
+
return /* @__PURE__ */ jsx(ColumnDisplayValue, { ...props });
|
|
7305
|
+
}
|
|
7288
7306
|
switch (typeCode) {
|
|
7289
7307
|
case 0:
|
|
7290
7308
|
return /* @__PURE__ */ jsx(BoolEdit, { ...props });
|
|
@@ -8304,6 +8322,36 @@ function MainGridVirtualizeFooter({
|
|
|
8304
8322
|
] });
|
|
8305
8323
|
}
|
|
8306
8324
|
|
|
8325
|
+
// src/grids/virtualize-paging.ts
|
|
8326
|
+
function hasMoreRowsToLoad(state) {
|
|
8327
|
+
if (state.moreRecords === false) return false;
|
|
8328
|
+
if (state.moreRecords === true) return true;
|
|
8329
|
+
if (state.lastPageEmpty) return false;
|
|
8330
|
+
if (state.totalCount === void 0) return true;
|
|
8331
|
+
return state.accumulatedCount < state.totalCount;
|
|
8332
|
+
}
|
|
8333
|
+
var VirtualizePagingCookies = class {
|
|
8334
|
+
key;
|
|
8335
|
+
byPage = /* @__PURE__ */ new Map();
|
|
8336
|
+
/** Store the cookie the response for `page` came back with (no-op for a null / empty cookie). */
|
|
8337
|
+
record(key, page, cookie) {
|
|
8338
|
+
if (this.key !== key) {
|
|
8339
|
+
this.key = key;
|
|
8340
|
+
this.byPage = /* @__PURE__ */ new Map();
|
|
8341
|
+
}
|
|
8342
|
+
if (cookie) this.byPage.set(page, cookie);
|
|
8343
|
+
}
|
|
8344
|
+
/**
|
|
8345
|
+
* The cookie to send when requesting `page` under `key`: the one page
|
|
8346
|
+
* `page - 1` returned, or `undefined` when it isn't known (page 1, a
|
|
8347
|
+
* non-sequential jump, or a key the store has no cookies for).
|
|
8348
|
+
*/
|
|
8349
|
+
cookieFor(key, page) {
|
|
8350
|
+
if (this.key !== key || page <= 1) return void 0;
|
|
8351
|
+
return this.byPage.get(page - 1);
|
|
8352
|
+
}
|
|
8353
|
+
};
|
|
8354
|
+
|
|
8307
8355
|
// src/grids/persisted-grid-state.ts
|
|
8308
8356
|
function readPersistedGridStateFromUrl(queryParameterName) {
|
|
8309
8357
|
if (!queryParameterName) return null;
|
|
@@ -8367,6 +8415,12 @@ var ViewSort = {
|
|
|
8367
8415
|
/** Localized display name, descending. */
|
|
8368
8416
|
NameDescending: "nameDescending"
|
|
8369
8417
|
};
|
|
8418
|
+
function resolveViewLabel(view, t) {
|
|
8419
|
+
const key = `tables.${view.tableName}.views.${view.id}.label`;
|
|
8420
|
+
const localized = t(key);
|
|
8421
|
+
if (localized !== key) return localized;
|
|
8422
|
+
return view.displayName?.trim() ? view.displayName : null;
|
|
8423
|
+
}
|
|
8370
8424
|
function customToViewMetadata(custom) {
|
|
8371
8425
|
return {
|
|
8372
8426
|
id: custom.id,
|
|
@@ -8835,8 +8889,22 @@ function MainGridImpl({
|
|
|
8835
8889
|
`[MainGrid] Declared <GridColumn> children override the column projection of the supplied fetchXml (columns: ${columnsKey.split(",").join(", ")}). Drop the children \u2014 or remove the conflicting <attribute> elements from the fetchXml \u2014 to silence this message.`
|
|
8836
8890
|
);
|
|
8837
8891
|
}, [columnsKey, useInlineFetchXml]);
|
|
8892
|
+
const accumulatorResetKey = useMemo(
|
|
8893
|
+
() => [
|
|
8894
|
+
resolvedViewId ?? "",
|
|
8895
|
+
useInlineFetchXml ? inlineFetchXml ?? "" : "",
|
|
8896
|
+
debouncedSearchText,
|
|
8897
|
+
sort.map((s) => `${s.columnName}:${s.descending ? "d" : "a"}`).join("|"),
|
|
8898
|
+
filtersKey,
|
|
8899
|
+
pageSize,
|
|
8900
|
+
tableName ?? ""
|
|
8901
|
+
].join("|"),
|
|
8902
|
+
[resolvedViewId, useInlineFetchXml, inlineFetchXml, debouncedSearchText, sort, filtersKey, pageSize, tableName]
|
|
8903
|
+
);
|
|
8904
|
+
const [virtualizeCookies] = useState(() => new VirtualizePagingCookies());
|
|
8838
8905
|
const searchRequest = useMemo(() => {
|
|
8839
8906
|
const trimmed = debouncedSearchText.trim();
|
|
8907
|
+
const pagingCookie = isVirtualize ? virtualizeCookies.cookieFor(accumulatorResetKey, page) : void 0;
|
|
8840
8908
|
return {
|
|
8841
8909
|
...useInlineFetchXml && inlineFetchXml ? { fetchXml: inlineFetchXml } : resolvedViewId !== void 0 && { viewId: resolvedViewId },
|
|
8842
8910
|
...trimmed && { searchText: trimmed },
|
|
@@ -8856,7 +8924,8 @@ function MainGridImpl({
|
|
|
8856
8924
|
},
|
|
8857
8925
|
...columnsOverride && { columns: [...columnsOverride] },
|
|
8858
8926
|
pageNumber: page,
|
|
8859
|
-
pageSize
|
|
8927
|
+
pageSize,
|
|
8928
|
+
...pagingCookie && { pagingCookie }
|
|
8860
8929
|
};
|
|
8861
8930
|
}, [
|
|
8862
8931
|
resolvedViewId,
|
|
@@ -8867,7 +8936,9 @@ function MainGridImpl({
|
|
|
8867
8936
|
page,
|
|
8868
8937
|
pageSize,
|
|
8869
8938
|
filtersKey,
|
|
8870
|
-
columnsKey
|
|
8939
|
+
columnsKey,
|
|
8940
|
+
isVirtualize,
|
|
8941
|
+
accumulatorResetKey
|
|
8871
8942
|
]);
|
|
8872
8943
|
const transformPending = !!transformViewAsync || isCustomActiveView;
|
|
8873
8944
|
const recordsResult = useGridData(searchRequest, {
|
|
@@ -9026,7 +9097,7 @@ function MainGridImpl({
|
|
|
9026
9097
|
const rowRecord = cellCtx.row.original;
|
|
9027
9098
|
const rowId = rowRecord.id;
|
|
9028
9099
|
const isPendingCreateRow = !!rowId && rowId.startsWith("__pending-create-");
|
|
9029
|
-
if (editable && !isPendingCreateRow && hasEditorForType) {
|
|
9100
|
+
if (editable && !isPendingCreateRow && hasEditorForType && canWriteColumn(rowRecord, columnName)) {
|
|
9030
9101
|
return (
|
|
9031
9102
|
// Sizing wrapper — overrides Fluent v9's default
|
|
9032
9103
|
// <Input> / <Combobox> / <Dropdown> min-width
|
|
@@ -9164,18 +9235,6 @@ function MainGridImpl({
|
|
|
9164
9235
|
]);
|
|
9165
9236
|
const pageRecords = dataSource ? dataSource.rows : recordsResult.data?.tableRecords ?? EMPTY_RECORDS;
|
|
9166
9237
|
const [accumulatedRows, setAccumulatedRows] = useState(null);
|
|
9167
|
-
const accumulatorResetKey = useMemo(
|
|
9168
|
-
() => [
|
|
9169
|
-
resolvedViewId ?? "",
|
|
9170
|
-
useInlineFetchXml ? inlineFetchXml ?? "" : "",
|
|
9171
|
-
debouncedSearchText,
|
|
9172
|
-
sort.map((s) => `${s.columnName}:${s.descending ? "d" : "a"}`).join("|"),
|
|
9173
|
-
filtersKey,
|
|
9174
|
-
pageSize,
|
|
9175
|
-
tableName ?? ""
|
|
9176
|
-
].join("|"),
|
|
9177
|
-
[resolvedViewId, useInlineFetchXml, inlineFetchXml, debouncedSearchText, sort, filtersKey, pageSize, tableName]
|
|
9178
|
-
);
|
|
9179
9238
|
const resetVirtualizedView = useCallback(() => {
|
|
9180
9239
|
setAccumulatedRows([]);
|
|
9181
9240
|
setPage(1);
|
|
@@ -9201,6 +9260,12 @@ function MainGridImpl({
|
|
|
9201
9260
|
return [...base, ...additions];
|
|
9202
9261
|
});
|
|
9203
9262
|
}, [isVirtualize, recordsResult.status, pageRecords]);
|
|
9263
|
+
useEffect(() => {
|
|
9264
|
+
if (!isVirtualize) return;
|
|
9265
|
+
const landed = recordsResult.data;
|
|
9266
|
+
if (!landed) return;
|
|
9267
|
+
virtualizeCookies.record(accumulatorResetKey, page, landed.pagingInfo?.pagingCookie);
|
|
9268
|
+
}, [isVirtualize, recordsResult.data]);
|
|
9204
9269
|
const data = isVirtualize ? accumulatedRows ?? EMPTY_RECORDS : pageRecords;
|
|
9205
9270
|
const [pendingRowUpdates, setPendingRowUpdates] = useState(() => /* @__PURE__ */ new Map());
|
|
9206
9271
|
const [pendingRowCreates, setPendingRowCreates] = useState(() => []);
|
|
@@ -9681,7 +9746,15 @@ function MainGridImpl({
|
|
|
9681
9746
|
if (raw == null) return void 0;
|
|
9682
9747
|
return typeof raw === "number" ? raw : Number(raw);
|
|
9683
9748
|
})();
|
|
9684
|
-
const
|
|
9749
|
+
const hasMoreRowsToLoad2 = isVirtualize && hasMoreRowsToLoad({
|
|
9750
|
+
accumulatedCount: accumulatedRows?.length ?? 0,
|
|
9751
|
+
totalCount,
|
|
9752
|
+
moreRecords: dataSource ? dataSource.moreRecords : recordsResult.data?.pagingInfo?.moreRecords,
|
|
9753
|
+
// "A page has landed and it carried no rows." In standalone mode
|
|
9754
|
+
// `data` is only ever defined for a landed response (errors wipe it);
|
|
9755
|
+
// the datasource has no data handle, so idle-after-success stands in.
|
|
9756
|
+
lastPageEmpty: dataSource ? dataSource.status === QueryStatus.Success && !dataSource.isFetching && dataSource.rows.length === 0 : recordsResult.data !== void 0 && pageRecords.length === 0
|
|
9757
|
+
});
|
|
9685
9758
|
useEffect(() => {
|
|
9686
9759
|
if (!isVirtualize) return;
|
|
9687
9760
|
const sentinel = loadMoreSentinelRef.current;
|
|
@@ -9692,7 +9765,7 @@ function MainGridImpl({
|
|
|
9692
9765
|
const entry = entries[0];
|
|
9693
9766
|
if (!entry?.isIntersecting) return;
|
|
9694
9767
|
if (recordsResult.isFetching) return;
|
|
9695
|
-
if (!
|
|
9768
|
+
if (!hasMoreRowsToLoad2) return;
|
|
9696
9769
|
setPage(page + 1);
|
|
9697
9770
|
},
|
|
9698
9771
|
{
|
|
@@ -9705,7 +9778,7 @@ function MainGridImpl({
|
|
|
9705
9778
|
);
|
|
9706
9779
|
observer.observe(sentinel);
|
|
9707
9780
|
return () => observer.disconnect();
|
|
9708
|
-
}, [isVirtualize,
|
|
9781
|
+
}, [isVirtualize, hasMoreRowsToLoad2, recordsResult.isFetching, page, setPage]);
|
|
9709
9782
|
const handlePageChange = (nextPage) => {
|
|
9710
9783
|
if (nextPage === page) return;
|
|
9711
9784
|
setPage(nextPage);
|
|
@@ -9714,8 +9787,8 @@ function MainGridImpl({
|
|
|
9714
9787
|
};
|
|
9715
9788
|
const selectedView = views?.find((v) => v.id === resolvedViewId);
|
|
9716
9789
|
const selectedViewLabelKey = selectedView ? `tables.${selectedView.tableName}.views.${selectedView.id}.label` : "";
|
|
9717
|
-
const selectedViewLabel = selectedView ? t
|
|
9718
|
-
const singleViewTitle = selectedView
|
|
9790
|
+
const selectedViewLabel = selectedView ? resolveViewLabel(selectedView, t) ?? selectedViewLabelKey : "";
|
|
9791
|
+
const singleViewTitle = selectedView ? resolveViewLabel(selectedView, t) ?? void 0 : void 0;
|
|
9719
9792
|
return /* @__PURE__ */ jsx(GridContextProvider, { value: gridContextValue, children: /* @__PURE__ */ jsxs(
|
|
9720
9793
|
"div",
|
|
9721
9794
|
{
|
|
@@ -9748,7 +9821,7 @@ function MainGridImpl({
|
|
|
9748
9821
|
if (data2.optionValue) handleViewChange(data2.optionValue);
|
|
9749
9822
|
},
|
|
9750
9823
|
children: views?.map((view) => {
|
|
9751
|
-
const label = t
|
|
9824
|
+
const label = resolveViewLabel(view, t) ?? `tables.${view.tableName}.views.${view.id}.label`;
|
|
9752
9825
|
return /* @__PURE__ */ jsx(Option, { value: view.id, text: label, children: label }, view.id);
|
|
9753
9826
|
})
|
|
9754
9827
|
}
|
|
@@ -10325,7 +10398,7 @@ function MainGridImpl({
|
|
|
10325
10398
|
}
|
|
10326
10399
|
),
|
|
10327
10400
|
displayedData.length === 0 && /* @__PURE__ */ jsx("div", { className: styles.emptyStateRow, children: t("app.components.grid.empty-content") }),
|
|
10328
|
-
isVirtualize &&
|
|
10401
|
+
isVirtualize && hasMoreRowsToLoad2 && // No spinner here: the full-body `refetchScrim` overlay below is the
|
|
10329
10402
|
// single load indicator. Rendering a `size="tiny"` spinner in the
|
|
10330
10403
|
// sentinel as well meant a deps-change refetch (refresh / sort /
|
|
10331
10404
|
// search / view switch) — which resets the accumulator to empty and
|
|
@@ -10844,7 +10917,8 @@ function LookupEdit({
|
|
|
10844
10917
|
metadata,
|
|
10845
10918
|
record,
|
|
10846
10919
|
readOnly,
|
|
10847
|
-
disabled
|
|
10920
|
+
disabled,
|
|
10921
|
+
columnName
|
|
10848
10922
|
);
|
|
10849
10923
|
const setLookupValue = useGuardedSetValue(
|
|
10850
10924
|
rawSetLookupValue,
|
|
@@ -12624,6 +12698,7 @@ function PowerPortalsProThemeProvider({
|
|
|
12624
12698
|
defaultMode = ThemeMode.System,
|
|
12625
12699
|
defaultAccentColor = "default",
|
|
12626
12700
|
defaultTextDirection = TextDirection.Ltr,
|
|
12701
|
+
lockAccentColor = false,
|
|
12627
12702
|
customAccents,
|
|
12628
12703
|
storageKey = DEFAULT_MODE_STORAGE_KEY,
|
|
12629
12704
|
style,
|
|
@@ -12647,9 +12722,11 @@ function PowerPortalsProThemeProvider({
|
|
|
12647
12722
|
() => readStoredMode(storageKey) ?? defaultMode
|
|
12648
12723
|
);
|
|
12649
12724
|
const [accentColor, setAccentColorState] = useState(() => {
|
|
12725
|
+
const configured = defaultAccentColor in accentMap ? defaultAccentColor : "default";
|
|
12726
|
+
if (lockAccentColor) return configured;
|
|
12650
12727
|
const stored = readStoredString(accentStorageKey);
|
|
12651
12728
|
if (stored && stored in accentMap) return stored;
|
|
12652
|
-
return
|
|
12729
|
+
return configured;
|
|
12653
12730
|
});
|
|
12654
12731
|
const [textDirection, setTextDirectionState] = useState(
|
|
12655
12732
|
() => readStoredDirection(directionStorageKey) ?? defaultTextDirection
|
|
@@ -12679,6 +12756,12 @@ function PowerPortalsProThemeProvider({
|
|
|
12679
12756
|
document.body.classList.toggle("ppp-theme-dark", isDark);
|
|
12680
12757
|
document.body.classList.toggle("ppp-theme-light", !isDark);
|
|
12681
12758
|
}, [isDark]);
|
|
12759
|
+
useEffect(() => {
|
|
12760
|
+
if (!lockAccentColor) return;
|
|
12761
|
+
const configured = defaultAccentColor in accentMap ? defaultAccentColor : "default";
|
|
12762
|
+
setAccentColorState(configured);
|
|
12763
|
+
writeStored(accentStorageKey, configured);
|
|
12764
|
+
}, [lockAccentColor, defaultAccentColor, accentMap, accentStorageKey]);
|
|
12682
12765
|
const setMode = useCallback(
|
|
12683
12766
|
(next) => {
|
|
12684
12767
|
setModeState(next);
|
|
@@ -12688,11 +12771,12 @@ function PowerPortalsProThemeProvider({
|
|
|
12688
12771
|
);
|
|
12689
12772
|
const setAccentColor = useCallback(
|
|
12690
12773
|
(next) => {
|
|
12774
|
+
if (lockAccentColor) return;
|
|
12691
12775
|
if (!(next in accentMap)) return;
|
|
12692
12776
|
setAccentColorState(next);
|
|
12693
12777
|
writeStored(accentStorageKey, next);
|
|
12694
12778
|
},
|
|
12695
|
-
[accentMap, accentStorageKey]
|
|
12779
|
+
[lockAccentColor, accentMap, accentStorageKey]
|
|
12696
12780
|
);
|
|
12697
12781
|
const setTextDirection = useCallback(
|
|
12698
12782
|
(next) => {
|
|
@@ -12717,6 +12801,7 @@ function PowerPortalsProThemeProvider({
|
|
|
12717
12801
|
setAccentColor,
|
|
12718
12802
|
availableAccents,
|
|
12719
12803
|
accentColors,
|
|
12804
|
+
accentColorLocked: lockAccentColor,
|
|
12720
12805
|
textDirection,
|
|
12721
12806
|
setTextDirection
|
|
12722
12807
|
}),
|
|
@@ -12728,6 +12813,7 @@ function PowerPortalsProThemeProvider({
|
|
|
12728
12813
|
setAccentColor,
|
|
12729
12814
|
availableAccents,
|
|
12730
12815
|
accentColors,
|
|
12816
|
+
lockAccentColor,
|
|
12731
12817
|
textDirection,
|
|
12732
12818
|
setTextDirection
|
|
12733
12819
|
]
|
|
@@ -12808,7 +12894,7 @@ function ThemeColorSelector({
|
|
|
12808
12894
|
width,
|
|
12809
12895
|
accentLabels
|
|
12810
12896
|
}) {
|
|
12811
|
-
const { accentColor, setAccentColor, availableAccents, accentColors } = useTheme();
|
|
12897
|
+
const { accentColor, setAccentColor, availableAccents, accentColors, accentColorLocked } = useTheme();
|
|
12812
12898
|
const t = useT();
|
|
12813
12899
|
const labelId = useId();
|
|
12814
12900
|
const styles = useStyles6();
|
|
@@ -12822,6 +12908,7 @@ function ThemeColorSelector({
|
|
|
12822
12908
|
},
|
|
12823
12909
|
[t, accentLabels]
|
|
12824
12910
|
);
|
|
12911
|
+
if (accentColorLocked) return null;
|
|
12825
12912
|
const handleOptionSelect = (_event, data) => {
|
|
12826
12913
|
const next = data.optionValue;
|
|
12827
12914
|
if (next && availableAccents.includes(next)) {
|
|
@@ -12989,7 +13076,304 @@ function LanguageDropdown({
|
|
|
12989
13076
|
}
|
|
12990
13077
|
);
|
|
12991
13078
|
}
|
|
13079
|
+
var MINIMUM_QUERY_LENGTH = 3;
|
|
13080
|
+
var MAXIMUM_RESULTS = 50;
|
|
13081
|
+
var SEARCH_DEBOUNCE_MS4 = 300;
|
|
13082
|
+
var GUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
12992
13083
|
var useStyles7 = makeStyles({
|
|
13084
|
+
surface: {
|
|
13085
|
+
maxWidth: "480px",
|
|
13086
|
+
display: "flex",
|
|
13087
|
+
flexDirection: "column"
|
|
13088
|
+
},
|
|
13089
|
+
titleRow: {
|
|
13090
|
+
display: "flex",
|
|
13091
|
+
flexDirection: "row",
|
|
13092
|
+
alignItems: "flex-start",
|
|
13093
|
+
columnGap: tokens.spacingHorizontalS
|
|
13094
|
+
},
|
|
13095
|
+
titleText: {
|
|
13096
|
+
flexGrow: 1,
|
|
13097
|
+
minWidth: 0
|
|
13098
|
+
},
|
|
13099
|
+
body: {
|
|
13100
|
+
display: "flex",
|
|
13101
|
+
flexDirection: "column",
|
|
13102
|
+
rowGap: tokens.spacingVerticalM,
|
|
13103
|
+
paddingTop: tokens.spacingVerticalM
|
|
13104
|
+
},
|
|
13105
|
+
results: {
|
|
13106
|
+
display: "flex",
|
|
13107
|
+
flexDirection: "column",
|
|
13108
|
+
// Fixed height, not min/max: a list that resizes on every keystroke makes the confirm button
|
|
13109
|
+
// jump around under the pointer while the administrator is still reading.
|
|
13110
|
+
height: "280px",
|
|
13111
|
+
overflowY: "auto",
|
|
13112
|
+
// Full shorthand — griffel types `borderColor` and friends as `never`, so the longhand
|
|
13113
|
+
// properties aren't usable here.
|
|
13114
|
+
border: `1px solid ${tokens.colorNeutralStroke1}`,
|
|
13115
|
+
borderRadius: tokens.borderRadiusMedium,
|
|
13116
|
+
backgroundColor: tokens.colorNeutralBackground1
|
|
13117
|
+
},
|
|
13118
|
+
result: {
|
|
13119
|
+
display: "flex",
|
|
13120
|
+
flexDirection: "row",
|
|
13121
|
+
alignItems: "center",
|
|
13122
|
+
columnGap: tokens.spacingHorizontalS,
|
|
13123
|
+
padding: `${tokens.spacingVerticalS} ${tokens.spacingHorizontalM}`,
|
|
13124
|
+
cursor: "pointer",
|
|
13125
|
+
borderBottom: `1px solid ${tokens.colorNeutralStroke2}`,
|
|
13126
|
+
textAlign: "left",
|
|
13127
|
+
background: "none",
|
|
13128
|
+
// A native <button> does NOT inherit colour or font from its container — the user-agent
|
|
13129
|
+
// stylesheet gives it `color: buttontext` and its own font stack. Without these three the
|
|
13130
|
+
// rows rendered as near-black text on the dark surface in dark mode, which is how this was
|
|
13131
|
+
// first spotted. Set explicitly rather than relying on inheritance.
|
|
13132
|
+
color: tokens.colorNeutralForeground1,
|
|
13133
|
+
fontFamily: "inherit",
|
|
13134
|
+
fontSize: tokens.fontSizeBase300,
|
|
13135
|
+
// The UA also gives buttons a border; `background: none` alone leaves it drawing a box
|
|
13136
|
+
// around every row. Only three sides — borderBottom above is the row separator.
|
|
13137
|
+
borderTop: "none",
|
|
13138
|
+
borderRight: "none",
|
|
13139
|
+
borderLeft: "none",
|
|
13140
|
+
":hover": {
|
|
13141
|
+
backgroundColor: tokens.colorNeutralBackground1Hover,
|
|
13142
|
+
color: tokens.colorNeutralForeground1Hover
|
|
13143
|
+
},
|
|
13144
|
+
":focus-visible": {
|
|
13145
|
+
outline: `2px solid ${tokens.colorStrokeFocus2}`,
|
|
13146
|
+
outlineOffset: "-2px"
|
|
13147
|
+
}
|
|
13148
|
+
},
|
|
13149
|
+
resultSelected: {
|
|
13150
|
+
backgroundColor: tokens.colorBrandBackground,
|
|
13151
|
+
color: tokens.colorNeutralForegroundOnBrand,
|
|
13152
|
+
":hover": {
|
|
13153
|
+
backgroundColor: tokens.colorBrandBackgroundHover,
|
|
13154
|
+
// Repeated because the base row's :hover also sets colour, and whichever griffel emits
|
|
13155
|
+
// last would otherwise win — leaving selected-and-hovered text unreadable on the brand fill.
|
|
13156
|
+
color: tokens.colorNeutralForegroundOnBrand
|
|
13157
|
+
}
|
|
13158
|
+
},
|
|
13159
|
+
resultText: {
|
|
13160
|
+
display: "flex",
|
|
13161
|
+
flexDirection: "column",
|
|
13162
|
+
minWidth: 0
|
|
13163
|
+
},
|
|
13164
|
+
name: {
|
|
13165
|
+
fontSize: tokens.fontSizeBase300,
|
|
13166
|
+
overflow: "hidden",
|
|
13167
|
+
textOverflow: "ellipsis",
|
|
13168
|
+
whiteSpace: "nowrap"
|
|
13169
|
+
},
|
|
13170
|
+
email: {
|
|
13171
|
+
fontSize: tokens.fontSizeBase200,
|
|
13172
|
+
opacity: 0.8,
|
|
13173
|
+
overflow: "hidden",
|
|
13174
|
+
textOverflow: "ellipsis",
|
|
13175
|
+
whiteSpace: "nowrap"
|
|
13176
|
+
},
|
|
13177
|
+
status: {
|
|
13178
|
+
display: "flex",
|
|
13179
|
+
flexDirection: "row",
|
|
13180
|
+
alignItems: "center",
|
|
13181
|
+
columnGap: tokens.spacingHorizontalS,
|
|
13182
|
+
padding: tokens.spacingVerticalXL,
|
|
13183
|
+
color: tokens.colorNeutralForeground3,
|
|
13184
|
+
fontSize: tokens.fontSizeBase200
|
|
13185
|
+
},
|
|
13186
|
+
warning: {
|
|
13187
|
+
display: "flex",
|
|
13188
|
+
flexDirection: "row",
|
|
13189
|
+
alignItems: "flex-start",
|
|
13190
|
+
columnGap: tokens.spacingHorizontalS,
|
|
13191
|
+
padding: `${tokens.spacingVerticalS} ${tokens.spacingHorizontalM}`,
|
|
13192
|
+
borderRadius: tokens.borderRadiusMedium,
|
|
13193
|
+
backgroundColor: tokens.colorNeutralBackground2,
|
|
13194
|
+
borderLeft: `3px solid ${tokens.colorPaletteRedBackground3}`,
|
|
13195
|
+
fontSize: tokens.fontSizeBase200
|
|
13196
|
+
},
|
|
13197
|
+
footer: {
|
|
13198
|
+
display: "flex",
|
|
13199
|
+
flexDirection: "row",
|
|
13200
|
+
justifyContent: "flex-end",
|
|
13201
|
+
columnGap: tokens.spacingHorizontalS,
|
|
13202
|
+
paddingTop: tokens.spacingVerticalM
|
|
13203
|
+
}
|
|
13204
|
+
});
|
|
13205
|
+
function ImpersonationPickerDialog({
|
|
13206
|
+
open,
|
|
13207
|
+
onClose,
|
|
13208
|
+
returnUrl = "/",
|
|
13209
|
+
className
|
|
13210
|
+
}) {
|
|
13211
|
+
const auth = useAuth();
|
|
13212
|
+
const styles = useStyles7();
|
|
13213
|
+
const t = useT();
|
|
13214
|
+
const { searchImpersonationTargets, impersonate } = auth;
|
|
13215
|
+
const [query, setQuery] = useState("");
|
|
13216
|
+
const [results, setResults] = useState([]);
|
|
13217
|
+
const [selected, setSelected] = useState(null);
|
|
13218
|
+
const [isSearching, setIsSearching] = useState(false);
|
|
13219
|
+
const [hasSearched, setHasSearched] = useState(false);
|
|
13220
|
+
const [hasMore, setHasMore] = useState(false);
|
|
13221
|
+
const [isStarting, setIsStarting] = useState(false);
|
|
13222
|
+
const requestIdRef = useRef(0);
|
|
13223
|
+
useEffect(() => {
|
|
13224
|
+
if (open) return;
|
|
13225
|
+
setQuery("");
|
|
13226
|
+
setResults([]);
|
|
13227
|
+
setSelected(null);
|
|
13228
|
+
setIsSearching(false);
|
|
13229
|
+
setHasSearched(false);
|
|
13230
|
+
setHasMore(false);
|
|
13231
|
+
setIsStarting(false);
|
|
13232
|
+
}, [open]);
|
|
13233
|
+
const trimmed = query.trim();
|
|
13234
|
+
const isTooShort = trimmed.length > 0 && trimmed.length < MINIMUM_QUERY_LENGTH;
|
|
13235
|
+
useEffect(() => {
|
|
13236
|
+
if (!open) return;
|
|
13237
|
+
const requestId = ++requestIdRef.current;
|
|
13238
|
+
if (trimmed.length < MINIMUM_QUERY_LENGTH && !GUID_PATTERN.test(trimmed)) {
|
|
13239
|
+
setResults([]);
|
|
13240
|
+
setHasSearched(false);
|
|
13241
|
+
setHasMore(false);
|
|
13242
|
+
setIsSearching(false);
|
|
13243
|
+
return;
|
|
13244
|
+
}
|
|
13245
|
+
let cancelled = false;
|
|
13246
|
+
const timer = setTimeout(async () => {
|
|
13247
|
+
setIsSearching(true);
|
|
13248
|
+
try {
|
|
13249
|
+
const response = await searchImpersonationTargets(trimmed);
|
|
13250
|
+
if (cancelled || requestId !== requestIdRef.current) return;
|
|
13251
|
+
setResults(response.results ?? []);
|
|
13252
|
+
setHasMore(response.hasMore ?? false);
|
|
13253
|
+
setHasSearched(true);
|
|
13254
|
+
} catch {
|
|
13255
|
+
if (cancelled || requestId !== requestIdRef.current) return;
|
|
13256
|
+
setResults([]);
|
|
13257
|
+
setHasMore(false);
|
|
13258
|
+
setHasSearched(true);
|
|
13259
|
+
} finally {
|
|
13260
|
+
if (!cancelled && requestId === requestIdRef.current) {
|
|
13261
|
+
setIsSearching(false);
|
|
13262
|
+
}
|
|
13263
|
+
}
|
|
13264
|
+
}, SEARCH_DEBOUNCE_MS4);
|
|
13265
|
+
return () => {
|
|
13266
|
+
cancelled = true;
|
|
13267
|
+
clearTimeout(timer);
|
|
13268
|
+
};
|
|
13269
|
+
}, [open, searchImpersonationTargets, trimmed]);
|
|
13270
|
+
const handleQueryChange = useCallback((value) => {
|
|
13271
|
+
setQuery(value);
|
|
13272
|
+
setSelected(null);
|
|
13273
|
+
}, []);
|
|
13274
|
+
const handleConfirm = useCallback(async () => {
|
|
13275
|
+
if (!selected?.contactId) return;
|
|
13276
|
+
setIsStarting(true);
|
|
13277
|
+
try {
|
|
13278
|
+
const response = await impersonate(selected.contactId);
|
|
13279
|
+
if (response.result === ImpersonateResult.Started) {
|
|
13280
|
+
window.location.assign(returnUrl);
|
|
13281
|
+
return;
|
|
13282
|
+
}
|
|
13283
|
+
setIsStarting(false);
|
|
13284
|
+
onClose();
|
|
13285
|
+
} catch {
|
|
13286
|
+
setIsStarting(false);
|
|
13287
|
+
}
|
|
13288
|
+
}, [impersonate, onClose, returnUrl, selected]);
|
|
13289
|
+
return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange: (_, data) => {
|
|
13290
|
+
if (!data.open) onClose();
|
|
13291
|
+
}, children: /* @__PURE__ */ jsxs(
|
|
13292
|
+
DialogSurface,
|
|
13293
|
+
{
|
|
13294
|
+
className: mergeClasses("ppp-impersonation-picker-dialog", styles.surface, className),
|
|
13295
|
+
children: [
|
|
13296
|
+
/* @__PURE__ */ jsxs("div", { className: styles.titleRow, children: [
|
|
13297
|
+
/* @__PURE__ */ jsx(DialogTitle, { className: styles.titleText, children: t("app.components.impersonation-picker.title") }),
|
|
13298
|
+
/* @__PURE__ */ jsx(
|
|
13299
|
+
Button,
|
|
13300
|
+
{
|
|
13301
|
+
appearance: "subtle",
|
|
13302
|
+
icon: /* @__PURE__ */ jsx(Dismiss24Regular, {}),
|
|
13303
|
+
"aria-label": t("app.components.impersonation-picker.cancel"),
|
|
13304
|
+
onClick: onClose
|
|
13305
|
+
}
|
|
13306
|
+
)
|
|
13307
|
+
] }),
|
|
13308
|
+
/* @__PURE__ */ jsxs("div", { className: styles.body, children: [
|
|
13309
|
+
/* @__PURE__ */ jsx(
|
|
13310
|
+
SearchBox,
|
|
13311
|
+
{
|
|
13312
|
+
value: query,
|
|
13313
|
+
onChange: (_, data) => handleQueryChange(data.value),
|
|
13314
|
+
placeholder: t("app.components.impersonation-picker.search-placeholder"),
|
|
13315
|
+
appearance: "outline",
|
|
13316
|
+
style: { width: "100%" }
|
|
13317
|
+
}
|
|
13318
|
+
),
|
|
13319
|
+
/* @__PURE__ */ jsx("div", { className: styles.results, role: "listbox", children: isSearching ? /* @__PURE__ */ jsxs("div", { className: styles.status, children: [
|
|
13320
|
+
/* @__PURE__ */ jsx(Spinner, { size: "tiny" }),
|
|
13321
|
+
/* @__PURE__ */ jsx("span", { children: t("app.components.impersonation-picker.searching") })
|
|
13322
|
+
] }) : isTooShort ? (
|
|
13323
|
+
// Distinct from "no matches": the search hasn't run. Conflating the two reads as
|
|
13324
|
+
// "this person doesn't exist" when the user has simply typed too few characters.
|
|
13325
|
+
/* @__PURE__ */ jsx("div", { className: styles.status, children: t("app.components.impersonation-picker.hint", [String(MINIMUM_QUERY_LENGTH)]) })
|
|
13326
|
+
) : hasSearched && results.length === 0 ? /* @__PURE__ */ jsx("div", { className: styles.status, children: t("app.components.impersonation-picker.no-matches") }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
13327
|
+
results.map((candidate) => {
|
|
13328
|
+
const isSelected = selected?.contactId === candidate.contactId;
|
|
13329
|
+
return /* @__PURE__ */ jsxs(
|
|
13330
|
+
"button",
|
|
13331
|
+
{
|
|
13332
|
+
type: "button",
|
|
13333
|
+
role: "option",
|
|
13334
|
+
"aria-selected": isSelected,
|
|
13335
|
+
className: mergeClasses(
|
|
13336
|
+
styles.result,
|
|
13337
|
+
isSelected && styles.resultSelected
|
|
13338
|
+
),
|
|
13339
|
+
onClick: () => setSelected(candidate),
|
|
13340
|
+
children: [
|
|
13341
|
+
/* @__PURE__ */ jsx(Person20Regular, {}),
|
|
13342
|
+
/* @__PURE__ */ jsxs("span", { className: styles.resultText, children: [
|
|
13343
|
+
/* @__PURE__ */ jsx("span", { className: styles.name, children: candidate.fullName ?? candidate.email ?? candidate.contactId }),
|
|
13344
|
+
candidate.email && /* @__PURE__ */ jsx("span", { className: styles.email, children: candidate.email })
|
|
13345
|
+
] })
|
|
13346
|
+
]
|
|
13347
|
+
},
|
|
13348
|
+
candidate.contactId
|
|
13349
|
+
);
|
|
13350
|
+
}),
|
|
13351
|
+
hasMore && /* @__PURE__ */ jsx("div", { className: styles.status, children: t("app.components.impersonation-picker.too-many", [String(MAXIMUM_RESULTS)]) })
|
|
13352
|
+
] }) }),
|
|
13353
|
+
selected && /* @__PURE__ */ jsxs("div", { className: styles.warning, children: [
|
|
13354
|
+
/* @__PURE__ */ jsx(Warning20Regular, {}),
|
|
13355
|
+
/* @__PURE__ */ jsx("span", { children: t("app.components.impersonation-picker.warning") })
|
|
13356
|
+
] })
|
|
13357
|
+
] }),
|
|
13358
|
+
/* @__PURE__ */ jsxs("div", { className: styles.footer, children: [
|
|
13359
|
+
/* @__PURE__ */ jsx(
|
|
13360
|
+
Button,
|
|
13361
|
+
{
|
|
13362
|
+
appearance: "primary",
|
|
13363
|
+
icon: /* @__PURE__ */ jsx(EyeTracking20Regular, {}),
|
|
13364
|
+
disabled: !selected || isStarting,
|
|
13365
|
+
onClick: handleConfirm,
|
|
13366
|
+
children: t("app.components.impersonation-picker.confirm")
|
|
13367
|
+
}
|
|
13368
|
+
),
|
|
13369
|
+
/* @__PURE__ */ jsx(Button, { appearance: "secondary", onClick: onClose, disabled: isStarting, children: t("app.components.impersonation-picker.cancel") })
|
|
13370
|
+
] })
|
|
13371
|
+
]
|
|
13372
|
+
}
|
|
13373
|
+
) });
|
|
13374
|
+
}
|
|
13375
|
+
var IMPERSONATION_ROLE = "SystemAdmin";
|
|
13376
|
+
var useStyles8 = makeStyles({
|
|
12993
13377
|
trigger: {
|
|
12994
13378
|
backgroundColor: "transparent",
|
|
12995
13379
|
border: "none",
|
|
@@ -13049,8 +13433,9 @@ function ProfileMainMenu({
|
|
|
13049
13433
|
signInUrl = "/login"
|
|
13050
13434
|
}) {
|
|
13051
13435
|
const auth = useAuth();
|
|
13052
|
-
const styles =
|
|
13436
|
+
const styles = useStyles8();
|
|
13053
13437
|
const t = useT();
|
|
13438
|
+
const [isPickerOpen, setIsPickerOpen] = useState(false);
|
|
13054
13439
|
const handleLogout = useCallback(async () => {
|
|
13055
13440
|
try {
|
|
13056
13441
|
await auth.logout();
|
|
@@ -13067,7 +13452,14 @@ function ProfileMainMenu({
|
|
|
13067
13452
|
}
|
|
13068
13453
|
}, [auth]);
|
|
13069
13454
|
if (auth.status === AuthStatus.Loading) {
|
|
13070
|
-
return /* @__PURE__ */ jsx(
|
|
13455
|
+
return /* @__PURE__ */ jsx(
|
|
13456
|
+
Avatar,
|
|
13457
|
+
{
|
|
13458
|
+
className: "ppp-profile-main-menu",
|
|
13459
|
+
size: 28,
|
|
13460
|
+
"aria-label": t("app.messages.record-loading")
|
|
13461
|
+
}
|
|
13462
|
+
);
|
|
13071
13463
|
}
|
|
13072
13464
|
if (auth.status === AuthStatus.Anonymous) {
|
|
13073
13465
|
if (anonymousContent !== void 0) return /* @__PURE__ */ jsx(Fragment, { children: anonymousContent });
|
|
@@ -13088,61 +13480,126 @@ function ProfileMainMenu({
|
|
|
13088
13480
|
const resolvedAccountLabel = accountLabel ?? t("app.components.profile-main-menu.account");
|
|
13089
13481
|
const signedInAsLabel = t("app.components.profile-main-menu.signed-in-as");
|
|
13090
13482
|
const logoutLabel = t("app.buttons.logout.label");
|
|
13483
|
+
const canImpersonate = (auth.user.roles?.includes(IMPERSONATION_ROLE) ?? false) && auth.user.portalUserType === PortalUserType.SystemUser;
|
|
13091
13484
|
const altIdentityTableName = auth.user.altIdentityTableName;
|
|
13092
|
-
const switchIdentityLabel = altIdentityTableName ? t(
|
|
13093
|
-
"app.components.profile-main-menu.
|
|
13094
|
-
|
|
13095
|
-
|
|
13096
|
-
|
|
13097
|
-
|
|
13098
|
-
|
|
13099
|
-
|
|
13100
|
-
|
|
13485
|
+
const switchIdentityLabel = altIdentityTableName ? t("app.components.profile-main-menu.switch-to", [
|
|
13486
|
+
altIdentityTableName === "systemuser" ? t("app.components.profile-main-menu.alt-kind-systemuser") : t("app.components.profile-main-menu.alt-kind-contact")
|
|
13487
|
+
]) : null;
|
|
13488
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
13489
|
+
/* @__PURE__ */ jsxs(Menu, { children: [
|
|
13490
|
+
/* @__PURE__ */ jsx(MenuTrigger, { disableButtonEnhancement: true, children: /* @__PURE__ */ jsx(
|
|
13491
|
+
"button",
|
|
13492
|
+
{
|
|
13493
|
+
type: "button",
|
|
13494
|
+
className: mergeClasses("ppp-profile-main-menu", styles.trigger),
|
|
13495
|
+
"aria-label": email || logoutLabel,
|
|
13496
|
+
children: /* @__PURE__ */ jsx(Avatar, { size: 28, initials, name: email })
|
|
13497
|
+
}
|
|
13498
|
+
) }),
|
|
13499
|
+
/* @__PURE__ */ jsx(MenuPopover, { children: /* @__PURE__ */ jsxs("div", { className: styles.popoverBody, children: [
|
|
13500
|
+
headerSlot,
|
|
13501
|
+
/* @__PURE__ */ jsxs("div", { className: styles.identity, children: [
|
|
13502
|
+
/* @__PURE__ */ jsx(Avatar, { size: 40, initials, name: email }),
|
|
13503
|
+
/* @__PURE__ */ jsxs("div", { className: styles.identityText, children: [
|
|
13504
|
+
/* @__PURE__ */ jsx("span", { className: styles.identityLabel, children: signedInAsLabel }),
|
|
13505
|
+
/* @__PURE__ */ jsx("span", { className: styles.identityValue, title: email, children: email })
|
|
13506
|
+
] })
|
|
13507
|
+
] }),
|
|
13508
|
+
/* @__PURE__ */ jsx(Divider, {}),
|
|
13509
|
+
/* @__PURE__ */ jsxs(MenuList, { className: styles.actions, children: [
|
|
13510
|
+
accountUrl && /* @__PURE__ */ jsx(
|
|
13511
|
+
MenuItem,
|
|
13512
|
+
{
|
|
13513
|
+
icon: /* @__PURE__ */ jsx(PersonEdit20Regular, {}),
|
|
13514
|
+
onClick: () => {
|
|
13515
|
+
window.location.href = accountUrl;
|
|
13516
|
+
},
|
|
13517
|
+
children: resolvedAccountLabel
|
|
13518
|
+
}
|
|
13519
|
+
),
|
|
13520
|
+
switchIdentityLabel && /* @__PURE__ */ jsx(
|
|
13521
|
+
MenuItem,
|
|
13522
|
+
{
|
|
13523
|
+
icon: /* @__PURE__ */ jsx(ArrowSwap20Regular, {}),
|
|
13524
|
+
onClick: handleSwitchIdentity,
|
|
13525
|
+
children: switchIdentityLabel
|
|
13526
|
+
}
|
|
13527
|
+
),
|
|
13528
|
+
canImpersonate && /* @__PURE__ */ jsx(
|
|
13529
|
+
MenuItem,
|
|
13530
|
+
{
|
|
13531
|
+
icon: /* @__PURE__ */ jsx(EyeTracking20Regular, {}),
|
|
13532
|
+
onClick: () => setIsPickerOpen(true),
|
|
13533
|
+
children: t("app.components.profile-main-menu.impersonate")
|
|
13534
|
+
}
|
|
13535
|
+
),
|
|
13536
|
+
/* @__PURE__ */ jsx(MenuItem, { icon: /* @__PURE__ */ jsx(SignOut20Regular, {}), onClick: handleLogout, children: logoutLabel })
|
|
13537
|
+
] }),
|
|
13538
|
+
footerSlot && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
13539
|
+
/* @__PURE__ */ jsx(Divider, {}),
|
|
13540
|
+
footerSlot
|
|
13541
|
+
] })
|
|
13542
|
+
] }) })
|
|
13543
|
+
] }),
|
|
13544
|
+
canImpersonate && /* @__PURE__ */ jsx(
|
|
13545
|
+
ImpersonationPickerDialog,
|
|
13101
13546
|
{
|
|
13102
|
-
|
|
13103
|
-
|
|
13104
|
-
"aria-label": email || logoutLabel,
|
|
13105
|
-
children: /* @__PURE__ */ jsx(Avatar, { size: 28, initials, name: email })
|
|
13547
|
+
open: isPickerOpen,
|
|
13548
|
+
onClose: () => setIsPickerOpen(false)
|
|
13106
13549
|
}
|
|
13107
|
-
)
|
|
13108
|
-
/* @__PURE__ */ jsx(MenuPopover, { children: /* @__PURE__ */ jsxs("div", { className: styles.popoverBody, children: [
|
|
13109
|
-
headerSlot,
|
|
13110
|
-
/* @__PURE__ */ jsxs("div", { className: styles.identity, children: [
|
|
13111
|
-
/* @__PURE__ */ jsx(Avatar, { size: 40, initials, name: email }),
|
|
13112
|
-
/* @__PURE__ */ jsxs("div", { className: styles.identityText, children: [
|
|
13113
|
-
/* @__PURE__ */ jsx("span", { className: styles.identityLabel, children: signedInAsLabel }),
|
|
13114
|
-
/* @__PURE__ */ jsx("span", { className: styles.identityValue, title: email, children: email })
|
|
13115
|
-
] })
|
|
13116
|
-
] }),
|
|
13117
|
-
/* @__PURE__ */ jsx(Divider, {}),
|
|
13118
|
-
/* @__PURE__ */ jsxs(MenuList, { className: styles.actions, children: [
|
|
13119
|
-
accountUrl && /* @__PURE__ */ jsx(
|
|
13120
|
-
MenuItem,
|
|
13121
|
-
{
|
|
13122
|
-
icon: /* @__PURE__ */ jsx(PersonEdit20Regular, {}),
|
|
13123
|
-
onClick: () => {
|
|
13124
|
-
window.location.href = accountUrl;
|
|
13125
|
-
},
|
|
13126
|
-
children: resolvedAccountLabel
|
|
13127
|
-
}
|
|
13128
|
-
),
|
|
13129
|
-
switchIdentityLabel && /* @__PURE__ */ jsx(
|
|
13130
|
-
MenuItem,
|
|
13131
|
-
{
|
|
13132
|
-
icon: /* @__PURE__ */ jsx(ArrowSwap20Regular, {}),
|
|
13133
|
-
onClick: handleSwitchIdentity,
|
|
13134
|
-
children: switchIdentityLabel
|
|
13135
|
-
}
|
|
13136
|
-
),
|
|
13137
|
-
/* @__PURE__ */ jsx(MenuItem, { icon: /* @__PURE__ */ jsx(SignOut20Regular, {}), onClick: handleLogout, children: logoutLabel })
|
|
13138
|
-
] }),
|
|
13139
|
-
footerSlot && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
13140
|
-
/* @__PURE__ */ jsx(Divider, {}),
|
|
13141
|
-
footerSlot
|
|
13142
|
-
] })
|
|
13143
|
-
] }) })
|
|
13550
|
+
)
|
|
13144
13551
|
] });
|
|
13145
13552
|
}
|
|
13553
|
+
function ImpersonationBanner({
|
|
13554
|
+
returnUrl = "/",
|
|
13555
|
+
className
|
|
13556
|
+
}) {
|
|
13557
|
+
const auth = useAuth();
|
|
13558
|
+
const t = useT();
|
|
13559
|
+
const [isStopping, setIsStopping] = useState(false);
|
|
13560
|
+
const { stopImpersonation } = auth;
|
|
13561
|
+
const handleStop = useCallback(async () => {
|
|
13562
|
+
setIsStopping(true);
|
|
13563
|
+
try {
|
|
13564
|
+
await stopImpersonation();
|
|
13565
|
+
window.location.assign(returnUrl);
|
|
13566
|
+
} catch {
|
|
13567
|
+
setIsStopping(false);
|
|
13568
|
+
}
|
|
13569
|
+
}, [returnUrl, stopImpersonation]);
|
|
13570
|
+
if (auth.status !== AuthStatus.Authenticated || !auth.user.isImpersonating) {
|
|
13571
|
+
return null;
|
|
13572
|
+
}
|
|
13573
|
+
const viewingAs = auth.user.email ?? auth.user.userName ?? "";
|
|
13574
|
+
const impersonator = auth.user.impersonatorName;
|
|
13575
|
+
return (
|
|
13576
|
+
// The class is placement only — PageLayout targets it to assign the grid row. It carries no
|
|
13577
|
+
// appearance of its own; Fluent owns all of that.
|
|
13578
|
+
/* @__PURE__ */ jsxs(
|
|
13579
|
+
MessageBar,
|
|
13580
|
+
{
|
|
13581
|
+
className: mergeClasses("ppp-impersonation-banner", className),
|
|
13582
|
+
intent: "error",
|
|
13583
|
+
children: [
|
|
13584
|
+
/* @__PURE__ */ jsxs(MessageBarBody, { children: [
|
|
13585
|
+
/* @__PURE__ */ jsx(MessageBarTitle, { children: t("app.components.impersonation-banner.viewing-as", [viewingAs]) }),
|
|
13586
|
+
impersonator ? ` ${t("app.components.impersonation-banner.you-are", [impersonator])}` : null
|
|
13587
|
+
] }),
|
|
13588
|
+
/* @__PURE__ */ jsx(MessageBarActions, { children: /* @__PURE__ */ jsx(
|
|
13589
|
+
Button,
|
|
13590
|
+
{
|
|
13591
|
+
icon: /* @__PURE__ */ jsx(ArrowExit20Regular, {}),
|
|
13592
|
+
iconPosition: "after",
|
|
13593
|
+
disabled: isStopping,
|
|
13594
|
+
onClick: handleStop,
|
|
13595
|
+
children: t("app.components.impersonation-banner.stop")
|
|
13596
|
+
}
|
|
13597
|
+
) })
|
|
13598
|
+
]
|
|
13599
|
+
}
|
|
13600
|
+
)
|
|
13601
|
+
);
|
|
13602
|
+
}
|
|
13146
13603
|
var usePanelStyles = makeStyles({
|
|
13147
13604
|
// Vertical stack of setting sections with consistent gap. Matches the
|
|
13148
13605
|
// panel body the SiteSettingsButton's drawer renders, but extracted
|
|
@@ -13191,7 +13648,7 @@ function SiteSettingsPanel({
|
|
|
13191
13648
|
}
|
|
13192
13649
|
);
|
|
13193
13650
|
}
|
|
13194
|
-
var
|
|
13651
|
+
var useStyles9 = makeStyles({
|
|
13195
13652
|
// Wraps the standalone panel inside the drawer body to add the small
|
|
13196
13653
|
// top inset that the popover's title visually expects. The panel
|
|
13197
13654
|
// itself stays inset-free so it doesn't carry extra padding when
|
|
@@ -13211,7 +13668,7 @@ function SiteSettingsButton({
|
|
|
13211
13668
|
accentLabels
|
|
13212
13669
|
}) {
|
|
13213
13670
|
const t = useT();
|
|
13214
|
-
const styles =
|
|
13671
|
+
const styles = useStyles9();
|
|
13215
13672
|
const [open, setOpen] = useState(false);
|
|
13216
13673
|
const close = useCallback(() => setOpen(false), []);
|
|
13217
13674
|
const label = t("app.site-settings-label");
|
|
@@ -13689,7 +14146,7 @@ function bestRouteMatch(routes, pathname) {
|
|
|
13689
14146
|
}
|
|
13690
14147
|
return best;
|
|
13691
14148
|
}
|
|
13692
|
-
var
|
|
14149
|
+
var useStyles10 = makeStyles({
|
|
13693
14150
|
// Shared scrim look. Both global (full-screen) and scoped variants reuse
|
|
13694
14151
|
// these so the visual feel is identical — only the positioning differs.
|
|
13695
14152
|
// Theme-aware translucent backdrop drawn via a `::before` pseudo-element
|
|
@@ -13751,7 +14208,7 @@ function FluentOverlayProvider({ children }) {
|
|
|
13751
14208
|
] });
|
|
13752
14209
|
}
|
|
13753
14210
|
function GlobalOverlayLayer() {
|
|
13754
|
-
const styles =
|
|
14211
|
+
const styles = useStyles10();
|
|
13755
14212
|
const overlay = useOverlayForTarget(void 0);
|
|
13756
14213
|
if (!overlay) return null;
|
|
13757
14214
|
return /* @__PURE__ */ jsx(ScrimContent, { overlay, className: mergeClasses(styles.scrim, styles.global) });
|
|
@@ -13762,7 +14219,7 @@ function FluentOverlayTarget({
|
|
|
13762
14219
|
className,
|
|
13763
14220
|
style
|
|
13764
14221
|
}) {
|
|
13765
|
-
const styles =
|
|
14222
|
+
const styles = useStyles10();
|
|
13766
14223
|
const overlay = useOverlayForTarget(targetId);
|
|
13767
14224
|
return /* @__PURE__ */ jsxs("div", { className: mergeClasses("ppp-overlay-target", styles.scopedHost, className), style, children: [
|
|
13768
14225
|
children,
|
|
@@ -13770,14 +14227,14 @@ function FluentOverlayTarget({
|
|
|
13770
14227
|
] });
|
|
13771
14228
|
}
|
|
13772
14229
|
function ScrimContent({ overlay, className }) {
|
|
13773
|
-
const styles =
|
|
14230
|
+
const styles = useStyles10();
|
|
13774
14231
|
const showProgress = overlay.showProgress !== false;
|
|
13775
14232
|
return /* @__PURE__ */ jsxs("div", { className, role: "status", "aria-live": "polite", children: [
|
|
13776
14233
|
showProgress && /* @__PURE__ */ jsx(Spinner, { size: "large" }),
|
|
13777
14234
|
overlay.description && /* @__PURE__ */ jsx("span", { className: styles.description, children: overlay.description })
|
|
13778
14235
|
] });
|
|
13779
14236
|
}
|
|
13780
|
-
var
|
|
14237
|
+
var useStyles11 = makeStyles({
|
|
13781
14238
|
// Centered placeholder used while prefixes are being fetched. Same
|
|
13782
14239
|
// shape as the spinner blocks in `<NewRecordGridButton>` /
|
|
13783
14240
|
// `<OpenRecordGridButton>` dialogs (~160px min height + vertical
|
|
@@ -13797,7 +14254,7 @@ function LocalizationBoundary({
|
|
|
13797
14254
|
fallback,
|
|
13798
14255
|
children
|
|
13799
14256
|
}) {
|
|
13800
|
-
const styles =
|
|
14257
|
+
const styles = useStyles11();
|
|
13801
14258
|
const resolvedPrefixes = prefixes ?? EMPTY_PREFIXES;
|
|
13802
14259
|
const { locale } = useLocale();
|
|
13803
14260
|
useLocalization(resolvedPrefixes);
|
|
@@ -13819,7 +14276,7 @@ function LocalizationBoundary({
|
|
|
13819
14276
|
return /* @__PURE__ */ jsx("div", { className: mergeClasses("ppp-localization-boundary", styles.fallback), role: "status", "aria-live": "polite", children: /* @__PURE__ */ jsx(Spinner, { size: "medium" }) });
|
|
13820
14277
|
}
|
|
13821
14278
|
var EMPTY_PREFIXES = Object.freeze([]);
|
|
13822
|
-
var
|
|
14279
|
+
var useStyles12 = makeStyles({
|
|
13823
14280
|
root: {
|
|
13824
14281
|
display: "flex",
|
|
13825
14282
|
flexDirection: "column",
|
|
@@ -13877,7 +14334,7 @@ function isSameLanguage(a, b) {
|
|
|
13877
14334
|
return primaryA.length > 0 && primaryA === primary(b);
|
|
13878
14335
|
}
|
|
13879
14336
|
function LocalizationTranslator({ className }) {
|
|
13880
|
-
const styles =
|
|
14337
|
+
const styles = useStyles12();
|
|
13881
14338
|
const t = useT();
|
|
13882
14339
|
const { ppp } = usePowerPortalsPro();
|
|
13883
14340
|
const [availability, setAvailability] = useState(null);
|
|
@@ -14365,7 +14822,7 @@ function SectionColumnRenderer({
|
|
|
14365
14822
|
}
|
|
14366
14823
|
);
|
|
14367
14824
|
}
|
|
14368
|
-
var
|
|
14825
|
+
var useStyles13 = makeStyles({
|
|
14369
14826
|
root: {
|
|
14370
14827
|
display: "flex",
|
|
14371
14828
|
flexDirection: "column",
|
|
@@ -14445,6 +14902,18 @@ var useStyles12 = makeStyles({
|
|
|
14445
14902
|
},
|
|
14446
14903
|
// Scroll viewport for the merged grid so a tall result set scrolls inside the dialog.
|
|
14447
14904
|
dialogGrid: { maxHeight: "60vh", overflowY: "auto", overflowX: "auto" },
|
|
14905
|
+
// Merged-snapshot cells. Keys and sources are long single tokens (dotted keys,
|
|
14906
|
+
// backslash-only absolute paths) with no natural break opportunity, so without
|
|
14907
|
+
// this the text paints straight over the neighbouring column. `overflow-wrap:
|
|
14908
|
+
// anywhere` (not just `break-word`) is what makes the flex cell honour its
|
|
14909
|
+
// column width — it counts the soft breaks toward min-content — so the token
|
|
14910
|
+
// wraps inside the column instead of stretching it. Same recipe as
|
|
14911
|
+
// `sourceCell` in the per-source loads table above.
|
|
14912
|
+
mergedCell: {
|
|
14913
|
+
whiteSpace: "normal",
|
|
14914
|
+
overflowWrap: "anywhere",
|
|
14915
|
+
wordBreak: "break-word"
|
|
14916
|
+
},
|
|
14448
14917
|
filterInput: { minWidth: "260px" },
|
|
14449
14918
|
pager: { display: "flex", alignItems: "center", gap: tokens.spacingHorizontalS },
|
|
14450
14919
|
grow: { flex: 1 },
|
|
@@ -14476,7 +14945,7 @@ function cultureLabel(culture) {
|
|
|
14476
14945
|
}
|
|
14477
14946
|
}
|
|
14478
14947
|
function LocalizationAdmin({ className }) {
|
|
14479
|
-
const styles =
|
|
14948
|
+
const styles = useStyles13();
|
|
14480
14949
|
const t = useT();
|
|
14481
14950
|
const { ppp } = usePowerPortalsPro();
|
|
14482
14951
|
const [overview, setOverview] = useState(null);
|
|
@@ -14926,7 +15395,7 @@ function MergedSourcesDialog({
|
|
|
14926
15395
|
size: "small",
|
|
14927
15396
|
children: [
|
|
14928
15397
|
/* @__PURE__ */ jsx(DataGridHeader, { children: /* @__PURE__ */ jsx(DataGridRow, { children: ({ renderHeaderCell }) => /* @__PURE__ */ jsx(DataGridHeaderCell, { children: renderHeaderCell() }) }) }),
|
|
14929
|
-
/* @__PURE__ */ jsx(DataGridBody, { children: ({ item, rowId }) => /* @__PURE__ */ jsx(DataGridRow, { children: ({ renderCell }) => /* @__PURE__ */ jsx(DataGridCell, { children: renderCell(item) }) }, rowId) })
|
|
15398
|
+
/* @__PURE__ */ jsx(DataGridBody, { children: ({ item, rowId }) => /* @__PURE__ */ jsx(DataGridRow, { children: ({ renderCell }) => /* @__PURE__ */ jsx(DataGridCell, { className: styles.mergedCell, children: renderCell(item) }) }, rowId) })
|
|
14930
15399
|
]
|
|
14931
15400
|
}
|
|
14932
15401
|
) })
|
|
@@ -14946,7 +15415,7 @@ function MergedSourcesDialog({
|
|
|
14946
15415
|
] })
|
|
14947
15416
|
] }) }) });
|
|
14948
15417
|
}
|
|
14949
|
-
var
|
|
15418
|
+
var useStyles14 = makeStyles({
|
|
14950
15419
|
root: {
|
|
14951
15420
|
display: "flex",
|
|
14952
15421
|
flexDirection: "column",
|
|
@@ -14969,7 +15438,7 @@ var useStyles13 = makeStyles({
|
|
|
14969
15438
|
});
|
|
14970
15439
|
var toMs = (value) => Number(value);
|
|
14971
15440
|
function CacheAdmin({ className }) {
|
|
14972
|
-
const styles =
|
|
15441
|
+
const styles = useStyles14();
|
|
14973
15442
|
const t = useT();
|
|
14974
15443
|
const { ppp } = usePowerPortalsPro();
|
|
14975
15444
|
const [cacheNames, setCacheNames] = useState([]);
|
|
@@ -15104,7 +15573,7 @@ function CacheAdmin({ className }) {
|
|
|
15104
15573
|
] }) : null
|
|
15105
15574
|
] });
|
|
15106
15575
|
}
|
|
15107
|
-
var
|
|
15576
|
+
var useStyles15 = makeStyles({
|
|
15108
15577
|
list: {
|
|
15109
15578
|
margin: 0,
|
|
15110
15579
|
paddingLeft: tokens.spacingHorizontalXL,
|
|
@@ -15119,7 +15588,7 @@ function ValidationSummary({
|
|
|
15119
15588
|
className,
|
|
15120
15589
|
style
|
|
15121
15590
|
}) {
|
|
15122
|
-
const styles =
|
|
15591
|
+
const styles = useStyles15();
|
|
15123
15592
|
const t = useT();
|
|
15124
15593
|
const validation = useValidationContext();
|
|
15125
15594
|
const resolvedTitle = title === void 0 ? t("app.errors.form-validation-errors") : title;
|
|
@@ -15996,7 +16465,7 @@ function isWizardRecordPageElement(node) {
|
|
|
15996
16465
|
const type = node.type;
|
|
15997
16466
|
return !!type && type[PAGE_MARKER] === true;
|
|
15998
16467
|
}
|
|
15999
|
-
var
|
|
16468
|
+
var useStyles16 = makeStyles({
|
|
16000
16469
|
shell: {
|
|
16001
16470
|
display: "flex",
|
|
16002
16471
|
flexDirection: "column",
|
|
@@ -16138,7 +16607,7 @@ function WizardRecordFormInner({
|
|
|
16138
16607
|
stepperVisibility,
|
|
16139
16608
|
isCreate
|
|
16140
16609
|
}) {
|
|
16141
|
-
const styles =
|
|
16610
|
+
const styles = useStyles16();
|
|
16142
16611
|
return /* @__PURE__ */ jsx("div", { className: mergeClasses("ppp-wizard-record-form", styles.shell), children: /* @__PURE__ */ jsx(
|
|
16143
16612
|
Wizard,
|
|
16144
16613
|
{
|
|
@@ -16172,7 +16641,7 @@ function WizardFooter({
|
|
|
16172
16641
|
onCancel,
|
|
16173
16642
|
cancelLabel
|
|
16174
16643
|
}) {
|
|
16175
|
-
const styles =
|
|
16644
|
+
const styles = useStyles16();
|
|
16176
16645
|
const t = useT();
|
|
16177
16646
|
const recordContext = useRecordContext();
|
|
16178
16647
|
const wizard = useWizard();
|
|
@@ -17654,13 +18123,17 @@ var usePageLayoutStyles = makeStyles({
|
|
|
17654
18123
|
position: "relative",
|
|
17655
18124
|
display: "grid",
|
|
17656
18125
|
gridTemplateColumns: "auto minmax(0, 1fr)",
|
|
17657
|
-
|
|
18126
|
+
// Four rows, not three: the first carries the impersonation banner. It's an `auto` track and
|
|
18127
|
+
// the banner renders nothing for an ordinary session, so the row collapses to zero height and
|
|
18128
|
+
// the layout is unchanged whenever nobody is impersonating.
|
|
18129
|
+
gridTemplateRows: "auto auto 1fr auto",
|
|
17658
18130
|
// Lets the PageLayout shrink when it's nested inside another
|
|
17659
18131
|
// PageLayout's `<main>` (the outer main is a grid item; without
|
|
17660
18132
|
// `min-width: 0` on this inner root the outer's `minmax(0, 1fr)`
|
|
17661
18133
|
// track wouldn't be honored once content tries to grow wider).
|
|
17662
18134
|
minWidth: 0,
|
|
17663
18135
|
gridTemplateAreas: `
|
|
18136
|
+
'impersonation impersonation'
|
|
17664
18137
|
'header header'
|
|
17665
18138
|
'navigation main'
|
|
17666
18139
|
'footer footer'
|
|
@@ -17770,6 +18243,11 @@ var usePageLayoutStyles = makeStyles({
|
|
|
17770
18243
|
childHeader: {
|
|
17771
18244
|
borderBottomWidth: "1px"
|
|
17772
18245
|
},
|
|
18246
|
+
impersonationBanner: {
|
|
18247
|
+
// Placement only. The banner is a Fluent MessageBar and Fluent owns everything about how it
|
|
18248
|
+
// looks; this grid assignment is the extent of PageLayout's involvement.
|
|
18249
|
+
gridArea: "impersonation"
|
|
18250
|
+
},
|
|
17773
18251
|
navigation: {
|
|
17774
18252
|
gridArea: "navigation",
|
|
17775
18253
|
overflowY: "auto",
|
|
@@ -17896,6 +18374,7 @@ function PageLayout({
|
|
|
17896
18374
|
...resizable ? { "--ppp-nav-width": `${navWidth}px` } : {}
|
|
17897
18375
|
};
|
|
17898
18376
|
return /* @__PURE__ */ jsx(PageLayoutNestingContext.Provider, { value: { isNested: true }, children: /* @__PURE__ */ jsxs("div", { className: rootClass, style: rootStyle, children: [
|
|
18377
|
+
!isNested && /* @__PURE__ */ jsx(ImpersonationBanner, { className: styles.impersonationBanner }),
|
|
17899
18378
|
header !== void 0 && headerVisible && /* @__PURE__ */ jsx(Header, { className: headerClass, ...headerStyle && { style: headerStyle }, children: header }),
|
|
17900
18379
|
navigation !== void 0 && navigationVisible && /* @__PURE__ */ jsx(
|
|
17901
18380
|
"nav",
|
|
@@ -18124,7 +18603,7 @@ var RADIAL_CHART_TYPES = /* @__PURE__ */ new Set([
|
|
|
18124
18603
|
ChartType.Radar,
|
|
18125
18604
|
ChartType.Funnel
|
|
18126
18605
|
]);
|
|
18127
|
-
var
|
|
18606
|
+
var useStyles17 = makeStyles({
|
|
18128
18607
|
// The wrapper uses Fluent design tokens directly so the rounded bordered
|
|
18129
18608
|
// look picks up theme changes. `colorNeutralBackground1` (white in light,
|
|
18130
18609
|
// grey[16] in dark) matches the Blazor FluentUIChart's
|
|
@@ -18202,7 +18681,7 @@ function FluentUIChartImpl(props, ref) {
|
|
|
18202
18681
|
showBorder = true,
|
|
18203
18682
|
onElementClick
|
|
18204
18683
|
} = props;
|
|
18205
|
-
const styles =
|
|
18684
|
+
const styles = useStyles17();
|
|
18206
18685
|
const containerRef = useRef(null);
|
|
18207
18686
|
const palette = useFluentChartPalette(containerRef);
|
|
18208
18687
|
const themedDatasets = useMemo(() => {
|
|
@@ -18283,7 +18762,7 @@ function assembleTheme(palette, yAxisPrefix, yAxisSuffix, xAxisPrefix, xAxisSuff
|
|
|
18283
18762
|
if (orientation !== void 0) theme.indexAxis = toIndexAxis(orientation);
|
|
18284
18763
|
return Object.keys(theme).length > 0 ? theme : void 0;
|
|
18285
18764
|
}
|
|
18286
|
-
var
|
|
18765
|
+
var useStyles18 = makeStyles({
|
|
18287
18766
|
// Outer container — flex column so the view selector, message bar, and
|
|
18288
18767
|
// chart fill share the caller's height budget.
|
|
18289
18768
|
root: {
|
|
@@ -18361,7 +18840,7 @@ var DataverseChart = forwardRef(
|
|
|
18361
18840
|
} = props;
|
|
18362
18841
|
const chartSource = dataSource instanceof DataverseChartDataSource ? dataSource : void 0;
|
|
18363
18842
|
const viewDs = dataSource instanceof DataverseChartDataSource ? void 0 : dataSource;
|
|
18364
|
-
const styles =
|
|
18843
|
+
const styles = useStyles18();
|
|
18365
18844
|
const t = useT();
|
|
18366
18845
|
const { ppp, viewMetadataCache } = usePowerPortalsPro();
|
|
18367
18846
|
const [data, setData] = useState({ labels: [], datasets: [] });
|
|
@@ -18595,6 +19074,6 @@ function applyViewIdToSource(source, viewId) {
|
|
|
18595
19074
|
// src/index.ts
|
|
18596
19075
|
var VERSION = "0.1.0";
|
|
18597
19076
|
|
|
18598
|
-
export { Body, BoolEdit, BoolEditorType, CacheAdmin, ChoiceEdit, ChoiceEditorType, ChoiceInvalidValueBehavior, ChoiceOrientation, ChoiceValueSort, ColumnDisplayValue, ColumnEdit, DataverseChart, DateTimeEdit, DateTimeEditorType, DeleteContextButton, DeleteRecordGridButton, DescriptionLocation, FileEdit, FileGrid, FileViewer, FluentDialogProvider, FluentOverlayProvider, FluentOverlayTarget, FluentUIChart, Footer, GridButton, GridButtonBehavior, GridButtonRole, GridButtons, GridColumn, GridColumns, GridTemplateColumn, Header, Highlighter, ImageEdit, ImageViewer, LabelPosition, LanguageDropdown, LinkExistingRecordGridButton, LocalizationAdmin, LocalizationBoundary, LocalizationTranslator, LogoutButton, LookupDialog, LookupEdit, LookupEditorType, LookupForm, MainGrid, ManyToManyLookupEdit, ManyToManyLookupEditorType, MaskedTextField, MemoEdit, MenuBar, MoneyEdit, MultiSelectChoiceEdit, NavGroup, NavItem, NavMenu, NavigateNewRecordGridButton, NavigateOpenRecordGridButton, NavigateRecordGridButton, NewRecordGridButton, NumberEdit, OFFICE_ACCENT_DEFINITIONS, OFFICE_ACCENT_HEX_TO_NAME, OFFICE_ACCENT_THEMES, OFFICE_COLOR_NAME_TO_ACCENT, OpenRecordGridButton, PageLayout, PagingMode, PowerPortalsProThemeProvider, ProfileMainMenu, RefreshContextButton, RefreshGridButton, RouterUnsavedChangesGuard, SaveContextButton, Section, SectionColumn, SectionColumnOrientation, SiteSettingsButton, SiteSettingsPanel, SubGrid, TextDirection, TextEdit, ThemeColorSelector, ThemeMode, ThemeSelector, ThemeTextDirection, UnlinkExistingRecordGridButton, VERSION, ValidationSummary, ViewSort, WizardRecordForm, WizardRecordPage, evaluateGridButtonBehavior, findFirstButtonOfRole, getCellRenderer, getChartPalette, getChoiceMetadata, getDisplayDescription, getDisplayLabel, getEditComponentForMetadata, getEditComponentForType, getGridButtonRoleFromElement, getLookupMetadata, getNumberLimits, getRendererTypeForMetadata, getStringMaxLength, isColumnSortable, isMetadataReadOnly, isMetadataRequired, isNewRecord, officeColorValueToAccentName, resolveColumnDisplayValue, setGridButtonRole, splitHighlightSegments, toTranslucent, useBoolColumn, useChoiceColumn, useDateColumn, useFileColumn, useFluentChartPalette, useGridContext, useLookupColumn, useMoneyColumn, useMultiSelectChoiceColumn, useNumberColumn, useStringColumn, useTheme };
|
|
19077
|
+
export { Body, BoolEdit, BoolEditorType, CacheAdmin, ChoiceEdit, ChoiceEditorType, ChoiceInvalidValueBehavior, ChoiceOrientation, ChoiceValueSort, ColumnDisplayValue, ColumnEdit, DataverseChart, DateTimeEdit, DateTimeEditorType, DeleteContextButton, DeleteRecordGridButton, DescriptionLocation, FileEdit, FileGrid, FileViewer, FluentDialogProvider, FluentOverlayProvider, FluentOverlayTarget, FluentUIChart, Footer, GridButton, GridButtonBehavior, GridButtonRole, GridButtons, GridColumn, GridColumns, GridTemplateColumn, Header, Highlighter, ImageEdit, ImageViewer, ImpersonationBanner, ImpersonationPickerDialog, LabelPosition, LanguageDropdown, LinkExistingRecordGridButton, LocalizationAdmin, LocalizationBoundary, LocalizationTranslator, LogoutButton, LookupDialog, LookupEdit, LookupEditorType, LookupForm, MainGrid, ManyToManyLookupEdit, ManyToManyLookupEditorType, MaskedTextField, MemoEdit, MenuBar, MoneyEdit, MultiSelectChoiceEdit, NavGroup, NavItem, NavMenu, NavigateNewRecordGridButton, NavigateOpenRecordGridButton, NavigateRecordGridButton, NewRecordGridButton, NumberEdit, OFFICE_ACCENT_DEFINITIONS, OFFICE_ACCENT_HEX_TO_NAME, OFFICE_ACCENT_THEMES, OFFICE_COLOR_NAME_TO_ACCENT, OpenRecordGridButton, PageLayout, PagingMode, PowerPortalsProThemeProvider, ProfileMainMenu, RefreshContextButton, RefreshGridButton, RouterUnsavedChangesGuard, SaveContextButton, Section, SectionColumn, SectionColumnOrientation, SiteSettingsButton, SiteSettingsPanel, SubGrid, TextDirection, TextEdit, ThemeColorSelector, ThemeMode, ThemeSelector, ThemeTextDirection, UnlinkExistingRecordGridButton, VERSION, ValidationSummary, ViewSort, WizardRecordForm, WizardRecordPage, evaluateGridButtonBehavior, findFirstButtonOfRole, getCellRenderer, getChartPalette, getChoiceMetadata, getDisplayDescription, getDisplayLabel, getEditComponentForMetadata, getEditComponentForType, getGridButtonRoleFromElement, getLookupMetadata, getNumberLimits, getRendererTypeForMetadata, getStringMaxLength, isColumnSortable, isMetadataReadOnly, isMetadataRequired, isNewRecord, officeColorValueToAccentName, resolveColumnDisplayValue, setGridButtonRole, splitHighlightSegments, toTranslucent, useBoolColumn, useChoiceColumn, useDateColumn, useFileColumn, useFluentChartPalette, useGridContext, useLookupColumn, useMoneyColumn, useMultiSelectChoiceColumn, useNumberColumn, useStringColumn, useTheme };
|
|
18599
19078
|
//# sourceMappingURL=index.js.map
|
|
18600
19079
|
//# sourceMappingURL=index.js.map
|