@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.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { useState, useRef, useEffect, useCallback, useMemo } from 'react';
|
|
2
|
-
import { StyleSheet, View, Text, Linking } from 'react-native';
|
|
2
|
+
import { StyleSheet, View, Text, useWindowDimensions, Linking, ScrollView } from 'react-native';
|
|
3
3
|
import { Button } from '@dloizides/ui-buttons';
|
|
4
4
|
import { useUi, ToastHost, createToastBus } from '@dloizides/ui-feedback';
|
|
5
|
-
import { copyText, ModalShell, ModalDropdown, DropdownVariant } from '@dloizides/ui-layout';
|
|
5
|
+
import { copyText, LAYOUT_COLLAPSE_BREAKPOINT, ModalShell, ModalDropdown, DropdownVariant } from '@dloizides/ui-layout';
|
|
6
6
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
7
7
|
import { SelectControl, FormField, FormSwitch, Field } from '@dloizides/ui-forms';
|
|
8
8
|
import { FilterBar, DataTable } from '@dloizides/ui-tables';
|
|
@@ -167,12 +167,25 @@ var ACCESS_ADMIN_I18N = {
|
|
|
167
167
|
usersUpdateSuccess: "accessAdmin.users.updateSuccess",
|
|
168
168
|
usersUpdateFailed: "accessAdmin.users.updateFailed",
|
|
169
169
|
usersResetSuccess: "accessAdmin.users.resetSuccess",
|
|
170
|
-
usersResetFailed: "accessAdmin.users.resetFailed"
|
|
170
|
+
usersResetFailed: "accessAdmin.users.resetFailed",
|
|
171
|
+
usersFieldBlockedReason: "accessAdmin.users.fieldBlockedReason",
|
|
172
|
+
usersBlockedReasonPlaceholder: "accessAdmin.users.blockedReasonPlaceholder",
|
|
173
|
+
usersBlockedReasonHint: "accessAdmin.users.blockedReasonHint",
|
|
174
|
+
permissionsHeading: "accessAdmin.permissions.heading",
|
|
175
|
+
permissionsNote: "accessAdmin.permissions.note",
|
|
176
|
+
permissionsColPermission: "accessAdmin.permissions.colPermission",
|
|
177
|
+
permissionsGranted: "accessAdmin.permissions.granted",
|
|
178
|
+
permissionsNotGranted: "accessAdmin.permissions.notGranted",
|
|
179
|
+
permissionsCellLabel: "accessAdmin.permissions.cellLabel",
|
|
180
|
+
permissionsReadOnlyHint: "accessAdmin.permissions.readOnlyHint",
|
|
181
|
+
permissionsRoleCount: "accessAdmin.permissions.roleCount",
|
|
182
|
+
permissionsEmpty: "accessAdmin.permissions.empty"
|
|
171
183
|
};
|
|
172
184
|
var ACCESS_ADMIN_TEST_IDS = {
|
|
173
185
|
linkPanel: "access-link-panel",
|
|
174
186
|
accountPanel: "account-link-panel",
|
|
175
|
-
usersPanel: "user-management-panel"
|
|
187
|
+
usersPanel: "user-management-panel",
|
|
188
|
+
permissionMatrix: "permission-matrix"
|
|
176
189
|
};
|
|
177
190
|
|
|
178
191
|
// src/expiry/expiryPolicy.ts
|
|
@@ -317,7 +330,7 @@ var AccessLinkPanel = ({
|
|
|
317
330
|
}) => {
|
|
318
331
|
const { t } = useUi();
|
|
319
332
|
const palette = useAccessAdminPalette();
|
|
320
|
-
const
|
|
333
|
+
const styles2 = useMemo(() => buildStyles(palette), [palette]);
|
|
321
334
|
const state = useCapabilityLinkMint({
|
|
322
335
|
subject,
|
|
323
336
|
policy,
|
|
@@ -345,16 +358,16 @@ var AccessLinkPanel = ({
|
|
|
345
358
|
onResult(t(ACCESS_ADMIN_I18N.copyFailed, subject.displayName), "error" /* Error */);
|
|
346
359
|
});
|
|
347
360
|
};
|
|
348
|
-
return /* @__PURE__ */ jsxs(View, { style:
|
|
349
|
-
/* @__PURE__ */ jsx(Text, { style:
|
|
350
|
-
/* @__PURE__ */ jsx(Text, { style:
|
|
351
|
-
/* @__PURE__ */ jsx(Text, { style:
|
|
352
|
-
/* @__PURE__ */ jsx(Text, { style:
|
|
353
|
-
state.minted !== null ? /* @__PURE__ */ jsxs(View, { style:
|
|
354
|
-
/* @__PURE__ */ jsx(Text, { style:
|
|
355
|
-
/* @__PURE__ */ jsx(Text, { style:
|
|
356
|
-
/* @__PURE__ */ jsx(Text, { selectable: true, style:
|
|
357
|
-
/* @__PURE__ */ jsxs(View, { style:
|
|
361
|
+
return /* @__PURE__ */ jsxs(View, { style: styles2.panel, testID: testIDPrefix, children: [
|
|
362
|
+
/* @__PURE__ */ jsx(Text, { style: styles2.heading, children: t(ACCESS_ADMIN_I18N.panelHeading, subject.displayName) }),
|
|
363
|
+
/* @__PURE__ */ jsx(Text, { style: styles2.note, children: t(ACCESS_ADMIN_I18N.panelNote) }),
|
|
364
|
+
/* @__PURE__ */ jsx(Text, { style: styles2.warning, testID: `${testIDPrefix}-capability-warning`, children: t(ACCESS_ADMIN_I18N.capabilityWarning) }),
|
|
365
|
+
/* @__PURE__ */ jsx(Text, { style: styles2.note, testID: `${testIDPrefix}-expiry-preview`, children: t(ACCESS_ADMIN_I18N.expiryPreview, expiryDate) }),
|
|
366
|
+
state.minted !== null ? /* @__PURE__ */ jsxs(View, { style: styles2.revealBox, testID: `${testIDPrefix}-minted`, children: [
|
|
367
|
+
/* @__PURE__ */ jsx(Text, { style: styles2.revealTitle, children: t(ACCESS_ADMIN_I18N.mintedTitle, subject.displayName) }),
|
|
368
|
+
/* @__PURE__ */ jsx(Text, { style: styles2.note, children: t(ACCESS_ADMIN_I18N.mintedHint) }),
|
|
369
|
+
/* @__PURE__ */ jsx(Text, { selectable: true, style: styles2.url, testID: `${testIDPrefix}-minted-url`, children: mintedUrl }),
|
|
370
|
+
/* @__PURE__ */ jsxs(View, { style: styles2.actions, children: [
|
|
358
371
|
/* @__PURE__ */ jsx(
|
|
359
372
|
Button,
|
|
360
373
|
{
|
|
@@ -388,13 +401,13 @@ var AccessLinkPanel = ({
|
|
|
388
401
|
}
|
|
389
402
|
)
|
|
390
403
|
] }),
|
|
391
|
-
/* @__PURE__ */ jsx(Text, { style:
|
|
404
|
+
/* @__PURE__ */ jsx(Text, { style: styles2.note, children: t(ACCESS_ADMIN_I18N.emailNote) })
|
|
392
405
|
] }) : null,
|
|
393
|
-
linksFailed ? /* @__PURE__ */ jsx(Text, { style:
|
|
394
|
-
!linksFailed && liveLinks.length > 0 ? /* @__PURE__ */ jsxs(View, { style:
|
|
395
|
-
/* @__PURE__ */ jsx(Text, { style:
|
|
396
|
-
liveLinks.map((link) => /* @__PURE__ */ jsxs(View, { style:
|
|
397
|
-
/* @__PURE__ */ jsx(Text, { style:
|
|
406
|
+
linksFailed ? /* @__PURE__ */ jsx(Text, { style: styles2.warning, testID: `${testIDPrefix}-load-error`, children: t(ACCESS_ADMIN_I18N.liveLoadError) }) : null,
|
|
407
|
+
!linksFailed && liveLinks.length > 0 ? /* @__PURE__ */ jsxs(View, { style: styles2.liveBox, children: [
|
|
408
|
+
/* @__PURE__ */ jsx(Text, { style: styles2.subheading, children: t(ACCESS_ADMIN_I18N.liveHeading, String(liveLinks.length)) }),
|
|
409
|
+
liveLinks.map((link) => /* @__PURE__ */ jsxs(View, { style: styles2.liveRow, children: [
|
|
410
|
+
/* @__PURE__ */ jsx(Text, { style: styles2.liveMeta, children: t(
|
|
398
411
|
ACCESS_ADMIN_I18N.liveMeta,
|
|
399
412
|
formatLinkDate(link.createdAt, ""),
|
|
400
413
|
formatLinkDate(link.expiresAt, t(ACCESS_ADMIN_I18N.expiresNever))
|
|
@@ -402,8 +415,8 @@ var AccessLinkPanel = ({
|
|
|
402
415
|
renderLinkActions === void 0 ? null : renderLinkActions(link)
|
|
403
416
|
] }, link.id))
|
|
404
417
|
] }) : null,
|
|
405
|
-
!linksFailed && liveLinks.length === 0 ? /* @__PURE__ */ jsx(Text, { style:
|
|
406
|
-
/* @__PURE__ */ jsxs(View, { style:
|
|
418
|
+
!linksFailed && liveLinks.length === 0 ? /* @__PURE__ */ jsx(Text, { style: styles2.note, testID: `${testIDPrefix}-no-live`, children: t(ACCESS_ADMIN_I18N.noLive) }) : null,
|
|
419
|
+
/* @__PURE__ */ jsxs(View, { style: styles2.actions, children: [
|
|
407
420
|
/* @__PURE__ */ jsx(
|
|
408
421
|
Button,
|
|
409
422
|
{
|
|
@@ -549,7 +562,7 @@ var AccountLinkPanel = ({
|
|
|
549
562
|
}) => {
|
|
550
563
|
const { t } = useUi();
|
|
551
564
|
const palette = useAccessAdminPalette();
|
|
552
|
-
const
|
|
565
|
+
const styles2 = useMemo(() => buildStyles2(palette), [palette]);
|
|
553
566
|
const state = useSubjectAccountLink({
|
|
554
567
|
subject,
|
|
555
568
|
boundAccountId,
|
|
@@ -564,9 +577,9 @@ var AccountLinkPanel = ({
|
|
|
564
577
|
[accounts, bindings, subject, unnamedLabel]
|
|
565
578
|
);
|
|
566
579
|
const selectedLabel = options.find((option) => option.value === state.selectedAccountId)?.label ?? "";
|
|
567
|
-
return /* @__PURE__ */ jsxs(View, { style:
|
|
568
|
-
/* @__PURE__ */ jsx(Text, { style:
|
|
569
|
-
/* @__PURE__ */ jsx(Text, { style:
|
|
580
|
+
return /* @__PURE__ */ jsxs(View, { style: styles2.panel, testID: testIDPrefix, children: [
|
|
581
|
+
/* @__PURE__ */ jsx(Text, { style: styles2.heading, children: t(ACCESS_ADMIN_I18N.accountPanelHeading, subject.displayName) }),
|
|
582
|
+
/* @__PURE__ */ jsx(Text, { style: styles2.note, children: t(ACCESS_ADMIN_I18N.accountPanelNote) }),
|
|
570
583
|
options.length > 0 ? /* @__PURE__ */ jsx(
|
|
571
584
|
SelectControl,
|
|
572
585
|
{
|
|
@@ -579,8 +592,8 @@ var AccountLinkPanel = ({
|
|
|
579
592
|
testID: `${testIDPrefix}-picker`,
|
|
580
593
|
value: state.selectedAccountId ?? ""
|
|
581
594
|
}
|
|
582
|
-
) : /* @__PURE__ */ jsx(Text, { style:
|
|
583
|
-
/* @__PURE__ */ jsxs(View, { style:
|
|
595
|
+
) : /* @__PURE__ */ jsx(Text, { style: styles2.note, testID: `${testIDPrefix}-no-accounts`, children: t(ACCESS_ADMIN_I18N.accountNone) }),
|
|
596
|
+
/* @__PURE__ */ jsxs(View, { style: styles2.actions, children: [
|
|
584
597
|
/* @__PURE__ */ jsx(
|
|
585
598
|
Button,
|
|
586
599
|
{
|
|
@@ -673,6 +686,18 @@ function roleOptions(assignableRoles) {
|
|
|
673
686
|
function tenantValueToId(value) {
|
|
674
687
|
return value === NO_TENANT_VALUE ? null : value;
|
|
675
688
|
}
|
|
689
|
+
function isBlocking(wasActive, active) {
|
|
690
|
+
return wasActive && !active;
|
|
691
|
+
}
|
|
692
|
+
function isBlockReasonMissing(wasActive, active, blockedReason) {
|
|
693
|
+
return isBlocking(wasActive, active) && blockedReason.trim() === "";
|
|
694
|
+
}
|
|
695
|
+
function buildEditPatch(input) {
|
|
696
|
+
const patch = { displayName: input.displayName.trim(), role: input.role, active: input.active };
|
|
697
|
+
if (isBlocking(input.wasActive, input.active)) patch.blockedReason = input.blockedReason.trim();
|
|
698
|
+
if (input.tenantId !== void 0) patch.tenantId = input.tenantId;
|
|
699
|
+
return patch;
|
|
700
|
+
}
|
|
676
701
|
var ACTIONS_GAP = 8;
|
|
677
702
|
function buildUserColumns({
|
|
678
703
|
t,
|
|
@@ -728,7 +753,7 @@ function buildUserColumns({
|
|
|
728
753
|
variant: "secondary"
|
|
729
754
|
}
|
|
730
755
|
),
|
|
731
|
-
/* @__PURE__ */ jsx(
|
|
756
|
+
onReset !== void 0 ? /* @__PURE__ */ jsx(
|
|
732
757
|
Button,
|
|
733
758
|
{
|
|
734
759
|
accessibilityHint: t(ACCESS_ADMIN_I18N.usersResetHint),
|
|
@@ -739,7 +764,7 @@ function buildUserColumns({
|
|
|
739
764
|
testID: `${testIDPrefix}-reset-${user.id}`,
|
|
740
765
|
variant: "secondary"
|
|
741
766
|
}
|
|
742
|
-
)
|
|
767
|
+
) : null
|
|
743
768
|
] })
|
|
744
769
|
}
|
|
745
770
|
];
|
|
@@ -911,6 +936,7 @@ var EditUserModal = ({
|
|
|
911
936
|
const [role, setRole] = useState("");
|
|
912
937
|
const [tenantValue, setTenantValue] = useState(NO_TENANT_VALUE);
|
|
913
938
|
const [active, setActive] = useState(true);
|
|
939
|
+
const [blockedReason, setBlockedReason] = useState("");
|
|
914
940
|
const [submitting, setSubmitting] = useState(false);
|
|
915
941
|
const userId = user?.id;
|
|
916
942
|
useEffect(() => {
|
|
@@ -919,28 +945,36 @@ var EditUserModal = ({
|
|
|
919
945
|
setRole(user.roles[0] ?? "");
|
|
920
946
|
setTenantValue(user.tenantId ?? NO_TENANT_VALUE);
|
|
921
947
|
setActive(user.active);
|
|
948
|
+
setBlockedReason(user.blockedReason ?? "");
|
|
922
949
|
setSubmitting(false);
|
|
923
950
|
}, [visible, userId, user]);
|
|
924
|
-
const
|
|
951
|
+
const wasActive = user?.active ?? true;
|
|
952
|
+
const canSubmit = !submitting && displayName.trim() !== "" && role !== "" && !isBlockReasonMissing(wasActive, active, blockedReason);
|
|
925
953
|
const handleSubmit = async () => {
|
|
926
954
|
if (user === null) return;
|
|
927
955
|
setSubmitting(true);
|
|
928
|
-
const patch = {
|
|
929
|
-
displayName
|
|
956
|
+
const patch = buildEditPatch({
|
|
957
|
+
displayName,
|
|
930
958
|
role,
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
959
|
+
wasActive,
|
|
960
|
+
active,
|
|
961
|
+
blockedReason,
|
|
962
|
+
tenantId: isPlatformAdmin ? tenantValueToId(tenantValue) : void 0
|
|
963
|
+
});
|
|
934
964
|
const ok = await onSubmit(user.id, patch);
|
|
935
965
|
setSubmitting(false);
|
|
936
966
|
if (ok) onCancel();
|
|
937
967
|
};
|
|
968
|
+
const submitIfReady = () => {
|
|
969
|
+
if (canSubmit) void handleSubmit();
|
|
970
|
+
};
|
|
938
971
|
return /* @__PURE__ */ jsx(ModalShell, { onCancel, title: t(ACCESS_ADMIN_I18N.usersEditTitle), visible, children: /* @__PURE__ */ jsxs(View, { style: modalFormStyles.body, testID: testIDPrefix, children: [
|
|
939
972
|
/* @__PURE__ */ jsx(
|
|
940
973
|
FormField,
|
|
941
974
|
{
|
|
942
975
|
label: t(ACCESS_ADMIN_I18N.usersFieldDisplayName),
|
|
943
976
|
onChangeText: setDisplayName,
|
|
977
|
+
onSubmitEditing: submitIfReady,
|
|
944
978
|
placeholder: t(ACCESS_ADMIN_I18N.usersDisplayNamePlaceholder),
|
|
945
979
|
required: true,
|
|
946
980
|
testID: `${testIDPrefix}-display-name`,
|
|
@@ -981,6 +1015,19 @@ var EditUserModal = ({
|
|
|
981
1015
|
value: active
|
|
982
1016
|
}
|
|
983
1017
|
),
|
|
1018
|
+
active ? null : /* @__PURE__ */ jsx(
|
|
1019
|
+
FormField,
|
|
1020
|
+
{
|
|
1021
|
+
accessibilityHint: t(ACCESS_ADMIN_I18N.usersBlockedReasonHint),
|
|
1022
|
+
label: t(ACCESS_ADMIN_I18N.usersFieldBlockedReason),
|
|
1023
|
+
onChangeText: setBlockedReason,
|
|
1024
|
+
onSubmitEditing: submitIfReady,
|
|
1025
|
+
placeholder: t(ACCESS_ADMIN_I18N.usersBlockedReasonPlaceholder),
|
|
1026
|
+
required: wasActive,
|
|
1027
|
+
testID: `${testIDPrefix}-blocked-reason`,
|
|
1028
|
+
value: blockedReason
|
|
1029
|
+
}
|
|
1030
|
+
),
|
|
984
1031
|
/* @__PURE__ */ jsxs(View, { style: modalFormStyles.actions, children: [
|
|
985
1032
|
/* @__PURE__ */ jsx(
|
|
986
1033
|
Button,
|
|
@@ -1073,6 +1120,8 @@ var ResetPasswordModal = ({
|
|
|
1073
1120
|
] })
|
|
1074
1121
|
] }) });
|
|
1075
1122
|
};
|
|
1123
|
+
var MISSING_CREATE = "createUser is not provided";
|
|
1124
|
+
var MISSING_RESET = "resetPassword is not provided";
|
|
1076
1125
|
function useUserManagement(api, t) {
|
|
1077
1126
|
const [users, setUsers] = useState([]);
|
|
1078
1127
|
const [loading, setLoading] = useState(true);
|
|
@@ -1114,7 +1163,7 @@ function useUserManagement(api, t) {
|
|
|
1114
1163
|
);
|
|
1115
1164
|
const create = useCallback(
|
|
1116
1165
|
(input) => runWrite(
|
|
1117
|
-
() => api.createUser(input),
|
|
1166
|
+
() => api.createUser ? api.createUser(input) : Promise.reject(new Error(MISSING_CREATE)),
|
|
1118
1167
|
ACCESS_ADMIN_I18N.usersCreateSuccess,
|
|
1119
1168
|
ACCESS_ADMIN_I18N.usersCreateFailed
|
|
1120
1169
|
),
|
|
@@ -1130,7 +1179,7 @@ function useUserManagement(api, t) {
|
|
|
1130
1179
|
);
|
|
1131
1180
|
const resetPassword = useCallback(
|
|
1132
1181
|
(id, password) => runWrite(
|
|
1133
|
-
() => api.resetPassword(id, password),
|
|
1182
|
+
() => api.resetPassword ? api.resetPassword(id, password) : Promise.reject(new Error(MISSING_RESET)),
|
|
1134
1183
|
ACCESS_ADMIN_I18N.usersResetSuccess,
|
|
1135
1184
|
ACCESS_ADMIN_I18N.usersResetFailed
|
|
1136
1185
|
),
|
|
@@ -1162,7 +1211,7 @@ var UserManagementPanel = ({
|
|
|
1162
1211
|
testID = ACCESS_ADMIN_TEST_IDS.usersPanel
|
|
1163
1212
|
}) => {
|
|
1164
1213
|
const palette = useAccessAdminPalette();
|
|
1165
|
-
const
|
|
1214
|
+
const styles2 = useMemo(() => buildStyles3(palette), [palette]);
|
|
1166
1215
|
const controller = useUserManagement(api, t);
|
|
1167
1216
|
const [query, setQuery] = useState("");
|
|
1168
1217
|
const [openModal, setOpenModal] = useState("none" /* None */);
|
|
@@ -1180,18 +1229,26 @@ var UserManagementPanel = ({
|
|
|
1180
1229
|
setOpenModal("reset" /* Reset */);
|
|
1181
1230
|
};
|
|
1182
1231
|
const closeModal = () => setOpenModal("none" /* None */);
|
|
1232
|
+
const canCreate = api.createUser !== void 0;
|
|
1233
|
+
const canReset = api.resetPassword !== void 0;
|
|
1183
1234
|
const columns = useMemo(
|
|
1184
|
-
() => buildUserColumns({
|
|
1185
|
-
|
|
1235
|
+
() => buildUserColumns({
|
|
1236
|
+
t,
|
|
1237
|
+
tenants,
|
|
1238
|
+
testIDPrefix: testID,
|
|
1239
|
+
onEdit: openEdit,
|
|
1240
|
+
onReset: canReset ? openReset : void 0
|
|
1241
|
+
}),
|
|
1242
|
+
[t, tenants, testID, canReset]
|
|
1186
1243
|
);
|
|
1187
|
-
return /* @__PURE__ */ jsxs(View, { style:
|
|
1244
|
+
return /* @__PURE__ */ jsxs(View, { style: styles2.panel, testID, children: [
|
|
1188
1245
|
/* @__PURE__ */ jsx(ToastHost, { subscribe: controller.toastSubscribe, toastTestID: `${testID}-toast` }),
|
|
1189
|
-
/* @__PURE__ */ jsx(Text, { style:
|
|
1190
|
-
/* @__PURE__ */ jsx(Text, { style:
|
|
1246
|
+
/* @__PURE__ */ jsx(Text, { style: styles2.heading, children: t(ACCESS_ADMIN_I18N.usersHeading) }),
|
|
1247
|
+
/* @__PURE__ */ jsx(Text, { style: styles2.note, children: t(ACCESS_ADMIN_I18N.usersNote) }),
|
|
1191
1248
|
/* @__PURE__ */ jsx(
|
|
1192
1249
|
FilterBar,
|
|
1193
1250
|
{
|
|
1194
|
-
actions: /* @__PURE__ */ jsx(
|
|
1251
|
+
actions: canCreate ? /* @__PURE__ */ jsx(
|
|
1195
1252
|
Button,
|
|
1196
1253
|
{
|
|
1197
1254
|
accessibilityHint: t(ACCESS_ADMIN_I18N.usersCreateHint),
|
|
@@ -1200,11 +1257,11 @@ var UserManagementPanel = ({
|
|
|
1200
1257
|
onPress: () => setOpenModal("create" /* Create */),
|
|
1201
1258
|
testID: `${testID}-create`
|
|
1202
1259
|
}
|
|
1203
|
-
),
|
|
1260
|
+
) : void 0,
|
|
1204
1261
|
resultsCount: visibleUsers.length,
|
|
1205
1262
|
resultsLabel: t(ACCESS_ADMIN_I18N.usersResultsLabel),
|
|
1206
1263
|
testID: `${testID}-filter-bar`,
|
|
1207
|
-
children: /* @__PURE__ */ jsx(View, { style:
|
|
1264
|
+
children: /* @__PURE__ */ jsx(View, { style: styles2.search, children: /* @__PURE__ */ jsx(
|
|
1208
1265
|
FormField,
|
|
1209
1266
|
{
|
|
1210
1267
|
accessibilityLabel: t(ACCESS_ADMIN_I18N.usersSearchLabel),
|
|
@@ -1219,8 +1276,8 @@ var UserManagementPanel = ({
|
|
|
1219
1276
|
) })
|
|
1220
1277
|
}
|
|
1221
1278
|
),
|
|
1222
|
-
controller.loadFailed ? /* @__PURE__ */ jsxs(View, { style:
|
|
1223
|
-
/* @__PURE__ */ jsx(Text, { style:
|
|
1279
|
+
controller.loadFailed ? /* @__PURE__ */ jsxs(View, { style: styles2.errorBox, testID: `${testID}-load-error`, children: [
|
|
1280
|
+
/* @__PURE__ */ jsx(Text, { style: styles2.warning, children: t(ACCESS_ADMIN_I18N.usersLoadError) }),
|
|
1224
1281
|
/* @__PURE__ */ jsx(
|
|
1225
1282
|
Button,
|
|
1226
1283
|
{
|
|
@@ -1245,7 +1302,7 @@ var UserManagementPanel = ({
|
|
|
1245
1302
|
zebra: true
|
|
1246
1303
|
}
|
|
1247
1304
|
),
|
|
1248
|
-
/* @__PURE__ */ jsx(
|
|
1305
|
+
canCreate ? /* @__PURE__ */ jsx(
|
|
1249
1306
|
CreateUserModal,
|
|
1250
1307
|
{
|
|
1251
1308
|
assignableRoles,
|
|
@@ -1257,7 +1314,7 @@ var UserManagementPanel = ({
|
|
|
1257
1314
|
testIDPrefix: `${testID}-create-modal`,
|
|
1258
1315
|
visible: openModal === "create" /* Create */
|
|
1259
1316
|
}
|
|
1260
|
-
),
|
|
1317
|
+
) : null,
|
|
1261
1318
|
/* @__PURE__ */ jsx(
|
|
1262
1319
|
EditUserModal,
|
|
1263
1320
|
{
|
|
@@ -1272,7 +1329,7 @@ var UserManagementPanel = ({
|
|
|
1272
1329
|
visible: openModal === "edit" /* Edit */
|
|
1273
1330
|
}
|
|
1274
1331
|
),
|
|
1275
|
-
/* @__PURE__ */ jsx(
|
|
1332
|
+
canReset ? /* @__PURE__ */ jsx(
|
|
1276
1333
|
ResetPasswordModal,
|
|
1277
1334
|
{
|
|
1278
1335
|
onCancel: closeModal,
|
|
@@ -1282,7 +1339,7 @@ var UserManagementPanel = ({
|
|
|
1282
1339
|
user: activeUser,
|
|
1283
1340
|
visible: openModal === "reset" /* Reset */
|
|
1284
1341
|
}
|
|
1285
|
-
)
|
|
1342
|
+
) : null
|
|
1286
1343
|
] });
|
|
1287
1344
|
};
|
|
1288
1345
|
var buildStyles3 = (c) => StyleSheet.create({
|
|
@@ -1302,6 +1359,116 @@ var buildStyles3 = (c) => StyleSheet.create({
|
|
|
1302
1359
|
warning: { color: c.danger, fontSize: FONT_SM3, fontWeight: "600" }
|
|
1303
1360
|
});
|
|
1304
1361
|
|
|
1305
|
-
|
|
1362
|
+
// src/PermissionMatrix/permissionMatrixModel.ts
|
|
1363
|
+
function buildPermissionMatrix(roles, permissions, grants) {
|
|
1364
|
+
return roles.map((role) => {
|
|
1365
|
+
const held = new Set(grants[role.id] ?? []);
|
|
1366
|
+
const cells = permissions.map((permission) => ({ permission, granted: held.has(permission.id) }));
|
|
1367
|
+
return { role, cells, grantedCount: cells.filter((cell) => cell.granted).length };
|
|
1368
|
+
});
|
|
1369
|
+
}
|
|
1370
|
+
function grantStatusLabel(granted, t) {
|
|
1371
|
+
return granted ? t(ACCESS_ADMIN_I18N.permissionsGranted) : t(ACCESS_ADMIN_I18N.permissionsNotGranted);
|
|
1372
|
+
}
|
|
1373
|
+
function cellAccessibilityLabel(role, permission, granted, t) {
|
|
1374
|
+
return t(ACCESS_ADMIN_I18N.permissionsCellLabel, role.label, permission.label, grantStatusLabel(granted, t));
|
|
1375
|
+
}
|
|
1376
|
+
var SPACE_XS4 = 4;
|
|
1377
|
+
var SPACE_SM5 = 8;
|
|
1378
|
+
var SPACE_MD5 = 12;
|
|
1379
|
+
var RADIUS = 8;
|
|
1380
|
+
var MAX_WIDTH = 1200;
|
|
1381
|
+
var LABEL_COLUMN_WIDTH = 280;
|
|
1382
|
+
var ROLE_COLUMN_WIDTH = 140;
|
|
1383
|
+
var HEADING_SIZE = 18;
|
|
1384
|
+
var BODY_SIZE = 14;
|
|
1385
|
+
var LINE_HEIGHT = 20;
|
|
1386
|
+
var styles = StyleSheet.create({
|
|
1387
|
+
root: { alignSelf: "center", gap: SPACE_MD5, maxWidth: MAX_WIDTH, width: "100%" },
|
|
1388
|
+
heading: { fontSize: HEADING_SIZE, fontWeight: "600", lineHeight: LINE_HEIGHT + SPACE_XS4 },
|
|
1389
|
+
body: { fontSize: BODY_SIZE, lineHeight: LINE_HEIGHT },
|
|
1390
|
+
strong: { fontSize: BODY_SIZE, fontWeight: "600", lineHeight: LINE_HEIGHT },
|
|
1391
|
+
list: { gap: SPACE_MD5 },
|
|
1392
|
+
card: { borderRadius: RADIUS, borderWidth: StyleSheet.hairlineWidth, gap: SPACE_SM5, padding: SPACE_MD5 },
|
|
1393
|
+
stackRow: { flexDirection: "row", flexWrap: "wrap", gap: SPACE_SM5, justifyContent: "space-between" },
|
|
1394
|
+
stackLabel: { flexBasis: 0, flexGrow: 1, minWidth: 0 },
|
|
1395
|
+
tableRow: { borderBottomWidth: StyleSheet.hairlineWidth, flexDirection: "row" },
|
|
1396
|
+
labelCell: { padding: SPACE_SM5, width: LABEL_COLUMN_WIDTH },
|
|
1397
|
+
roleCell: { padding: SPACE_SM5, width: ROLE_COLUMN_WIDTH }
|
|
1398
|
+
});
|
|
1399
|
+
var statusColor = (granted, palette) => granted ? palette.textPrimary : palette.textSecondary;
|
|
1400
|
+
var StackedMatrix = ({ columns, palette, t, testID }) => /* @__PURE__ */ jsx(View, { style: styles.list, children: columns.map(({ role, cells, grantedCount }) => /* @__PURE__ */ jsxs(
|
|
1401
|
+
View,
|
|
1402
|
+
{
|
|
1403
|
+
style: [styles.card, { backgroundColor: palette.panelSurface, borderColor: palette.border }],
|
|
1404
|
+
testID: `${testID}-role-${role.id}`,
|
|
1405
|
+
children: [
|
|
1406
|
+
/* @__PURE__ */ jsx(Text, { style: [styles.strong, { color: palette.textPrimary }], children: role.label }),
|
|
1407
|
+
/* @__PURE__ */ jsx(Text, { style: [styles.body, { color: palette.textSecondary }], children: t(ACCESS_ADMIN_I18N.permissionsRoleCount, String(grantedCount), String(cells.length)) }),
|
|
1408
|
+
cells.map(({ permission, granted }) => /* @__PURE__ */ jsxs(
|
|
1409
|
+
View,
|
|
1410
|
+
{
|
|
1411
|
+
accessibilityHint: t(ACCESS_ADMIN_I18N.permissionsReadOnlyHint),
|
|
1412
|
+
accessibilityLabel: cellAccessibilityLabel(role, permission, granted, t),
|
|
1413
|
+
accessible: true,
|
|
1414
|
+
style: styles.stackRow,
|
|
1415
|
+
testID: `${testID}-cell-${role.id}-${permission.id}`,
|
|
1416
|
+
children: [
|
|
1417
|
+
/* @__PURE__ */ jsx(Text, { style: [styles.body, styles.stackLabel, { color: palette.textPrimary }], children: permission.label }),
|
|
1418
|
+
/* @__PURE__ */ jsx(Text, { style: [granted ? styles.strong : styles.body, { color: statusColor(granted, palette) }], children: grantStatusLabel(granted, t) })
|
|
1419
|
+
]
|
|
1420
|
+
},
|
|
1421
|
+
permission.id
|
|
1422
|
+
))
|
|
1423
|
+
]
|
|
1424
|
+
},
|
|
1425
|
+
role.id
|
|
1426
|
+
)) });
|
|
1427
|
+
var TableMatrix = ({ columns, permissions, palette, t, testID }) => /* @__PURE__ */ jsx(ScrollView, { horizontal: true, testID: `${testID}-table`, children: /* @__PURE__ */ jsxs(View, { style: [styles.card, { backgroundColor: palette.panelSurface, borderColor: palette.border }], children: [
|
|
1428
|
+
/* @__PURE__ */ jsxs(View, { style: [styles.tableRow, { borderColor: palette.border }], children: [
|
|
1429
|
+
/* @__PURE__ */ jsx(Text, { style: [styles.strong, styles.labelCell, { color: palette.textPrimary }], children: t(ACCESS_ADMIN_I18N.permissionsColPermission) }),
|
|
1430
|
+
columns.map(({ role }) => /* @__PURE__ */ jsx(Text, { style: [styles.strong, styles.roleCell, { color: palette.textPrimary }], children: role.label }, role.id))
|
|
1431
|
+
] }),
|
|
1432
|
+
permissions.map((permission, index) => /* @__PURE__ */ jsxs(View, { style: [styles.tableRow, { borderColor: palette.border }], children: [
|
|
1433
|
+
/* @__PURE__ */ jsx(Text, { style: [styles.body, styles.labelCell, { color: palette.textPrimary }], children: permission.label }),
|
|
1434
|
+
columns.map(({ role, cells }) => {
|
|
1435
|
+
const granted = cells[index]?.granted === true;
|
|
1436
|
+
return /* @__PURE__ */ jsx(
|
|
1437
|
+
Text,
|
|
1438
|
+
{
|
|
1439
|
+
accessibilityHint: t(ACCESS_ADMIN_I18N.permissionsReadOnlyHint),
|
|
1440
|
+
accessibilityLabel: cellAccessibilityLabel(role, permission, granted, t),
|
|
1441
|
+
style: [granted ? styles.strong : styles.body, styles.roleCell, { color: statusColor(granted, palette) }],
|
|
1442
|
+
testID: `${testID}-cell-${role.id}-${permission.id}`,
|
|
1443
|
+
children: grantStatusLabel(granted, t)
|
|
1444
|
+
},
|
|
1445
|
+
role.id
|
|
1446
|
+
);
|
|
1447
|
+
})
|
|
1448
|
+
] }, permission.id))
|
|
1449
|
+
] }) });
|
|
1450
|
+
var PermissionMatrix = ({
|
|
1451
|
+
roles,
|
|
1452
|
+
permissions,
|
|
1453
|
+
grants,
|
|
1454
|
+
t,
|
|
1455
|
+
testID = ACCESS_ADMIN_TEST_IDS.permissionMatrix
|
|
1456
|
+
}) => {
|
|
1457
|
+
const palette = useAccessAdminPalette();
|
|
1458
|
+
const { width } = useWindowDimensions();
|
|
1459
|
+
const columns = useMemo(() => buildPermissionMatrix(roles, permissions, grants), [roles, permissions, grants]);
|
|
1460
|
+
const isWide = width >= LAYOUT_COLLAPSE_BREAKPOINT;
|
|
1461
|
+
const isEmpty = roles.length === 0 || permissions.length === 0;
|
|
1462
|
+
const partProps = { columns, permissions, palette, t, testID };
|
|
1463
|
+
return /* @__PURE__ */ jsxs(View, { style: styles.root, testID, children: [
|
|
1464
|
+
/* @__PURE__ */ jsx(Text, { accessibilityRole: "header", style: [styles.heading, { color: palette.textPrimary }], children: t(ACCESS_ADMIN_I18N.permissionsHeading) }),
|
|
1465
|
+
/* @__PURE__ */ jsx(Text, { style: [styles.body, { color: palette.textSecondary }], children: t(ACCESS_ADMIN_I18N.permissionsNote) }),
|
|
1466
|
+
isEmpty ? /* @__PURE__ */ jsx(Text, { style: [styles.body, { color: palette.textSecondary }], testID: `${testID}-empty`, children: t(ACCESS_ADMIN_I18N.permissionsEmpty) }) : null,
|
|
1467
|
+
!isEmpty && isWide ? /* @__PURE__ */ jsx(TableMatrix, { ...partProps }) : null,
|
|
1468
|
+
!isEmpty && !isWide ? /* @__PURE__ */ jsx(StackedMatrix, { ...partProps }) : null
|
|
1469
|
+
] });
|
|
1470
|
+
};
|
|
1471
|
+
|
|
1472
|
+
export { ACCESS_ADMIN_I18N, ACCESS_ADMIN_TEST_IDS, AccessLinkPanel, AccessResultTone, AccountLinkPanel, PermissionMatrix, UserManagementPanel, accountDisplayLabel, activeLinksForSubject, buildAccountOptions, buildCapabilityLinkMailto, buildPermissionMatrix, capabilityExpiryDate, capabilityExpiryDays, daysUntilAnchor, formatLinkDate, linksForSubject, useAccessAdminPalette, useCapabilityLinkMint, useSubjectAccountLink };
|
|
1306
1473
|
//# sourceMappingURL=index.mjs.map
|
|
1307
1474
|
//# sourceMappingURL=index.mjs.map
|