@zealamic/payload-auth-rbac-plugin 1.0.1 → 1.0.2

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.
Files changed (55) hide show
  1. package/README.md +17 -2
  2. package/dist/collections/users/index.js +11 -8
  3. package/dist/collections/users/index.js.map +1 -1
  4. package/dist/index.d.ts +1 -0
  5. package/dist/index.js.map +1 -1
  6. package/dist/types.d.ts +6 -0
  7. package/dist/types.js.map +1 -1
  8. package/package.json +20 -16
  9. package/assets/cover-photo.jpg +0 -0
  10. package/docs/COLLECTIONS.md +0 -440
  11. package/docs/TRANSLATIONS.md +0 -469
  12. package/docs/UTILS.md +0 -226
  13. package/src/collections/permission-actions/default-data.ts +0 -36
  14. package/src/collections/permission-actions/index.ts +0 -144
  15. package/src/collections/permission-actions/types.ts +0 -56
  16. package/src/collections/permission-features/default-data.ts +0 -30
  17. package/src/collections/permission-features/index.ts +0 -122
  18. package/src/collections/permission-features/types.ts +0 -47
  19. package/src/collections/permissions/default-data.ts +0 -38
  20. package/src/collections/permissions/index.ts +0 -160
  21. package/src/collections/permissions/types.ts +0 -57
  22. package/src/collections/roles/default-data.ts +0 -44
  23. package/src/collections/roles/hooks/sync-permission-matrix-draft.ts +0 -73
  24. package/src/collections/roles/index.ts +0 -178
  25. package/src/collections/roles/types.ts +0 -56
  26. package/src/collections/roles-permissions/default-data.ts +0 -28
  27. package/src/collections/roles-permissions/index.ts +0 -107
  28. package/src/collections/roles-permissions/types.ts +0 -42
  29. package/src/collections/users/default-data.ts +0 -19
  30. package/src/collections/users/index.ts +0 -148
  31. package/src/collections/users/parent-path.ts +0 -310
  32. package/src/collections/users/types.ts +0 -25
  33. package/src/components/role-permission-matrix-client/default-data.ts +0 -25
  34. package/src/components/role-permission-matrix-client/index.tsx +0 -369
  35. package/src/components/role-permission-matrix-client/matrix.module.scss +0 -66
  36. package/src/components/role-permission-matrix-client/types.ts +0 -16
  37. package/src/endpoints/customEndpointHandler.ts +0 -5
  38. package/src/exports/client.ts +0 -1
  39. package/src/exports/rsc.ts +0 -0
  40. package/src/index.ts +0 -249
  41. package/src/lib/constants/general.ts +0 -1
  42. package/src/lib/constants/index.ts +0 -15
  43. package/src/lib/constants/permission-action.ts +0 -9
  44. package/src/lib/constants/permission-feature.ts +0 -4
  45. package/src/lib/constants/permission.ts +0 -4
  46. package/src/lib/constants/role.ts +0 -10
  47. package/src/lib/constants/user.ts +0 -1
  48. package/src/lib/utils/access.ts +0 -611
  49. package/src/lib/utils/data.ts +0 -7
  50. package/src/lib/utils/fields.ts +0 -62
  51. package/src/lib/utils/index.ts +0 -4
  52. package/src/lib/utils/localization.ts +0 -106
  53. package/src/styles/variables.scss +0 -1
  54. package/src/types.ts +0 -64
  55. /package/{src → dist}/general-types.d.ts +0 -0
