@dloizides/ui-access-admin 1.2.2 → 1.4.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 +18 -1
- package/dist/index.d.mts +56 -9
- package/dist/index.d.ts +56 -9
- package/dist/index.js +221 -52
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +222 -55
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
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,
|
|
@@ -730,7 +755,7 @@ function buildUserColumns({
|
|
|
730
755
|
variant: "secondary"
|
|
731
756
|
}
|
|
732
757
|
),
|
|
733
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
758
|
+
onReset !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
734
759
|
uiButtons.Button,
|
|
735
760
|
{
|
|
736
761
|
accessibilityHint: t(ACCESS_ADMIN_I18N.usersResetHint),
|
|
@@ -741,7 +766,7 @@ function buildUserColumns({
|
|
|
741
766
|
testID: `${testIDPrefix}-reset-${user.id}`,
|
|
742
767
|
variant: "secondary"
|
|
743
768
|
}
|
|
744
|
-
)
|
|
769
|
+
) : null
|
|
745
770
|
] })
|
|
746
771
|
}
|
|
747
772
|
];
|
|
@@ -913,6 +938,7 @@ var EditUserModal = ({
|
|
|
913
938
|
const [role, setRole] = react.useState("");
|
|
914
939
|
const [tenantValue, setTenantValue] = react.useState(NO_TENANT_VALUE);
|
|
915
940
|
const [active, setActive] = react.useState(true);
|
|
941
|
+
const [blockedReason, setBlockedReason] = react.useState("");
|
|
916
942
|
const [submitting, setSubmitting] = react.useState(false);
|
|
917
943
|
const userId = user?.id;
|
|
918
944
|
react.useEffect(() => {
|
|
@@ -921,28 +947,36 @@ var EditUserModal = ({
|
|
|
921
947
|
setRole(user.roles[0] ?? "");
|
|
922
948
|
setTenantValue(user.tenantId ?? NO_TENANT_VALUE);
|
|
923
949
|
setActive(user.active);
|
|
950
|
+
setBlockedReason(user.blockedReason ?? "");
|
|
924
951
|
setSubmitting(false);
|
|
925
952
|
}, [visible, userId, user]);
|
|
926
|
-
const
|
|
953
|
+
const wasActive = user?.active ?? true;
|
|
954
|
+
const canSubmit = !submitting && displayName.trim() !== "" && role !== "" && !isBlockReasonMissing(wasActive, active, blockedReason);
|
|
927
955
|
const handleSubmit = async () => {
|
|
928
956
|
if (user === null) return;
|
|
929
957
|
setSubmitting(true);
|
|
930
|
-
const patch = {
|
|
931
|
-
displayName
|
|
958
|
+
const patch = buildEditPatch({
|
|
959
|
+
displayName,
|
|
932
960
|
role,
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
961
|
+
wasActive,
|
|
962
|
+
active,
|
|
963
|
+
blockedReason,
|
|
964
|
+
tenantId: isPlatformAdmin ? tenantValueToId(tenantValue) : void 0
|
|
965
|
+
});
|
|
936
966
|
const ok = await onSubmit(user.id, patch);
|
|
937
967
|
setSubmitting(false);
|
|
938
968
|
if (ok) onCancel();
|
|
939
969
|
};
|
|
970
|
+
const submitIfReady = () => {
|
|
971
|
+
if (canSubmit) void handleSubmit();
|
|
972
|
+
};
|
|
940
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: [
|
|
941
974
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
942
975
|
uiForms.FormField,
|
|
943
976
|
{
|
|
944
977
|
label: t(ACCESS_ADMIN_I18N.usersFieldDisplayName),
|
|
945
978
|
onChangeText: setDisplayName,
|
|
979
|
+
onSubmitEditing: submitIfReady,
|
|
946
980
|
placeholder: t(ACCESS_ADMIN_I18N.usersDisplayNamePlaceholder),
|
|
947
981
|
required: true,
|
|
948
982
|
testID: `${testIDPrefix}-display-name`,
|
|
@@ -983,6 +1017,19 @@ var EditUserModal = ({
|
|
|
983
1017
|
value: active
|
|
984
1018
|
}
|
|
985
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
|
+
),
|
|
986
1033
|
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: modalFormStyles.actions, children: [
|
|
987
1034
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
988
1035
|
uiButtons.Button,
|
|
@@ -1075,6 +1122,8 @@ var ResetPasswordModal = ({
|
|
|
1075
1122
|
] })
|
|
1076
1123
|
] }) });
|
|
1077
1124
|
};
|
|
1125
|
+
var MISSING_CREATE = "createUser is not provided";
|
|
1126
|
+
var MISSING_RESET = "resetPassword is not provided";
|
|
1078
1127
|
function useUserManagement(api, t) {
|
|
1079
1128
|
const [users, setUsers] = react.useState([]);
|
|
1080
1129
|
const [loading, setLoading] = react.useState(true);
|
|
@@ -1116,7 +1165,7 @@ function useUserManagement(api, t) {
|
|
|
1116
1165
|
);
|
|
1117
1166
|
const create = react.useCallback(
|
|
1118
1167
|
(input) => runWrite(
|
|
1119
|
-
() => api.createUser(input),
|
|
1168
|
+
() => api.createUser ? api.createUser(input) : Promise.reject(new Error(MISSING_CREATE)),
|
|
1120
1169
|
ACCESS_ADMIN_I18N.usersCreateSuccess,
|
|
1121
1170
|
ACCESS_ADMIN_I18N.usersCreateFailed
|
|
1122
1171
|
),
|
|
@@ -1132,7 +1181,7 @@ function useUserManagement(api, t) {
|
|
|
1132
1181
|
);
|
|
1133
1182
|
const resetPassword = react.useCallback(
|
|
1134
1183
|
(id, password) => runWrite(
|
|
1135
|
-
() => api.resetPassword(id, password),
|
|
1184
|
+
() => api.resetPassword ? api.resetPassword(id, password) : Promise.reject(new Error(MISSING_RESET)),
|
|
1136
1185
|
ACCESS_ADMIN_I18N.usersResetSuccess,
|
|
1137
1186
|
ACCESS_ADMIN_I18N.usersResetFailed
|
|
1138
1187
|
),
|
|
@@ -1164,7 +1213,7 @@ var UserManagementPanel = ({
|
|
|
1164
1213
|
testID = ACCESS_ADMIN_TEST_IDS.usersPanel
|
|
1165
1214
|
}) => {
|
|
1166
1215
|
const palette = useAccessAdminPalette();
|
|
1167
|
-
const
|
|
1216
|
+
const styles2 = react.useMemo(() => buildStyles3(palette), [palette]);
|
|
1168
1217
|
const controller = useUserManagement(api, t);
|
|
1169
1218
|
const [query, setQuery] = react.useState("");
|
|
1170
1219
|
const [openModal, setOpenModal] = react.useState("none" /* None */);
|
|
@@ -1182,18 +1231,26 @@ var UserManagementPanel = ({
|
|
|
1182
1231
|
setOpenModal("reset" /* Reset */);
|
|
1183
1232
|
};
|
|
1184
1233
|
const closeModal = () => setOpenModal("none" /* None */);
|
|
1234
|
+
const canCreate = api.createUser !== void 0;
|
|
1235
|
+
const canReset = api.resetPassword !== void 0;
|
|
1185
1236
|
const columns = react.useMemo(
|
|
1186
|
-
() => buildUserColumns({
|
|
1187
|
-
|
|
1237
|
+
() => buildUserColumns({
|
|
1238
|
+
t,
|
|
1239
|
+
tenants,
|
|
1240
|
+
testIDPrefix: testID,
|
|
1241
|
+
onEdit: openEdit,
|
|
1242
|
+
onReset: canReset ? openReset : void 0
|
|
1243
|
+
}),
|
|
1244
|
+
[t, tenants, testID, canReset]
|
|
1188
1245
|
);
|
|
1189
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
1246
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles2.panel, testID, children: [
|
|
1190
1247
|
/* @__PURE__ */ jsxRuntime.jsx(uiFeedback.ToastHost, { subscribe: controller.toastSubscribe, toastTestID: `${testID}-toast` }),
|
|
1191
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
1192
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
1248
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles2.heading, children: t(ACCESS_ADMIN_I18N.usersHeading) }),
|
|
1249
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles2.note, children: t(ACCESS_ADMIN_I18N.usersNote) }),
|
|
1193
1250
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1194
1251
|
uiTables.FilterBar,
|
|
1195
1252
|
{
|
|
1196
|
-
actions: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1253
|
+
actions: canCreate ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1197
1254
|
uiButtons.Button,
|
|
1198
1255
|
{
|
|
1199
1256
|
accessibilityHint: t(ACCESS_ADMIN_I18N.usersCreateHint),
|
|
@@ -1202,11 +1259,11 @@ var UserManagementPanel = ({
|
|
|
1202
1259
|
onPress: () => setOpenModal("create" /* Create */),
|
|
1203
1260
|
testID: `${testID}-create`
|
|
1204
1261
|
}
|
|
1205
|
-
),
|
|
1262
|
+
) : void 0,
|
|
1206
1263
|
resultsCount: visibleUsers.length,
|
|
1207
1264
|
resultsLabel: t(ACCESS_ADMIN_I18N.usersResultsLabel),
|
|
1208
1265
|
testID: `${testID}-filter-bar`,
|
|
1209
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style:
|
|
1266
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles2.search, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1210
1267
|
uiForms.FormField,
|
|
1211
1268
|
{
|
|
1212
1269
|
accessibilityLabel: t(ACCESS_ADMIN_I18N.usersSearchLabel),
|
|
@@ -1221,8 +1278,8 @@ var UserManagementPanel = ({
|
|
|
1221
1278
|
) })
|
|
1222
1279
|
}
|
|
1223
1280
|
),
|
|
1224
|
-
controller.loadFailed ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
1225
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
1281
|
+
controller.loadFailed ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles2.errorBox, testID: `${testID}-load-error`, children: [
|
|
1282
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles2.warning, children: t(ACCESS_ADMIN_I18N.usersLoadError) }),
|
|
1226
1283
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1227
1284
|
uiButtons.Button,
|
|
1228
1285
|
{
|
|
@@ -1247,7 +1304,7 @@ var UserManagementPanel = ({
|
|
|
1247
1304
|
zebra: true
|
|
1248
1305
|
}
|
|
1249
1306
|
),
|
|
1250
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1307
|
+
canCreate ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1251
1308
|
CreateUserModal,
|
|
1252
1309
|
{
|
|
1253
1310
|
assignableRoles,
|
|
@@ -1259,7 +1316,7 @@ var UserManagementPanel = ({
|
|
|
1259
1316
|
testIDPrefix: `${testID}-create-modal`,
|
|
1260
1317
|
visible: openModal === "create" /* Create */
|
|
1261
1318
|
}
|
|
1262
|
-
),
|
|
1319
|
+
) : null,
|
|
1263
1320
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1264
1321
|
EditUserModal,
|
|
1265
1322
|
{
|
|
@@ -1274,7 +1331,7 @@ var UserManagementPanel = ({
|
|
|
1274
1331
|
visible: openModal === "edit" /* Edit */
|
|
1275
1332
|
}
|
|
1276
1333
|
),
|
|
1277
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1334
|
+
canReset ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1278
1335
|
ResetPasswordModal,
|
|
1279
1336
|
{
|
|
1280
1337
|
onCancel: closeModal,
|
|
@@ -1284,7 +1341,7 @@ var UserManagementPanel = ({
|
|
|
1284
1341
|
user: activeUser,
|
|
1285
1342
|
visible: openModal === "reset" /* Reset */
|
|
1286
1343
|
}
|
|
1287
|
-
)
|
|
1344
|
+
) : null
|
|
1288
1345
|
] });
|
|
1289
1346
|
};
|
|
1290
1347
|
var buildStyles3 = (c) => reactNative.StyleSheet.create({
|
|
@@ -1304,16 +1361,128 @@ var buildStyles3 = (c) => reactNative.StyleSheet.create({
|
|
|
1304
1361
|
warning: { color: c.danger, fontSize: FONT_SM3, fontWeight: "600" }
|
|
1305
1362
|
});
|
|
1306
1363
|
|
|
1364
|
+
// src/PermissionMatrix/permissionMatrixModel.ts
|
|
1365
|
+
function buildPermissionMatrix(roles, permissions, grants) {
|
|
1366
|
+
return roles.map((role) => {
|
|
1367
|
+
const held = new Set(grants[role.id] ?? []);
|
|
1368
|
+
const cells = permissions.map((permission) => ({ permission, granted: held.has(permission.id) }));
|
|
1369
|
+
return { role, cells, grantedCount: cells.filter((cell) => cell.granted).length };
|
|
1370
|
+
});
|
|
1371
|
+
}
|
|
1372
|
+
function grantStatusLabel(granted, t) {
|
|
1373
|
+
return granted ? t(ACCESS_ADMIN_I18N.permissionsGranted) : t(ACCESS_ADMIN_I18N.permissionsNotGranted);
|
|
1374
|
+
}
|
|
1375
|
+
function cellAccessibilityLabel(role, permission, granted, t) {
|
|
1376
|
+
return t(ACCESS_ADMIN_I18N.permissionsCellLabel, role.label, permission.label, grantStatusLabel(granted, t));
|
|
1377
|
+
}
|
|
1378
|
+
var SPACE_XS4 = 4;
|
|
1379
|
+
var SPACE_SM5 = 8;
|
|
1380
|
+
var SPACE_MD5 = 12;
|
|
1381
|
+
var RADIUS = 8;
|
|
1382
|
+
var MAX_WIDTH = 1200;
|
|
1383
|
+
var LABEL_COLUMN_WIDTH = 280;
|
|
1384
|
+
var ROLE_COLUMN_WIDTH = 140;
|
|
1385
|
+
var HEADING_SIZE = 18;
|
|
1386
|
+
var BODY_SIZE = 14;
|
|
1387
|
+
var LINE_HEIGHT = 20;
|
|
1388
|
+
var styles = reactNative.StyleSheet.create({
|
|
1389
|
+
root: { alignSelf: "center", gap: SPACE_MD5, maxWidth: MAX_WIDTH, width: "100%" },
|
|
1390
|
+
heading: { fontSize: HEADING_SIZE, fontWeight: "600", lineHeight: LINE_HEIGHT + SPACE_XS4 },
|
|
1391
|
+
body: { fontSize: BODY_SIZE, lineHeight: LINE_HEIGHT },
|
|
1392
|
+
strong: { fontSize: BODY_SIZE, fontWeight: "600", lineHeight: LINE_HEIGHT },
|
|
1393
|
+
list: { gap: SPACE_MD5 },
|
|
1394
|
+
card: { borderRadius: RADIUS, borderWidth: reactNative.StyleSheet.hairlineWidth, gap: SPACE_SM5, padding: SPACE_MD5 },
|
|
1395
|
+
stackRow: { flexDirection: "row", flexWrap: "wrap", gap: SPACE_SM5, justifyContent: "space-between" },
|
|
1396
|
+
stackLabel: { flexBasis: 0, flexGrow: 1, minWidth: 0 },
|
|
1397
|
+
tableRow: { borderBottomWidth: reactNative.StyleSheet.hairlineWidth, flexDirection: "row" },
|
|
1398
|
+
labelCell: { padding: SPACE_SM5, width: LABEL_COLUMN_WIDTH },
|
|
1399
|
+
roleCell: { padding: SPACE_SM5, width: ROLE_COLUMN_WIDTH }
|
|
1400
|
+
});
|
|
1401
|
+
var statusColor = (granted, palette) => granted ? palette.textPrimary : palette.textSecondary;
|
|
1402
|
+
var StackedMatrix = ({ columns, palette, t, testID }) => /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles.list, children: columns.map(({ role, cells, grantedCount }) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1403
|
+
reactNative.View,
|
|
1404
|
+
{
|
|
1405
|
+
style: [styles.card, { backgroundColor: palette.panelSurface, borderColor: palette.border }],
|
|
1406
|
+
testID: `${testID}-role-${role.id}`,
|
|
1407
|
+
children: [
|
|
1408
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles.strong, { color: palette.textPrimary }], children: role.label }),
|
|
1409
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles.body, { color: palette.textSecondary }], children: t(ACCESS_ADMIN_I18N.permissionsRoleCount, String(grantedCount), String(cells.length)) }),
|
|
1410
|
+
cells.map(({ permission, granted }) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1411
|
+
reactNative.View,
|
|
1412
|
+
{
|
|
1413
|
+
accessibilityHint: t(ACCESS_ADMIN_I18N.permissionsReadOnlyHint),
|
|
1414
|
+
accessibilityLabel: cellAccessibilityLabel(role, permission, granted, t),
|
|
1415
|
+
accessible: true,
|
|
1416
|
+
style: styles.stackRow,
|
|
1417
|
+
testID: `${testID}-cell-${role.id}-${permission.id}`,
|
|
1418
|
+
children: [
|
|
1419
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles.body, styles.stackLabel, { color: palette.textPrimary }], children: permission.label }),
|
|
1420
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [granted ? styles.strong : styles.body, { color: statusColor(granted, palette) }], children: grantStatusLabel(granted, t) })
|
|
1421
|
+
]
|
|
1422
|
+
},
|
|
1423
|
+
permission.id
|
|
1424
|
+
))
|
|
1425
|
+
]
|
|
1426
|
+
},
|
|
1427
|
+
role.id
|
|
1428
|
+
)) });
|
|
1429
|
+
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: [
|
|
1430
|
+
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles.tableRow, { borderColor: palette.border }], children: [
|
|
1431
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles.strong, styles.labelCell, { color: palette.textPrimary }], children: t(ACCESS_ADMIN_I18N.permissionsColPermission) }),
|
|
1432
|
+
columns.map(({ role }) => /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles.strong, styles.roleCell, { color: palette.textPrimary }], children: role.label }, role.id))
|
|
1433
|
+
] }),
|
|
1434
|
+
permissions.map((permission, index) => /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles.tableRow, { borderColor: palette.border }], children: [
|
|
1435
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles.body, styles.labelCell, { color: palette.textPrimary }], children: permission.label }),
|
|
1436
|
+
columns.map(({ role, cells }) => {
|
|
1437
|
+
const granted = cells[index]?.granted === true;
|
|
1438
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1439
|
+
reactNative.Text,
|
|
1440
|
+
{
|
|
1441
|
+
accessibilityHint: t(ACCESS_ADMIN_I18N.permissionsReadOnlyHint),
|
|
1442
|
+
accessibilityLabel: cellAccessibilityLabel(role, permission, granted, t),
|
|
1443
|
+
style: [granted ? styles.strong : styles.body, styles.roleCell, { color: statusColor(granted, palette) }],
|
|
1444
|
+
testID: `${testID}-cell-${role.id}-${permission.id}`,
|
|
1445
|
+
children: grantStatusLabel(granted, t)
|
|
1446
|
+
},
|
|
1447
|
+
role.id
|
|
1448
|
+
);
|
|
1449
|
+
})
|
|
1450
|
+
] }, permission.id))
|
|
1451
|
+
] }) });
|
|
1452
|
+
var PermissionMatrix = ({
|
|
1453
|
+
roles,
|
|
1454
|
+
permissions,
|
|
1455
|
+
grants,
|
|
1456
|
+
t,
|
|
1457
|
+
testID = ACCESS_ADMIN_TEST_IDS.permissionMatrix
|
|
1458
|
+
}) => {
|
|
1459
|
+
const palette = useAccessAdminPalette();
|
|
1460
|
+
const { width } = reactNative.useWindowDimensions();
|
|
1461
|
+
const columns = react.useMemo(() => buildPermissionMatrix(roles, permissions, grants), [roles, permissions, grants]);
|
|
1462
|
+
const isWide = width >= uiLayout.LAYOUT_COLLAPSE_BREAKPOINT;
|
|
1463
|
+
const isEmpty = roles.length === 0 || permissions.length === 0;
|
|
1464
|
+
const partProps = { columns, permissions, palette, t, testID };
|
|
1465
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles.root, testID, children: [
|
|
1466
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { accessibilityRole: "header", style: [styles.heading, { color: palette.textPrimary }], children: t(ACCESS_ADMIN_I18N.permissionsHeading) }),
|
|
1467
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles.body, { color: palette.textSecondary }], children: t(ACCESS_ADMIN_I18N.permissionsNote) }),
|
|
1468
|
+
isEmpty ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles.body, { color: palette.textSecondary }], testID: `${testID}-empty`, children: t(ACCESS_ADMIN_I18N.permissionsEmpty) }) : null,
|
|
1469
|
+
!isEmpty && isWide ? /* @__PURE__ */ jsxRuntime.jsx(TableMatrix, { ...partProps }) : null,
|
|
1470
|
+
!isEmpty && !isWide ? /* @__PURE__ */ jsxRuntime.jsx(StackedMatrix, { ...partProps }) : null
|
|
1471
|
+
] });
|
|
1472
|
+
};
|
|
1473
|
+
|
|
1307
1474
|
exports.ACCESS_ADMIN_I18N = ACCESS_ADMIN_I18N;
|
|
1308
1475
|
exports.ACCESS_ADMIN_TEST_IDS = ACCESS_ADMIN_TEST_IDS;
|
|
1309
1476
|
exports.AccessLinkPanel = AccessLinkPanel;
|
|
1310
1477
|
exports.AccessResultTone = AccessResultTone;
|
|
1311
1478
|
exports.AccountLinkPanel = AccountLinkPanel;
|
|
1479
|
+
exports.PermissionMatrix = PermissionMatrix;
|
|
1312
1480
|
exports.UserManagementPanel = UserManagementPanel;
|
|
1313
1481
|
exports.accountDisplayLabel = accountDisplayLabel;
|
|
1314
1482
|
exports.activeLinksForSubject = activeLinksForSubject;
|
|
1315
1483
|
exports.buildAccountOptions = buildAccountOptions;
|
|
1316
1484
|
exports.buildCapabilityLinkMailto = buildCapabilityLinkMailto;
|
|
1485
|
+
exports.buildPermissionMatrix = buildPermissionMatrix;
|
|
1317
1486
|
exports.capabilityExpiryDate = capabilityExpiryDate;
|
|
1318
1487
|
exports.capabilityExpiryDays = capabilityExpiryDays;
|
|
1319
1488
|
exports.daysUntilAnchor = daysUntilAnchor;
|