@dloizides/ui-access-admin 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -0
- package/dist/index.d.mts +54 -7
- package/dist/index.d.ts +54 -7
- package/dist/index.js +201 -41
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +202 -44
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,29 @@ All notable changes to `@dloizides/ui-access-admin` are documented here.
|
|
|
5
5
|
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the
|
|
6
6
|
project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.3.0]
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- `PermissionMatrix`: read-only roles x permissions view (FINREG-FUNDS-1 "Tenant funds, deal gate, blocking and roles", AC-R2). Data injected; one card per role below `LAYOUT_COLLAPSE_BREAKPOINT`, a table above it.
|
|
13
|
+
- `UserManagementPanel` edit modal: a required block reason when Active is off, sent as `blockedReason` (AC-B1). New `UserManagementPatch` type; `UserManagementUser.blockedReason`.
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- Peer `@dloizides/ui-layout` raised to `>=1.27.0` (needs `LAYOUT_COLLAPSE_BREAKPOINT`).
|
|
18
|
+
|
|
19
|
+
## [1.2.2]
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
- **`UserManagementPanel` — the create/edit Role & Tenant pickers did nothing on click.** They use
|
|
24
|
+
`ModalDropdown`, whose responsive default renders the INLINE menu on desktop web — a popover that
|
|
25
|
+
`createPortal`s to `document.body`. Inside the panel's `ModalShell` (an RN `Modal`) that portal
|
|
26
|
+
lands OUTSIDE the shell's focus-trapping layer, so it rendered behind the modal and was dismissed
|
|
27
|
+
the instant it opened (the trigger's `aria-expanded` flipped straight back to `false`). `PickerField`
|
|
28
|
+
now forces `variant={DropdownVariant.Modal}`, which renders the options in their own RN-`Modal`
|
|
29
|
+
layer that stacks ABOVE the shell — visible and tappable. Added `PickerField.test.tsx` to pin it.
|
|
30
|
+
|
|
8
31
|
## [1.2.0]
|
|
9
32
|
|
|
10
33
|
### Added
|
package/dist/index.d.mts
CHANGED
|
@@ -336,9 +336,17 @@ interface UserManagementUser {
|
|
|
336
336
|
/** The tenant this user belongs to, or null for a platform-level account. */
|
|
337
337
|
tenantId: string | null;
|
|
338
338
|
active: boolean;
|
|
339
|
+
blockedReason?: string | null;
|
|
339
340
|
/** ISO timestamp the user was created, when the directory reports it. */
|
|
340
341
|
createdAt?: string;
|
|
341
342
|
}
|
|
343
|
+
interface UserManagementPatch {
|
|
344
|
+
displayName?: string;
|
|
345
|
+
role?: string;
|
|
346
|
+
tenantId?: string | null;
|
|
347
|
+
active?: boolean;
|
|
348
|
+
blockedReason?: string;
|
|
349
|
+
}
|
|
342
350
|
/** What the host is asked to do. Each rejects with an `Error` on failure. */
|
|
343
351
|
interface UserManagementApi {
|
|
344
352
|
listUsers(): Promise<UserManagementUser[]>;
|
|
@@ -349,12 +357,7 @@ interface UserManagementApi {
|
|
|
349
357
|
role: string;
|
|
350
358
|
tenantId: string | null;
|
|
351
359
|
}): Promise<void>;
|
|
352
|
-
updateUser(id: string, patch:
|
|
353
|
-
displayName?: string;
|
|
354
|
-
role?: string;
|
|
355
|
-
tenantId?: string | null;
|
|
356
|
-
active?: boolean;
|
|
357
|
-
}): Promise<void>;
|
|
360
|
+
updateUser(id: string, patch: UserManagementPatch): Promise<void>;
|
|
358
361
|
resetPassword(id: string, password: string): Promise<void>;
|
|
359
362
|
}
|
|
360
363
|
/** One selectable tenant for the platform-admin tenant picker. */
|
|
@@ -403,6 +406,37 @@ interface UserManagementPanelProps {
|
|
|
403
406
|
|
|
404
407
|
declare const UserManagementPanel: ({ api, isPlatformAdmin, assignableRoles, tenants, t, testID, }: UserManagementPanelProps) => React.ReactElement;
|
|
405
408
|
|
|
409
|
+
type PermissionMatrixTranslate = (key: string, p1?: string, p2?: string, p3?: string) => string;
|
|
410
|
+
interface PermissionMatrixRole {
|
|
411
|
+
readonly id: string;
|
|
412
|
+
readonly label: string;
|
|
413
|
+
}
|
|
414
|
+
interface PermissionMatrixPermission {
|
|
415
|
+
readonly id: string;
|
|
416
|
+
readonly label: string;
|
|
417
|
+
}
|
|
418
|
+
type PermissionMatrixGrants = Readonly<Record<string, readonly string[] | undefined>>;
|
|
419
|
+
interface PermissionMatrixCell {
|
|
420
|
+
readonly permission: PermissionMatrixPermission;
|
|
421
|
+
readonly granted: boolean;
|
|
422
|
+
}
|
|
423
|
+
interface PermissionMatrixColumn {
|
|
424
|
+
readonly role: PermissionMatrixRole;
|
|
425
|
+
readonly cells: readonly PermissionMatrixCell[];
|
|
426
|
+
readonly grantedCount: number;
|
|
427
|
+
}
|
|
428
|
+
interface PermissionMatrixProps {
|
|
429
|
+
readonly roles: readonly PermissionMatrixRole[];
|
|
430
|
+
readonly permissions: readonly PermissionMatrixPermission[];
|
|
431
|
+
readonly grants: PermissionMatrixGrants;
|
|
432
|
+
readonly t: PermissionMatrixTranslate;
|
|
433
|
+
readonly testID?: string;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
declare const PermissionMatrix: ({ roles, permissions, grants, t, testID, }: PermissionMatrixProps) => React.ReactElement;
|
|
437
|
+
|
|
438
|
+
declare function buildPermissionMatrix(roles: readonly PermissionMatrixRole[], permissions: readonly PermissionMatrixPermission[], grants: PermissionMatrixGrants): PermissionMatrixColumn[];
|
|
439
|
+
|
|
406
440
|
/** Translate function — mirrors the fleet's `FM(key, p1?, p2?, p3?)` shape. */
|
|
407
441
|
type AccessTranslate = (key: string, p1?: string, p2?: string, p3?: string) => string;
|
|
408
442
|
interface UseCapabilityLinkMintOptions {
|
|
@@ -702,6 +736,18 @@ declare const ACCESS_ADMIN_I18N: {
|
|
|
702
736
|
readonly usersUpdateFailed: "accessAdmin.users.updateFailed";
|
|
703
737
|
readonly usersResetSuccess: "accessAdmin.users.resetSuccess";
|
|
704
738
|
readonly usersResetFailed: "accessAdmin.users.resetFailed";
|
|
739
|
+
readonly usersFieldBlockedReason: "accessAdmin.users.fieldBlockedReason";
|
|
740
|
+
readonly usersBlockedReasonPlaceholder: "accessAdmin.users.blockedReasonPlaceholder";
|
|
741
|
+
readonly usersBlockedReasonHint: "accessAdmin.users.blockedReasonHint";
|
|
742
|
+
readonly permissionsHeading: "accessAdmin.permissions.heading";
|
|
743
|
+
readonly permissionsNote: "accessAdmin.permissions.note";
|
|
744
|
+
readonly permissionsColPermission: "accessAdmin.permissions.colPermission";
|
|
745
|
+
readonly permissionsGranted: "accessAdmin.permissions.granted";
|
|
746
|
+
readonly permissionsNotGranted: "accessAdmin.permissions.notGranted";
|
|
747
|
+
readonly permissionsCellLabel: "accessAdmin.permissions.cellLabel";
|
|
748
|
+
readonly permissionsReadOnlyHint: "accessAdmin.permissions.readOnlyHint";
|
|
749
|
+
readonly permissionsRoleCount: "accessAdmin.permissions.roleCount";
|
|
750
|
+
readonly permissionsEmpty: "accessAdmin.permissions.empty";
|
|
705
751
|
};
|
|
706
752
|
/** The shape of {@link ACCESS_ADMIN_I18N} — useful for typing an override map. */
|
|
707
753
|
type AccessAdminI18n = typeof ACCESS_ADMIN_I18N;
|
|
@@ -714,6 +760,7 @@ declare const ACCESS_ADMIN_TEST_IDS: {
|
|
|
714
760
|
readonly linkPanel: "access-link-panel";
|
|
715
761
|
readonly accountPanel: "account-link-panel";
|
|
716
762
|
readonly usersPanel: "user-management-panel";
|
|
763
|
+
readonly permissionMatrix: "permission-matrix";
|
|
717
764
|
};
|
|
718
765
|
|
|
719
|
-
export { ACCESS_ADMIN_I18N, ACCESS_ADMIN_TEST_IDS, type AccessAdminI18n, type AccessAdminPalette, AccessLinkPanel, type AccessLinkPanelProps, type AccessResultReporter, AccessResultTone, type AccessSubject, type AccessTranslate, AccountLinkPanel, type AccountLinkPanelProps, type CapabilityLink, type CapabilityLinkMintState, type DescribeError, type ExpiryPolicy, type LinkSubjectAccount, type LinkableAccount, type MintCapabilityLink, type MintCapabilityLinkInput, type SubjectAccountLinkState, type UseCapabilityLinkMintOptions, type UseSubjectAccountLinkOptions, type UserManagementApi, UserManagementPanel, type UserManagementPanelProps, type UserManagementTenant, type UserManagementTranslate, type UserManagementUser, accountDisplayLabel, activeLinksForSubject, buildAccountOptions, buildCapabilityLinkMailto, capabilityExpiryDate, capabilityExpiryDays, daysUntilAnchor, formatLinkDate, linksForSubject, useAccessAdminPalette, useCapabilityLinkMint, useSubjectAccountLink };
|
|
766
|
+
export { ACCESS_ADMIN_I18N, ACCESS_ADMIN_TEST_IDS, type AccessAdminI18n, type AccessAdminPalette, AccessLinkPanel, type AccessLinkPanelProps, type AccessResultReporter, AccessResultTone, type AccessSubject, type AccessTranslate, AccountLinkPanel, type AccountLinkPanelProps, type CapabilityLink, type CapabilityLinkMintState, type DescribeError, type ExpiryPolicy, type LinkSubjectAccount, type LinkableAccount, type MintCapabilityLink, type MintCapabilityLinkInput, PermissionMatrix, type PermissionMatrixColumn, type PermissionMatrixGrants, type PermissionMatrixPermission, type PermissionMatrixProps, type PermissionMatrixRole, type PermissionMatrixTranslate, type SubjectAccountLinkState, type UseCapabilityLinkMintOptions, type UseSubjectAccountLinkOptions, type UserManagementApi, UserManagementPanel, type UserManagementPanelProps, type UserManagementPatch, type UserManagementTenant, type UserManagementTranslate, type UserManagementUser, accountDisplayLabel, activeLinksForSubject, buildAccountOptions, buildCapabilityLinkMailto, buildPermissionMatrix, capabilityExpiryDate, capabilityExpiryDays, daysUntilAnchor, formatLinkDate, linksForSubject, useAccessAdminPalette, useCapabilityLinkMint, useSubjectAccountLink };
|
package/dist/index.d.ts
CHANGED
|
@@ -336,9 +336,17 @@ interface UserManagementUser {
|
|
|
336
336
|
/** The tenant this user belongs to, or null for a platform-level account. */
|
|
337
337
|
tenantId: string | null;
|
|
338
338
|
active: boolean;
|
|
339
|
+
blockedReason?: string | null;
|
|
339
340
|
/** ISO timestamp the user was created, when the directory reports it. */
|
|
340
341
|
createdAt?: string;
|
|
341
342
|
}
|
|
343
|
+
interface UserManagementPatch {
|
|
344
|
+
displayName?: string;
|
|
345
|
+
role?: string;
|
|
346
|
+
tenantId?: string | null;
|
|
347
|
+
active?: boolean;
|
|
348
|
+
blockedReason?: string;
|
|
349
|
+
}
|
|
342
350
|
/** What the host is asked to do. Each rejects with an `Error` on failure. */
|
|
343
351
|
interface UserManagementApi {
|
|
344
352
|
listUsers(): Promise<UserManagementUser[]>;
|
|
@@ -349,12 +357,7 @@ interface UserManagementApi {
|
|
|
349
357
|
role: string;
|
|
350
358
|
tenantId: string | null;
|
|
351
359
|
}): Promise<void>;
|
|
352
|
-
updateUser(id: string, patch:
|
|
353
|
-
displayName?: string;
|
|
354
|
-
role?: string;
|
|
355
|
-
tenantId?: string | null;
|
|
356
|
-
active?: boolean;
|
|
357
|
-
}): Promise<void>;
|
|
360
|
+
updateUser(id: string, patch: UserManagementPatch): Promise<void>;
|
|
358
361
|
resetPassword(id: string, password: string): Promise<void>;
|
|
359
362
|
}
|
|
360
363
|
/** One selectable tenant for the platform-admin tenant picker. */
|
|
@@ -403,6 +406,37 @@ interface UserManagementPanelProps {
|
|
|
403
406
|
|
|
404
407
|
declare const UserManagementPanel: ({ api, isPlatformAdmin, assignableRoles, tenants, t, testID, }: UserManagementPanelProps) => React.ReactElement;
|
|
405
408
|
|
|
409
|
+
type PermissionMatrixTranslate = (key: string, p1?: string, p2?: string, p3?: string) => string;
|
|
410
|
+
interface PermissionMatrixRole {
|
|
411
|
+
readonly id: string;
|
|
412
|
+
readonly label: string;
|
|
413
|
+
}
|
|
414
|
+
interface PermissionMatrixPermission {
|
|
415
|
+
readonly id: string;
|
|
416
|
+
readonly label: string;
|
|
417
|
+
}
|
|
418
|
+
type PermissionMatrixGrants = Readonly<Record<string, readonly string[] | undefined>>;
|
|
419
|
+
interface PermissionMatrixCell {
|
|
420
|
+
readonly permission: PermissionMatrixPermission;
|
|
421
|
+
readonly granted: boolean;
|
|
422
|
+
}
|
|
423
|
+
interface PermissionMatrixColumn {
|
|
424
|
+
readonly role: PermissionMatrixRole;
|
|
425
|
+
readonly cells: readonly PermissionMatrixCell[];
|
|
426
|
+
readonly grantedCount: number;
|
|
427
|
+
}
|
|
428
|
+
interface PermissionMatrixProps {
|
|
429
|
+
readonly roles: readonly PermissionMatrixRole[];
|
|
430
|
+
readonly permissions: readonly PermissionMatrixPermission[];
|
|
431
|
+
readonly grants: PermissionMatrixGrants;
|
|
432
|
+
readonly t: PermissionMatrixTranslate;
|
|
433
|
+
readonly testID?: string;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
declare const PermissionMatrix: ({ roles, permissions, grants, t, testID, }: PermissionMatrixProps) => React.ReactElement;
|
|
437
|
+
|
|
438
|
+
declare function buildPermissionMatrix(roles: readonly PermissionMatrixRole[], permissions: readonly PermissionMatrixPermission[], grants: PermissionMatrixGrants): PermissionMatrixColumn[];
|
|
439
|
+
|
|
406
440
|
/** Translate function — mirrors the fleet's `FM(key, p1?, p2?, p3?)` shape. */
|
|
407
441
|
type AccessTranslate = (key: string, p1?: string, p2?: string, p3?: string) => string;
|
|
408
442
|
interface UseCapabilityLinkMintOptions {
|
|
@@ -702,6 +736,18 @@ declare const ACCESS_ADMIN_I18N: {
|
|
|
702
736
|
readonly usersUpdateFailed: "accessAdmin.users.updateFailed";
|
|
703
737
|
readonly usersResetSuccess: "accessAdmin.users.resetSuccess";
|
|
704
738
|
readonly usersResetFailed: "accessAdmin.users.resetFailed";
|
|
739
|
+
readonly usersFieldBlockedReason: "accessAdmin.users.fieldBlockedReason";
|
|
740
|
+
readonly usersBlockedReasonPlaceholder: "accessAdmin.users.blockedReasonPlaceholder";
|
|
741
|
+
readonly usersBlockedReasonHint: "accessAdmin.users.blockedReasonHint";
|
|
742
|
+
readonly permissionsHeading: "accessAdmin.permissions.heading";
|
|
743
|
+
readonly permissionsNote: "accessAdmin.permissions.note";
|
|
744
|
+
readonly permissionsColPermission: "accessAdmin.permissions.colPermission";
|
|
745
|
+
readonly permissionsGranted: "accessAdmin.permissions.granted";
|
|
746
|
+
readonly permissionsNotGranted: "accessAdmin.permissions.notGranted";
|
|
747
|
+
readonly permissionsCellLabel: "accessAdmin.permissions.cellLabel";
|
|
748
|
+
readonly permissionsReadOnlyHint: "accessAdmin.permissions.readOnlyHint";
|
|
749
|
+
readonly permissionsRoleCount: "accessAdmin.permissions.roleCount";
|
|
750
|
+
readonly permissionsEmpty: "accessAdmin.permissions.empty";
|
|
705
751
|
};
|
|
706
752
|
/** The shape of {@link ACCESS_ADMIN_I18N} — useful for typing an override map. */
|
|
707
753
|
type AccessAdminI18n = typeof ACCESS_ADMIN_I18N;
|
|
@@ -714,6 +760,7 @@ declare const ACCESS_ADMIN_TEST_IDS: {
|
|
|
714
760
|
readonly linkPanel: "access-link-panel";
|
|
715
761
|
readonly accountPanel: "account-link-panel";
|
|
716
762
|
readonly usersPanel: "user-management-panel";
|
|
763
|
+
readonly permissionMatrix: "permission-matrix";
|
|
717
764
|
};
|
|
718
765
|
|
|
719
|
-
export { ACCESS_ADMIN_I18N, ACCESS_ADMIN_TEST_IDS, type AccessAdminI18n, type AccessAdminPalette, AccessLinkPanel, type AccessLinkPanelProps, type AccessResultReporter, AccessResultTone, type AccessSubject, type AccessTranslate, AccountLinkPanel, type AccountLinkPanelProps, type CapabilityLink, type CapabilityLinkMintState, type DescribeError, type ExpiryPolicy, type LinkSubjectAccount, type LinkableAccount, type MintCapabilityLink, type MintCapabilityLinkInput, type SubjectAccountLinkState, type UseCapabilityLinkMintOptions, type UseSubjectAccountLinkOptions, type UserManagementApi, UserManagementPanel, type UserManagementPanelProps, type UserManagementTenant, type UserManagementTranslate, type UserManagementUser, accountDisplayLabel, activeLinksForSubject, buildAccountOptions, buildCapabilityLinkMailto, capabilityExpiryDate, capabilityExpiryDays, daysUntilAnchor, formatLinkDate, linksForSubject, useAccessAdminPalette, useCapabilityLinkMint, useSubjectAccountLink };
|
|
766
|
+
export { ACCESS_ADMIN_I18N, ACCESS_ADMIN_TEST_IDS, type AccessAdminI18n, type AccessAdminPalette, AccessLinkPanel, type AccessLinkPanelProps, type AccessResultReporter, AccessResultTone, type AccessSubject, type AccessTranslate, AccountLinkPanel, type AccountLinkPanelProps, type CapabilityLink, type CapabilityLinkMintState, type DescribeError, type ExpiryPolicy, type LinkSubjectAccount, type LinkableAccount, type MintCapabilityLink, type MintCapabilityLinkInput, PermissionMatrix, type PermissionMatrixColumn, type PermissionMatrixGrants, type PermissionMatrixPermission, type PermissionMatrixProps, type PermissionMatrixRole, type PermissionMatrixTranslate, type SubjectAccountLinkState, type UseCapabilityLinkMintOptions, type UseSubjectAccountLinkOptions, type UserManagementApi, UserManagementPanel, type UserManagementPanelProps, type UserManagementPatch, type UserManagementTenant, type UserManagementTranslate, type UserManagementUser, accountDisplayLabel, activeLinksForSubject, buildAccountOptions, buildCapabilityLinkMailto, buildPermissionMatrix, capabilityExpiryDate, capabilityExpiryDays, daysUntilAnchor, formatLinkDate, linksForSubject, useAccessAdminPalette, useCapabilityLinkMint, useSubjectAccountLink };
|
package/dist/index.js
CHANGED
|
@@ -169,12 +169,25 @@ var ACCESS_ADMIN_I18N = {
|
|
|
169
169
|
usersUpdateSuccess: "accessAdmin.users.updateSuccess",
|
|
170
170
|
usersUpdateFailed: "accessAdmin.users.updateFailed",
|
|
171
171
|
usersResetSuccess: "accessAdmin.users.resetSuccess",
|
|
172
|
-
usersResetFailed: "accessAdmin.users.resetFailed"
|
|
172
|
+
usersResetFailed: "accessAdmin.users.resetFailed",
|
|
173
|
+
usersFieldBlockedReason: "accessAdmin.users.fieldBlockedReason",
|
|
174
|
+
usersBlockedReasonPlaceholder: "accessAdmin.users.blockedReasonPlaceholder",
|
|
175
|
+
usersBlockedReasonHint: "accessAdmin.users.blockedReasonHint",
|
|
176
|
+
permissionsHeading: "accessAdmin.permissions.heading",
|
|
177
|
+
permissionsNote: "accessAdmin.permissions.note",
|
|
178
|
+
permissionsColPermission: "accessAdmin.permissions.colPermission",
|
|
179
|
+
permissionsGranted: "accessAdmin.permissions.granted",
|
|
180
|
+
permissionsNotGranted: "accessAdmin.permissions.notGranted",
|
|
181
|
+
permissionsCellLabel: "accessAdmin.permissions.cellLabel",
|
|
182
|
+
permissionsReadOnlyHint: "accessAdmin.permissions.readOnlyHint",
|
|
183
|
+
permissionsRoleCount: "accessAdmin.permissions.roleCount",
|
|
184
|
+
permissionsEmpty: "accessAdmin.permissions.empty"
|
|
173
185
|
};
|
|
174
186
|
var ACCESS_ADMIN_TEST_IDS = {
|
|
175
187
|
linkPanel: "access-link-panel",
|
|
176
188
|
accountPanel: "account-link-panel",
|
|
177
|
-
usersPanel: "user-management-panel"
|
|
189
|
+
usersPanel: "user-management-panel",
|
|
190
|
+
permissionMatrix: "permission-matrix"
|
|
178
191
|
};
|
|
179
192
|
|
|
180
193
|
// src/expiry/expiryPolicy.ts
|
|
@@ -319,7 +332,7 @@ var AccessLinkPanel = ({
|
|
|
319
332
|
}) => {
|
|
320
333
|
const { t } = uiFeedback.useUi();
|
|
321
334
|
const palette = useAccessAdminPalette();
|
|
322
|
-
const
|
|
335
|
+
const styles2 = react.useMemo(() => buildStyles(palette), [palette]);
|
|
323
336
|
const state = useCapabilityLinkMint({
|
|
324
337
|
subject,
|
|
325
338
|
policy,
|
|
@@ -347,16 +360,16 @@ var AccessLinkPanel = ({
|
|
|
347
360
|
onResult(t(ACCESS_ADMIN_I18N.copyFailed, subject.displayName), "error" /* Error */);
|
|
348
361
|
});
|
|
349
362
|
};
|
|
350
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
351
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
352
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
353
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
354
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
355
|
-
state.minted !== null ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
356
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
357
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
358
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { selectable: true, style:
|
|
359
|
-
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
363
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles2.panel, testID: testIDPrefix, children: [
|
|
364
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles2.heading, children: t(ACCESS_ADMIN_I18N.panelHeading, subject.displayName) }),
|
|
365
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles2.note, children: t(ACCESS_ADMIN_I18N.panelNote) }),
|
|
366
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles2.warning, testID: `${testIDPrefix}-capability-warning`, children: t(ACCESS_ADMIN_I18N.capabilityWarning) }),
|
|
367
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles2.note, testID: `${testIDPrefix}-expiry-preview`, children: t(ACCESS_ADMIN_I18N.expiryPreview, expiryDate) }),
|
|
368
|
+
state.minted !== null ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles2.revealBox, testID: `${testIDPrefix}-minted`, children: [
|
|
369
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles2.revealTitle, children: t(ACCESS_ADMIN_I18N.mintedTitle, subject.displayName) }),
|
|
370
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles2.note, children: t(ACCESS_ADMIN_I18N.mintedHint) }),
|
|
371
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { selectable: true, style: styles2.url, testID: `${testIDPrefix}-minted-url`, children: mintedUrl }),
|
|
372
|
+
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles2.actions, children: [
|
|
360
373
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
361
374
|
uiButtons.Button,
|
|
362
375
|
{
|
|
@@ -390,13 +403,13 @@ var AccessLinkPanel = ({
|
|
|
390
403
|
}
|
|
391
404
|
)
|
|
392
405
|
] }),
|
|
393
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
406
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles2.note, children: t(ACCESS_ADMIN_I18N.emailNote) })
|
|
394
407
|
] }) : null,
|
|
395
|
-
linksFailed ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
396
|
-
!linksFailed && liveLinks.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
397
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
398
|
-
liveLinks.map((link) => /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
399
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
408
|
+
linksFailed ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles2.warning, testID: `${testIDPrefix}-load-error`, children: t(ACCESS_ADMIN_I18N.liveLoadError) }) : null,
|
|
409
|
+
!linksFailed && liveLinks.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles2.liveBox, children: [
|
|
410
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles2.subheading, children: t(ACCESS_ADMIN_I18N.liveHeading, String(liveLinks.length)) }),
|
|
411
|
+
liveLinks.map((link) => /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles2.liveRow, children: [
|
|
412
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles2.liveMeta, children: t(
|
|
400
413
|
ACCESS_ADMIN_I18N.liveMeta,
|
|
401
414
|
formatLinkDate(link.createdAt, ""),
|
|
402
415
|
formatLinkDate(link.expiresAt, t(ACCESS_ADMIN_I18N.expiresNever))
|
|
@@ -404,8 +417,8 @@ var AccessLinkPanel = ({
|
|
|
404
417
|
renderLinkActions === void 0 ? null : renderLinkActions(link)
|
|
405
418
|
] }, link.id))
|
|
406
419
|
] }) : null,
|
|
407
|
-
!linksFailed && liveLinks.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
408
|
-
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
420
|
+
!linksFailed && liveLinks.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles2.note, testID: `${testIDPrefix}-no-live`, children: t(ACCESS_ADMIN_I18N.noLive) }) : null,
|
|
421
|
+
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles2.actions, children: [
|
|
409
422
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
410
423
|
uiButtons.Button,
|
|
411
424
|
{
|
|
@@ -551,7 +564,7 @@ var AccountLinkPanel = ({
|
|
|
551
564
|
}) => {
|
|
552
565
|
const { t } = uiFeedback.useUi();
|
|
553
566
|
const palette = useAccessAdminPalette();
|
|
554
|
-
const
|
|
567
|
+
const styles2 = react.useMemo(() => buildStyles2(palette), [palette]);
|
|
555
568
|
const state = useSubjectAccountLink({
|
|
556
569
|
subject,
|
|
557
570
|
boundAccountId,
|
|
@@ -566,9 +579,9 @@ var AccountLinkPanel = ({
|
|
|
566
579
|
[accounts, bindings, subject, unnamedLabel]
|
|
567
580
|
);
|
|
568
581
|
const selectedLabel = options.find((option) => option.value === state.selectedAccountId)?.label ?? "";
|
|
569
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
570
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
571
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
582
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles2.panel, testID: testIDPrefix, children: [
|
|
583
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles2.heading, children: t(ACCESS_ADMIN_I18N.accountPanelHeading, subject.displayName) }),
|
|
584
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles2.note, children: t(ACCESS_ADMIN_I18N.accountPanelNote) }),
|
|
572
585
|
options.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
573
586
|
uiForms.SelectControl,
|
|
574
587
|
{
|
|
@@ -581,8 +594,8 @@ var AccountLinkPanel = ({
|
|
|
581
594
|
testID: `${testIDPrefix}-picker`,
|
|
582
595
|
value: state.selectedAccountId ?? ""
|
|
583
596
|
}
|
|
584
|
-
) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
585
|
-
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
597
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles2.note, testID: `${testIDPrefix}-no-accounts`, children: t(ACCESS_ADMIN_I18N.accountNone) }),
|
|
598
|
+
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles2.actions, children: [
|
|
586
599
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
587
600
|
uiButtons.Button,
|
|
588
601
|
{
|
|
@@ -675,6 +688,18 @@ function roleOptions(assignableRoles) {
|
|
|
675
688
|
function tenantValueToId(value) {
|
|
676
689
|
return value === NO_TENANT_VALUE ? null : value;
|
|
677
690
|
}
|
|
691
|
+
function isBlocking(wasActive, active) {
|
|
692
|
+
return wasActive && !active;
|
|
693
|
+
}
|
|
694
|
+
function isBlockReasonMissing(wasActive, active, blockedReason) {
|
|
695
|
+
return isBlocking(wasActive, active) && blockedReason.trim() === "";
|
|
696
|
+
}
|
|
697
|
+
function buildEditPatch(input) {
|
|
698
|
+
const patch = { displayName: input.displayName.trim(), role: input.role, active: input.active };
|
|
699
|
+
if (isBlocking(input.wasActive, input.active)) patch.blockedReason = input.blockedReason.trim();
|
|
700
|
+
if (input.tenantId !== void 0) patch.tenantId = input.tenantId;
|
|
701
|
+
return patch;
|
|
702
|
+
}
|
|
678
703
|
var ACTIONS_GAP = 8;
|
|
679
704
|
function buildUserColumns({
|
|
680
705
|
t,
|
|
@@ -765,7 +790,8 @@ var PickerField = ({
|
|
|
765
790
|
onChange,
|
|
766
791
|
options,
|
|
767
792
|
testID,
|
|
768
|
-
value
|
|
793
|
+
value,
|
|
794
|
+
variant: uiLayout.DropdownVariant.Modal
|
|
769
795
|
}
|
|
770
796
|
) });
|
|
771
797
|
};
|
|
@@ -912,6 +938,7 @@ var EditUserModal = ({
|
|
|
912
938
|
const [role, setRole] = react.useState("");
|
|
913
939
|
const [tenantValue, setTenantValue] = react.useState(NO_TENANT_VALUE);
|
|
914
940
|
const [active, setActive] = react.useState(true);
|
|
941
|
+
const [blockedReason, setBlockedReason] = react.useState("");
|
|
915
942
|
const [submitting, setSubmitting] = react.useState(false);
|
|
916
943
|
const userId = user?.id;
|
|
917
944
|
react.useEffect(() => {
|
|
@@ -920,28 +947,36 @@ var EditUserModal = ({
|
|
|
920
947
|
setRole(user.roles[0] ?? "");
|
|
921
948
|
setTenantValue(user.tenantId ?? NO_TENANT_VALUE);
|
|
922
949
|
setActive(user.active);
|
|
950
|
+
setBlockedReason(user.blockedReason ?? "");
|
|
923
951
|
setSubmitting(false);
|
|
924
952
|
}, [visible, userId, user]);
|
|
925
|
-
const
|
|
953
|
+
const wasActive = user?.active ?? true;
|
|
954
|
+
const canSubmit = !submitting && displayName.trim() !== "" && role !== "" && !isBlockReasonMissing(wasActive, active, blockedReason);
|
|
926
955
|
const handleSubmit = async () => {
|
|
927
956
|
if (user === null) return;
|
|
928
957
|
setSubmitting(true);
|
|
929
|
-
const patch = {
|
|
930
|
-
displayName
|
|
958
|
+
const patch = buildEditPatch({
|
|
959
|
+
displayName,
|
|
931
960
|
role,
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
961
|
+
wasActive,
|
|
962
|
+
active,
|
|
963
|
+
blockedReason,
|
|
964
|
+
tenantId: isPlatformAdmin ? tenantValueToId(tenantValue) : void 0
|
|
965
|
+
});
|
|
935
966
|
const ok = await onSubmit(user.id, patch);
|
|
936
967
|
setSubmitting(false);
|
|
937
968
|
if (ok) onCancel();
|
|
938
969
|
};
|
|
970
|
+
const submitIfReady = () => {
|
|
971
|
+
if (canSubmit) void handleSubmit();
|
|
972
|
+
};
|
|
939
973
|
return /* @__PURE__ */ jsxRuntime.jsx(uiLayout.ModalShell, { onCancel, title: t(ACCESS_ADMIN_I18N.usersEditTitle), visible, children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: modalFormStyles.body, testID: testIDPrefix, children: [
|
|
940
974
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
941
975
|
uiForms.FormField,
|
|
942
976
|
{
|
|
943
977
|
label: t(ACCESS_ADMIN_I18N.usersFieldDisplayName),
|
|
944
978
|
onChangeText: setDisplayName,
|
|
979
|
+
onSubmitEditing: submitIfReady,
|
|
945
980
|
placeholder: t(ACCESS_ADMIN_I18N.usersDisplayNamePlaceholder),
|
|
946
981
|
required: true,
|
|
947
982
|
testID: `${testIDPrefix}-display-name`,
|
|
@@ -982,6 +1017,19 @@ var EditUserModal = ({
|
|
|
982
1017
|
value: active
|
|
983
1018
|
}
|
|
984
1019
|
),
|
|
1020
|
+
active ? null : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1021
|
+
uiForms.FormField,
|
|
1022
|
+
{
|
|
1023
|
+
accessibilityHint: t(ACCESS_ADMIN_I18N.usersBlockedReasonHint),
|
|
1024
|
+
label: t(ACCESS_ADMIN_I18N.usersFieldBlockedReason),
|
|
1025
|
+
onChangeText: setBlockedReason,
|
|
1026
|
+
onSubmitEditing: submitIfReady,
|
|
1027
|
+
placeholder: t(ACCESS_ADMIN_I18N.usersBlockedReasonPlaceholder),
|
|
1028
|
+
required: wasActive,
|
|
1029
|
+
testID: `${testIDPrefix}-blocked-reason`,
|
|
1030
|
+
value: blockedReason
|
|
1031
|
+
}
|
|
1032
|
+
),
|
|
985
1033
|
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: modalFormStyles.actions, children: [
|
|
986
1034
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
987
1035
|
uiButtons.Button,
|
|
@@ -1163,7 +1211,7 @@ var UserManagementPanel = ({
|
|
|
1163
1211
|
testID = ACCESS_ADMIN_TEST_IDS.usersPanel
|
|
1164
1212
|
}) => {
|
|
1165
1213
|
const palette = useAccessAdminPalette();
|
|
1166
|
-
const
|
|
1214
|
+
const styles2 = react.useMemo(() => buildStyles3(palette), [palette]);
|
|
1167
1215
|
const controller = useUserManagement(api, t);
|
|
1168
1216
|
const [query, setQuery] = react.useState("");
|
|
1169
1217
|
const [openModal, setOpenModal] = react.useState("none" /* None */);
|
|
@@ -1185,10 +1233,10 @@ var UserManagementPanel = ({
|
|
|
1185
1233
|
() => buildUserColumns({ t, tenants, testIDPrefix: testID, onEdit: openEdit, onReset: openReset }),
|
|
1186
1234
|
[t, tenants, testID]
|
|
1187
1235
|
);
|
|
1188
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
1236
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles2.panel, testID, children: [
|
|
1189
1237
|
/* @__PURE__ */ jsxRuntime.jsx(uiFeedback.ToastHost, { subscribe: controller.toastSubscribe, toastTestID: `${testID}-toast` }),
|
|
1190
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
1191
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
1238
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles2.heading, children: t(ACCESS_ADMIN_I18N.usersHeading) }),
|
|
1239
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles2.note, children: t(ACCESS_ADMIN_I18N.usersNote) }),
|
|
1192
1240
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1193
1241
|
uiTables.FilterBar,
|
|
1194
1242
|
{
|
|
@@ -1205,7 +1253,7 @@ var UserManagementPanel = ({
|
|
|
1205
1253
|
resultsCount: visibleUsers.length,
|
|
1206
1254
|
resultsLabel: t(ACCESS_ADMIN_I18N.usersResultsLabel),
|
|
1207
1255
|
testID: `${testID}-filter-bar`,
|
|
1208
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style:
|
|
1256
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles2.search, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1209
1257
|
uiForms.FormField,
|
|
1210
1258
|
{
|
|
1211
1259
|
accessibilityLabel: t(ACCESS_ADMIN_I18N.usersSearchLabel),
|
|
@@ -1220,8 +1268,8 @@ var UserManagementPanel = ({
|
|
|
1220
1268
|
) })
|
|
1221
1269
|
}
|
|
1222
1270
|
),
|
|
1223
|
-
controller.loadFailed ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
1224
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
1271
|
+
controller.loadFailed ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles2.errorBox, testID: `${testID}-load-error`, children: [
|
|
1272
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles2.warning, children: t(ACCESS_ADMIN_I18N.usersLoadError) }),
|
|
1225
1273
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1226
1274
|
uiButtons.Button,
|
|
1227
1275
|
{
|
|
@@ -1303,16 +1351,128 @@ var buildStyles3 = (c) => reactNative.StyleSheet.create({
|
|
|
1303
1351
|
warning: { color: c.danger, fontSize: FONT_SM3, fontWeight: "600" }
|
|
1304
1352
|
});
|
|
1305
1353
|
|
|
1354
|
+
// src/PermissionMatrix/permissionMatrixModel.ts
|
|
1355
|
+
function buildPermissionMatrix(roles, permissions, grants) {
|
|
1356
|
+
return roles.map((role) => {
|
|
1357
|
+
const held = new Set(grants[role.id] ?? []);
|
|
1358
|
+
const cells = permissions.map((permission) => ({ permission, granted: held.has(permission.id) }));
|
|
1359
|
+
return { role, cells, grantedCount: cells.filter((cell) => cell.granted).length };
|
|
1360
|
+
});
|
|
1361
|
+
}
|
|
1362
|
+
function grantStatusLabel(granted, t) {
|
|
1363
|
+
return granted ? t(ACCESS_ADMIN_I18N.permissionsGranted) : t(ACCESS_ADMIN_I18N.permissionsNotGranted);
|
|
1364
|
+
}
|
|
1365
|
+
function cellAccessibilityLabel(role, permission, granted, t) {
|
|
1366
|
+
return t(ACCESS_ADMIN_I18N.permissionsCellLabel, role.label, permission.label, grantStatusLabel(granted, t));
|
|
1367
|
+
}
|
|
1368
|
+
var SPACE_XS4 = 4;
|
|
1369
|
+
var SPACE_SM5 = 8;
|
|
1370
|
+
var SPACE_MD5 = 12;
|
|
1371
|
+
var RADIUS = 8;
|
|
1372
|
+
var MAX_WIDTH = 1200;
|
|
1373
|
+
var LABEL_COLUMN_WIDTH = 280;
|
|
1374
|
+
var ROLE_COLUMN_WIDTH = 140;
|
|
1375
|
+
var HEADING_SIZE = 18;
|
|
1376
|
+
var BODY_SIZE = 14;
|
|
1377
|
+
var LINE_HEIGHT = 20;
|
|
1378
|
+
var styles = reactNative.StyleSheet.create({
|
|
1379
|
+
root: { alignSelf: "center", gap: SPACE_MD5, maxWidth: MAX_WIDTH, width: "100%" },
|
|
1380
|
+
heading: { fontSize: HEADING_SIZE, fontWeight: "600", lineHeight: LINE_HEIGHT + SPACE_XS4 },
|
|
1381
|
+
body: { fontSize: BODY_SIZE, lineHeight: LINE_HEIGHT },
|
|
1382
|
+
strong: { fontSize: BODY_SIZE, fontWeight: "600", lineHeight: LINE_HEIGHT },
|
|
1383
|
+
list: { gap: SPACE_MD5 },
|
|
1384
|
+
card: { borderRadius: RADIUS, borderWidth: reactNative.StyleSheet.hairlineWidth, gap: SPACE_SM5, padding: SPACE_MD5 },
|
|
1385
|
+
stackRow: { flexDirection: "row", flexWrap: "wrap", gap: SPACE_SM5, justifyContent: "space-between" },
|
|
1386
|
+
stackLabel: { flexBasis: 0, flexGrow: 1, minWidth: 0 },
|
|
1387
|
+
tableRow: { borderBottomWidth: reactNative.StyleSheet.hairlineWidth, flexDirection: "row" },
|
|
1388
|
+
labelCell: { padding: SPACE_SM5, width: LABEL_COLUMN_WIDTH },
|
|
1389
|
+
roleCell: { padding: SPACE_SM5, width: ROLE_COLUMN_WIDTH }
|
|
1390
|
+
});
|
|
1391
|
+
var statusColor = (granted, palette) => granted ? palette.textPrimary : palette.textSecondary;
|
|
1392
|
+
var StackedMatrix = ({ columns, palette, t, testID }) => /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles.list, children: columns.map(({ role, cells, grantedCount }) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1393
|
+
reactNative.View,
|
|
1394
|
+
{
|
|
1395
|
+
style: [styles.card, { backgroundColor: palette.panelSurface, borderColor: palette.border }],
|
|
1396
|
+
testID: `${testID}-role-${role.id}`,
|
|
1397
|
+
children: [
|
|
1398
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles.strong, { color: palette.textPrimary }], children: role.label }),
|
|
1399
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles.body, { color: palette.textSecondary }], children: t(ACCESS_ADMIN_I18N.permissionsRoleCount, String(grantedCount), String(cells.length)) }),
|
|
1400
|
+
cells.map(({ permission, granted }) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1401
|
+
reactNative.View,
|
|
1402
|
+
{
|
|
1403
|
+
accessibilityHint: t(ACCESS_ADMIN_I18N.permissionsReadOnlyHint),
|
|
1404
|
+
accessibilityLabel: cellAccessibilityLabel(role, permission, granted, t),
|
|
1405
|
+
accessible: true,
|
|
1406
|
+
style: styles.stackRow,
|
|
1407
|
+
testID: `${testID}-cell-${role.id}-${permission.id}`,
|
|
1408
|
+
children: [
|
|
1409
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles.body, styles.stackLabel, { color: palette.textPrimary }], children: permission.label }),
|
|
1410
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [granted ? styles.strong : styles.body, { color: statusColor(granted, palette) }], children: grantStatusLabel(granted, t) })
|
|
1411
|
+
]
|
|
1412
|
+
},
|
|
1413
|
+
permission.id
|
|
1414
|
+
))
|
|
1415
|
+
]
|
|
1416
|
+
},
|
|
1417
|
+
role.id
|
|
1418
|
+
)) });
|
|
1419
|
+
var TableMatrix = ({ columns, permissions, palette, t, testID }) => /* @__PURE__ */ jsxRuntime.jsx(reactNative.ScrollView, { horizontal: true, testID: `${testID}-table`, children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles.card, { backgroundColor: palette.panelSurface, borderColor: palette.border }], children: [
|
|
1420
|
+
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles.tableRow, { borderColor: palette.border }], children: [
|
|
1421
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles.strong, styles.labelCell, { color: palette.textPrimary }], children: t(ACCESS_ADMIN_I18N.permissionsColPermission) }),
|
|
1422
|
+
columns.map(({ role }) => /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles.strong, styles.roleCell, { color: palette.textPrimary }], children: role.label }, role.id))
|
|
1423
|
+
] }),
|
|
1424
|
+
permissions.map((permission, index) => /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles.tableRow, { borderColor: palette.border }], children: [
|
|
1425
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles.body, styles.labelCell, { color: palette.textPrimary }], children: permission.label }),
|
|
1426
|
+
columns.map(({ role, cells }) => {
|
|
1427
|
+
const granted = cells[index]?.granted === true;
|
|
1428
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1429
|
+
reactNative.Text,
|
|
1430
|
+
{
|
|
1431
|
+
accessibilityHint: t(ACCESS_ADMIN_I18N.permissionsReadOnlyHint),
|
|
1432
|
+
accessibilityLabel: cellAccessibilityLabel(role, permission, granted, t),
|
|
1433
|
+
style: [granted ? styles.strong : styles.body, styles.roleCell, { color: statusColor(granted, palette) }],
|
|
1434
|
+
testID: `${testID}-cell-${role.id}-${permission.id}`,
|
|
1435
|
+
children: grantStatusLabel(granted, t)
|
|
1436
|
+
},
|
|
1437
|
+
role.id
|
|
1438
|
+
);
|
|
1439
|
+
})
|
|
1440
|
+
] }, permission.id))
|
|
1441
|
+
] }) });
|
|
1442
|
+
var PermissionMatrix = ({
|
|
1443
|
+
roles,
|
|
1444
|
+
permissions,
|
|
1445
|
+
grants,
|
|
1446
|
+
t,
|
|
1447
|
+
testID = ACCESS_ADMIN_TEST_IDS.permissionMatrix
|
|
1448
|
+
}) => {
|
|
1449
|
+
const palette = useAccessAdminPalette();
|
|
1450
|
+
const { width } = reactNative.useWindowDimensions();
|
|
1451
|
+
const columns = react.useMemo(() => buildPermissionMatrix(roles, permissions, grants), [roles, permissions, grants]);
|
|
1452
|
+
const isWide = width >= uiLayout.LAYOUT_COLLAPSE_BREAKPOINT;
|
|
1453
|
+
const isEmpty = roles.length === 0 || permissions.length === 0;
|
|
1454
|
+
const partProps = { columns, permissions, palette, t, testID };
|
|
1455
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles.root, testID, children: [
|
|
1456
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { accessibilityRole: "header", style: [styles.heading, { color: palette.textPrimary }], children: t(ACCESS_ADMIN_I18N.permissionsHeading) }),
|
|
1457
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles.body, { color: palette.textSecondary }], children: t(ACCESS_ADMIN_I18N.permissionsNote) }),
|
|
1458
|
+
isEmpty ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles.body, { color: palette.textSecondary }], testID: `${testID}-empty`, children: t(ACCESS_ADMIN_I18N.permissionsEmpty) }) : null,
|
|
1459
|
+
!isEmpty && isWide ? /* @__PURE__ */ jsxRuntime.jsx(TableMatrix, { ...partProps }) : null,
|
|
1460
|
+
!isEmpty && !isWide ? /* @__PURE__ */ jsxRuntime.jsx(StackedMatrix, { ...partProps }) : null
|
|
1461
|
+
] });
|
|
1462
|
+
};
|
|
1463
|
+
|
|
1306
1464
|
exports.ACCESS_ADMIN_I18N = ACCESS_ADMIN_I18N;
|
|
1307
1465
|
exports.ACCESS_ADMIN_TEST_IDS = ACCESS_ADMIN_TEST_IDS;
|
|
1308
1466
|
exports.AccessLinkPanel = AccessLinkPanel;
|
|
1309
1467
|
exports.AccessResultTone = AccessResultTone;
|
|
1310
1468
|
exports.AccountLinkPanel = AccountLinkPanel;
|
|
1469
|
+
exports.PermissionMatrix = PermissionMatrix;
|
|
1311
1470
|
exports.UserManagementPanel = UserManagementPanel;
|
|
1312
1471
|
exports.accountDisplayLabel = accountDisplayLabel;
|
|
1313
1472
|
exports.activeLinksForSubject = activeLinksForSubject;
|
|
1314
1473
|
exports.buildAccountOptions = buildAccountOptions;
|
|
1315
1474
|
exports.buildCapabilityLinkMailto = buildCapabilityLinkMailto;
|
|
1475
|
+
exports.buildPermissionMatrix = buildPermissionMatrix;
|
|
1316
1476
|
exports.capabilityExpiryDate = capabilityExpiryDate;
|
|
1317
1477
|
exports.capabilityExpiryDays = capabilityExpiryDays;
|
|
1318
1478
|
exports.daysUntilAnchor = daysUntilAnchor;
|