@@ -1,369 +0,0 @@
1
- "use client";
2
-
3
- import {
4
- useConfig,
5
- useDocumentInfo,
6
- useField,
7
- useTranslation,
8
- } from "@payloadcms/ui";
9
- import { Fragment, useEffect, useId, useMemo, useRef, useState } from "react";
10
- import type { PermissionAction } from "../../collections/permission-actions/types.js";
11
- import type { PermissionFeature } from "../../collections/permission-features/types.js";
12
- import type { Permission } from "../../collections/permissions/types.js";
13
- import type { RolePermission } from "../../collections/roles-permissions/types.js";
14
- import { STATUS as PERMISSION_STATUS } from "../../lib/constants/permission.js";
15
- import {
16
- STATUS as PERMISSION_ACTION_STATUS,
17
- TYPE,
18
- } from "../../lib/constants/permission-action.js";
19
- import { STATUS as PERMISSION_FEATURE_STATUS } from "../../lib/constants/permission-feature.js";
20
- import { toID } from "../../lib/utils/data.js";
21
-
22
- import styles from "./matrix.module.scss";
23
-
24
- const RBAC_PREFIX = "rbac";
25
-
26
- type ApiListResponse<T> = {
27
- docs?: T[];
28
- };
29
-
30
- export const RolePermissionMatrixClient = () => {
31
- const checkboxId = useId();
32
- const { config } = useConfig();
33
- const { hasSavePermission, id } = useDocumentInfo();
34
- const { setValue, value } = useField<Record<string, boolean> | null>({
35
- path: "permissionMatrixDraft",
36
- });
37
- const isReadOnly = !hasSavePermission;
38
-
39
- const [features, setFeatures] = useState<PermissionFeature[]>([]);
40
- const [actions, setActions] = useState<PermissionAction[]>([]);
41
- const [permissions, setPermissions] = useState<Permission[]>([]);
42
- const [rolePermissions, setRolePermissions] = useState<RolePermission[]>([]);
43
- const [loading, setLoading] = useState(true);
44
- const { t } = useTranslation();
45
- const seededForRoleIdRef = useRef<string | null>(null);
46
-
47
- useEffect(() => {
48
- const run = async () => {
49
- setLoading(true);
50
- try {
51
- const base = config?.routes?.api || "/api";
52
-
53
- const [featuresRes, actionsRes, permissionsRes, rolePermissionsRes] =
54
- await Promise.all([
55
- fetch(
56
- `${base}/permission-features?limit=0&depth=0&where[status][equals]=${PERMISSION_FEATURE_STATUS.ACTIVE}`,
57
- { credentials: "include" },
58
- ),
59
- fetch(
60
- `${base}/permission-actions?limit=0&depth=0&where[status][equals]=${PERMISSION_ACTION_STATUS.ACTIVE}`,
61
- { credentials: "include" },
62
- ),
63
- fetch(
64
- `${base}/permissions?limit=0&depth=1&where[status][equals]=${PERMISSION_STATUS.ACTIVE}`,
65
- { credentials: "include" },
66
- ),
67
- id
68
- ? fetch(
69
- `${base}/roles-permissions?limit=0&depth=0&where[role][equals]=${id}`,
70
- {
71
- credentials: "include",
72
- },
73
- )
74
- : Promise.resolve(new Response(JSON.stringify({ docs: [] }))),
75
- ]);
76
-
77
- const featuresJson =
78
- (await featuresRes.json()) as ApiListResponse<PermissionFeature>;
79
- const actionsJson =
80
- (await actionsRes.json()) as ApiListResponse<PermissionAction>;
81
- const permissionsJson =
82
- (await permissionsRes.json()) as ApiListResponse<Permission>;
83
- const rolePermissionsJson =
84
- (await rolePermissionsRes.json()) as ApiListResponse<RolePermission>;
85
-
86
- setFeatures(
87
- featuresJson.docs?.sort(
88
- (a, b) => (a?.sortOrder ?? 0) - (b?.sortOrder ?? 0),
89
- ) || [],
90
- );
91
- setActions(
92
- actionsJson.docs?.sort(
93
- (a, b) => (a?.sortOrder ?? 0) - (b?.sortOrder ?? 0),
94
- ) || [],
95
- );
96
- setPermissions(permissionsJson.docs || []);
97
- setRolePermissions(rolePermissionsJson.docs || []);
98
- } finally {
99
- setLoading(false);
100
- }
101
- };
102
-
103
- void run();
104
- }, [config?.routes?.api, id]);
105
-
106
- const enabledByPermissionID = useMemo(() => {
107
- const map = new Map<string, boolean>();
108
- for (const row of rolePermissions) {
109
- map.set(toID(row.permission), Boolean(row.enabled));
110
- }
111
- return map;
112
- }, [rolePermissions]);
113
-
114
- const draftValue = (
115
- value && typeof value === "object" && !Array.isArray(value) ? value : {}
116
- ) as Record<string, boolean>;
117
-
118
- useEffect(() => {
119
- if (!id || loading) {
120
- return;
121
- }
122
-
123
- const roleId = String(id);
124
- if (seededForRoleIdRef.current === roleId) {
125
- return;
126
- }
127
-
128
- const fromRolesPermissions: Record<string, boolean> = {};
129
- for (const [permissionID, enabled] of enabledByPermissionID.entries()) {
130
- if (permissionID) {
131
- fromRolesPermissions[permissionID] = enabled;
132
- }
133
- }
134
-
135
- const fromDocument =
136
- value && typeof value === "object" && !Array.isArray(value)
137
- ? (value as Record<string, boolean>)
138
- : {};
139
-
140
- const hasRolesPermissions = Object.keys(fromRolesPermissions).length > 0;
141
- const hasDocumentDraft = Object.keys(fromDocument).length > 0;
142
-
143
- if (!hasRolesPermissions && !hasDocumentDraft) {
144
- return;
145
- }
146
-
147
- seededForRoleIdRef.current = roleId;
148
- setValue({
149
- ...fromRolesPermissions,
150
- ...fromDocument,
151
- });
152
- }, [enabledByPermissionID, id, loading, setValue, value]);
153
-
154
- if (!id) {
155
- return (
156
- <div className={styles[`${RBAC_PREFIX}-component-placeholder`]}>
157
- {t(
158
- `components:rolePermissionMatrix:viewInUpdateScreenOnly:label` as Parameters<
159
- typeof t
160
- >[0],
161
- )}
162
- </div>
163
- );
164
- }
165
-
166
- if (loading) {
167
- return (
168
- <div className={styles[`${RBAC_PREFIX}-component-placeholder`]}>
169
- {t(
170
- `components:rolePermissionMatrix:loading:placeholder` as Parameters<
171
- typeof t
172
- >[0],
173
- )}
174
- </div>
175
- );
176
- }
177
-
178
- return (
179
- <div>
180
- <div className={styles[`${RBAC_PREFIX}-component-title`]}>
181
- {t(`components:rolePermissionMatrix:title` as Parameters<typeof t>[0])}
182
- </div>
183
-
184
- <div className={styles[`${RBAC_PREFIX}-table-container`]}>
185
- <table className={styles[`${RBAC_PREFIX}-table`]}>
186
- <thead>
187
- <tr>
188
- <th className={styles[`${RBAC_PREFIX}-table-th-feature`]}>
189
- {t(
190
- `components:rolePermissionMatrix:featuresLabel` as Parameters<
191
- typeof t
192
- >[0],
193
- )}
194
- </th>
195
- <th
196
- className={styles[`${RBAC_PREFIX}-table-th-action`]}
197
- colSpan={
198
- actions.filter((action) => action.type === TYPE.MAIN).length
199
- }
200
- >
201
- {t(
202
- `components:rolePermissionMatrix:actionsLabel` as Parameters<
203
- typeof t
204
- >[0],
205
- )}
206
- </th>
207
- </tr>
208
- </thead>
209
- <tbody>
210
- {features.map((feature) => {
211
- const mainActions = actions.filter(
212
- (action) => action.type === TYPE.MAIN,
213
- );
214
- const subActions = actions.filter(
215
- (action) =>
216
- action.type === TYPE.SUB &&
217
- permissions.some(
218
- (permission) =>
219
- toID(permission.permissionAction) === String(action.id) &&
220
- toID(permission.permissionFeature) === String(feature.id),
221
- ),
222
- );
223
- const isSubActionInPermission = subActions.length > 0;
224
-
225
- return (
226
- <Fragment key={String(feature.id)}>
227
- <tr>
228
- <td className={styles[`${RBAC_PREFIX}-table-td-feature`]}>
229
- {t(
230
- `components:rolePermissionMatrix:features:${feature.code}` as Parameters<
231
- typeof t
232
- >[0],
233
- ) || feature.id}
234
- </td>
235
-
236
- {mainActions.map((action) => {
237
- const matchedPermission = permissions.find(
238
- (permission) =>
239
- toID(permission.permissionFeature) ===
240
- String(feature.id) &&
241
- toID(permission.permissionAction) ===
242
- String(action.id),
243
- );
244
-
245
- if (!matchedPermission) {
246
- return (
247
- <td
248
- key={`${feature.id}-${action.id}`}
249
- className={styles[`${RBAC_PREFIX}-table-td-action`]}
250
- >
251
- -
252
- </td>
253
- );
254
- }
255
-
256
- const permissionID = String(matchedPermission.id);
257
- const checked =
258
- typeof draftValue[permissionID] === "boolean"
259
- ? draftValue[permissionID]
260
- : (enabledByPermissionID.get(permissionID) ?? false);
261
-
262
- return (
263
- <td
264
- key={`${feature.id}-${action.id}`}
265
- className={styles[`${RBAC_PREFIX}-table-td-action`]}
266
- >
267
- <div
268
- className={
269
- styles[`${RBAC_PREFIX}-table-td-action-container`]
270
- }
271
- >
272
- <input
273
- type="checkbox"
274
- id={`permission-matrix-checkbox-${checkboxId}-${feature.id}-${action.id}`}
275
- name={`permission-matrix-checkbox-${checkboxId}-${feature.id}-${action.id}`}
276
- checked={checked}
277
- disabled={isReadOnly}
278
- onChange={(event) => {
279
- setValue({
280
- ...draftValue,
281
- [permissionID]: event.target.checked,
282
- });
283
- }}
284
- className={
285
- styles[`${RBAC_PREFIX}-table-td-action-input`]
286
- }
287
- />
288
- <label
289
- htmlFor={`permission-matrix-checkbox-${checkboxId}-${feature.id}-${action.id}`}
290
- className={
291
- styles[`${RBAC_PREFIX}-table-td-action-label`]
292
- }
293
- >
294
- {t(
295
- `components:rolePermissionMatrix:actions:${action.code}` as Parameters<
296
- typeof t
297
- >[0],
298
- ) || action.id}
299
- </label>
300
- </div>
301
- </td>
302
- );
303
- })}
304
- </tr>
305
-
306
- {isSubActionInPermission && (
307
- <tr>
308
- <td
309
- className={styles[`${RBAC_PREFIX}-table-td-feature`]}
310
- ></td>
311
- <td
312
- className={styles[`${RBAC_PREFIX}-table-td-action`]}
313
- colSpan={mainActions.length}
314
- >
315
- {subActions.map((action) => {
316
- const matchedPermission = permissions.find(
317
- (permission) =>
318
- toID(permission.permissionFeature) ===
319
- String(feature.id) &&
320
- toID(permission.permissionAction) ===
321
- String(action.id),
322
- );
323
-
324
- if (!matchedPermission) {
325
- return null;
326
- }
327
-
328
- const permissionID = String(matchedPermission.id);
329
- const checked =
330
- typeof draftValue[permissionID] === "boolean"
331
- ? draftValue[permissionID]
332
- : (enabledByPermissionID.get(permissionID) ??
333
- false);
334
-
335
- return (
336
- <div key={`${feature.id}-${action.id}-sub`}>
337
- <input
338
- type="checkbox"
339
- checked={checked}
340
- disabled={isReadOnly}
341
- onChange={(event) => {
342
- setValue({
343
- ...draftValue,
344
- [permissionID]: event.target.checked,
345
- });
346
- }}
347
- />{" "}
348
- <span
349
- style={{
350
- display: "inline-block",
351
- }}
352
- >
353
- {action.code || action.id}
354
- </span>
355
- </div>
356
- );
357
- })}
358
- </td>
359
- </tr>
360
- )}
361
- </Fragment>
362
- );
363
- })}
364
- </tbody>
365
- </table>
366
- </div>
367
- </div>
368
- );
369
- };
@@ -1,66 +0,0 @@
1
- // Import Payload compile-time SCSS vars ($breakpoint-s-width, etc.).
2
- // Note: @payloadcms/ui/scss/vars is not a published export — use dist/scss/vars.
3
- // @use "../../../node_modules/@payloadcms/ui/dist/scss/vars" as payload-vars;
4
- @use "../../styles/variables" as rbac-vars;
5
-
6
- $local-prefix: rbac-vars.$rbac-prefix;
7
-
8
- .#{$local-prefix}-component {
9
- &-label {
10
- opacity: 0.8;
11
- padding: 0.5rem 0;
12
- }
13
- &-placeholder {
14
- opacity: 0.8;
15
- padding: 0.5rem 0;
16
- }
17
- &-title {
18
- font-weight: 600;
19
- margin-bottom: 0.5rem;
20
- }
21
- }
22
-
23
- .#{$local-prefix}-table {
24
- border-collapse: collapse;
25
- width: 100%;
26
- &-container {
27
- border-radius: var(--style-radius-m);
28
- border: 1px solid var(--theme-border-color);
29
- }
30
- &-th {
31
- &-feature {
32
- padding: 0.5rem;
33
- text-align: left;
34
- border-right: 1px solid var(--theme-border-color);
35
- width: 25%;
36
- }
37
- &-action {
38
- padding: 0.5rem;
39
- }
40
- }
41
- &-td {
42
- &-feature {
43
- border-right: 1px solid var(--theme-border-color);
44
- border-top: 1px solid var(--theme-border-color);
45
- padding: 0.5rem;
46
- }
47
- &-action {
48
- border-top: 1px solid var(--theme-border-color);
49
- padding: 0.5rem;
50
- &-container {
51
- display: flex;
52
- align-items: center;
53
- }
54
- &-input {
55
- user-select: none;
56
- cursor: pointer;
57
- }
58
- &-label {
59
- display: inline-block;
60
- padding-left: 0.25rem;
61
- user-select: none;
62
- cursor: pointer;
63
- }
64
- }
65
- }
66
- }
@@ -1,16 +0,0 @@
1
- export type RolePermissionMatrixClientTranslations = {
2
- [locale: string]: {
3
- viewInUpdateScreenOnly?: {
4
- label?: string;
5
- placeholder?: string;
6
- };
7
- loading?: {
8
- placeholder?: string;
9
- };
10
- title?: string;
11
- featuresLabel?: string;
12
- features?: Record<string, string>;
13
- actionsLabel?: string;
14
- actions?: Record<string, string>;
15
- };
16
- };
@@ -1,5 +0,0 @@
1
- import type { PayloadHandler } from "payload"
2
-
3
- export const customEndpointHandler: PayloadHandler = () => {
4
- return Response.json({ message: "Hello from custom endpoint" })
5
- }
@@ -1 +0,0 @@
1
- export { RolePermissionMatrixClient } from "../components/role-permission-matrix-client/index.js"
File without changes