@griddo/ax 11.15.9 → 11.16.0-rc.1

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 (95) hide show
  1. package/package.json +2 -2
  2. package/src/__tests__/components/RestrictionsModal/CurrentAccessList/CurrentAccessList.test.tsx +173 -0
  3. package/src/__tests__/components/RestrictionsModal/OptionsStep/OptionsStep.test.tsx +160 -0
  4. package/src/__tests__/components/RestrictionsModal/RestrictionsModal.test.tsx +134 -0
  5. package/src/__tests__/components/RestrictionsModal/RolesList/RolesList.test.tsx +234 -0
  6. package/src/__tests__/components/RestrictionsModal/UsersList/UsersList.test.tsx +288 -0
  7. package/src/__tests__/hooks/users.test.tsx +382 -0
  8. package/src/api/pages.tsx +24 -1
  9. package/src/api/sites.tsx +14 -14
  10. package/src/api/structuredData.tsx +17 -7
  11. package/src/components/Browser/index.tsx +12 -0
  12. package/src/components/Browser/style.tsx +5 -1
  13. package/src/components/ConfigPanel/Form/index.tsx +11 -10
  14. package/src/components/ContentItem/index.tsx +31 -0
  15. package/src/components/ContentItem/style.tsx +43 -0
  16. package/src/components/Fields/ImageField/index.tsx +2 -1
  17. package/src/components/Fields/RadioField/index.tsx +3 -3
  18. package/src/components/Fields/RadioField/style.tsx +1 -1
  19. package/src/components/FloatingNote/index.tsx +12 -1
  20. package/src/components/FloatingNote/style.tsx +2 -1
  21. package/src/components/Modal/style.tsx +11 -0
  22. package/src/components/PageFinder/SelectionListItem/index.tsx +27 -17
  23. package/src/components/PageFinder/index.tsx +65 -28
  24. package/src/components/PageFinder/style.tsx +0 -1
  25. package/src/components/RestrictionsModal/CurrentAccessList/index.tsx +74 -0
  26. package/src/components/RestrictionsModal/CurrentAccessList/style.tsx +155 -0
  27. package/src/components/RestrictionsModal/OptionsStep/index.tsx +55 -0
  28. package/src/components/RestrictionsModal/OptionsStep/style.tsx +29 -0
  29. package/src/components/RestrictionsModal/RolesList/RoleItem/index.tsx +54 -0
  30. package/src/components/RestrictionsModal/RolesList/RoleItem/style.tsx +34 -0
  31. package/src/components/RestrictionsModal/RolesList/index.tsx +107 -0
  32. package/src/components/RestrictionsModal/RolesList/style.tsx +76 -0
  33. package/src/components/RestrictionsModal/UsersList/UserItem/index.tsx +78 -0
  34. package/src/components/RestrictionsModal/UsersList/UserItem/style.tsx +73 -0
  35. package/src/components/RestrictionsModal/UsersList/index.tsx +151 -0
  36. package/src/components/RestrictionsModal/UsersList/style.tsx +55 -0
  37. package/src/components/RestrictionsModal/index.tsx +181 -0
  38. package/src/components/RestrictionsModal/style.tsx +31 -0
  39. package/src/components/RestrictionsModal/utils.tsx +24 -0
  40. package/src/components/ScheduleModal/index.tsx +32 -8
  41. package/src/components/SelectionComponent/index.tsx +65 -0
  42. package/src/components/SelectionComponent/style.tsx +69 -0
  43. package/src/components/TableFilters/RoleFilter/index.tsx +3 -3
  44. package/src/components/TableList/TableItem/style.tsx +7 -13
  45. package/src/components/Tabs/index.tsx +2 -1
  46. package/src/components/UserRolesAndSites/index.tsx +2 -2
  47. package/src/components/index.tsx +6 -0
  48. package/src/containers/PageEditor/actions.tsx +43 -0
  49. package/src/containers/PageEditor/constants.tsx +1 -0
  50. package/src/containers/PageEditor/interfaces.tsx +26 -19
  51. package/src/containers/PageEditor/reducer.tsx +32 -19
  52. package/src/containers/Users/reducer.tsx +1 -0
  53. package/src/helpers/forms.tsx +3 -1
  54. package/src/hooks/index.tsx +2 -1
  55. package/src/hooks/users.tsx +154 -14
  56. package/src/modules/ActivityLog/LogFilters/UserFilter/index.tsx +11 -12
  57. package/src/modules/Content/PageItem/index.tsx +17 -10
  58. package/src/modules/Content/index.tsx +1 -3
  59. package/src/modules/GlobalEditor/Editor/index.tsx +6 -0
  60. package/src/modules/GlobalEditor/PageBrowser/index.tsx +6 -0
  61. package/src/modules/GlobalEditor/Preview/index.tsx +4 -2
  62. package/src/modules/GlobalEditor/index.tsx +72 -45
  63. package/src/modules/Navigation/Menus/List/Table/ConfigPanel/Form/index.tsx +3 -5
  64. package/src/modules/Navigation/Menus/List/Table/ConfigPanel/index.tsx +4 -4
  65. package/src/modules/Navigation/Menus/List/Table/SidePanel/Form/ConnectedField/index.tsx +2 -3
  66. package/src/modules/Navigation/Menus/List/Table/SidePanel/Form/index.tsx +3 -4
  67. package/src/modules/Navigation/Menus/List/Table/SidePanel/index.tsx +5 -6
  68. package/src/modules/PageEditor/Editor/index.tsx +6 -0
  69. package/src/modules/PageEditor/PageBrowser/index.tsx +6 -0
  70. package/src/modules/PageEditor/Preview/index.tsx +9 -2
  71. package/src/modules/PageEditor/atoms.tsx +110 -3
  72. package/src/modules/PageEditor/index.tsx +76 -95
  73. package/src/modules/Settings/Integrations/IntegrationForm/index.tsx +1 -3
  74. package/src/modules/Sites/SitesList/GridView/GridSiteItem/style.tsx +19 -2
  75. package/src/modules/Sites/SitesList/WelcomeModal/FinalStep/index.tsx +2 -2
  76. package/src/modules/Sites/SitesList/WelcomeModal/utils.ts +2 -2
  77. package/src/modules/StructuredData/Form/ConnectedField/index.tsx +2 -2
  78. package/src/modules/StructuredData/Form/index.tsx +120 -75
  79. package/src/modules/StructuredData/Form/style.tsx +7 -1
  80. package/src/modules/StructuredData/StructuredDataList/GlobalPageItem/index.tsx +15 -8
  81. package/src/modules/StructuredData/StructuredDataList/StructuredDataItem/index.tsx +15 -9
  82. package/src/modules/StructuredData/{StructuredDataList/StructuredDataItem/utils.tsx → utils.tsx} +16 -2
  83. package/src/modules/Users/Profile/atoms.tsx +62 -4
  84. package/src/modules/Users/Profile/index.tsx +83 -4
  85. package/src/modules/Users/Profile/style.tsx +60 -0
  86. package/src/modules/Users/UserCreate/SiteItem/RolesModal/RoleItem/index.tsx +3 -5
  87. package/src/modules/Users/UserCreate/SiteItem/index.tsx +2 -2
  88. package/src/modules/Users/UserCreate/atoms.tsx +69 -0
  89. package/src/modules/Users/UserCreate/index.tsx +149 -70
  90. package/src/modules/Users/UserCreate/style.tsx +24 -1
  91. package/src/modules/Users/UserForm/index.tsx +260 -146
  92. package/src/modules/Users/UserForm/style.tsx +13 -1
  93. package/src/modules/Users/UserList/UserItem/index.tsx +3 -3
  94. package/src/types/index.tsx +19 -6
  95. package/src/types/logs.tsx +1 -1
@@ -1,30 +1,32 @@
1
- import {
1
+ import type { IBreadcrumbItem, IErrorItem, IPage, ISchema, IUserEditing, PageAccessGrantsSummary } from "@ax/types";
2
+
3
+ import type {
4
+ RESET_PAGE_EDITOR_STORE,
2
5
  SET_BREADCRUMB,
3
- SET_SCHEMA,
4
- SET_TAB,
5
- SET_SELECTED_EDITOR_ID,
6
- SET_EDITOR_CONTENT,
7
- SET_TEMPLATE,
8
- SET_SELECTED_CONTENT,
9
- SET_SELECTED_PARENT,
6
+ SET_COPY_MODULE,
10
7
  SET_CURRENT_PAGE_ID,
11
- SET_CURRENT_PAGE_STATUS,
12
- SET_CURRENT_PAGE_NAME,
13
8
  SET_CURRENT_PAGE_LANGUAGES,
14
- SET_IS_NEW_TRANSLATION,
15
- SET_TEMPLATE_CONFIG,
9
+ SET_CURRENT_PAGE_NAME,
10
+ SET_CURRENT_PAGE_STATUS,
11
+ SET_EDITOR_CONTENT,
16
12
  SET_ERRORS,
17
- SET_VALIDATED,
18
- SET_SITE_PAGE_ID,
19
- SET_USER_EDITING,
20
- SET_LAST_ELEMENT_ADDED_ID,
21
- SET_COPY_MODULE,
22
13
  SET_IS_IA_TRANSLATED,
14
+ SET_IS_NEW_TRANSLATION,
15
+ SET_LAST_ELEMENT_ADDED_ID,
23
16
  SET_LAST_TIMEOUT,
24
- RESET_PAGE_EDITOR_STORE,
17
+ SET_PAGE_ACCESS_GRANTS,
18
+ SET_SCHEMA,
25
19
  SET_SCROLL_EDITOR_ID,
20
+ SET_SELECTED_CONTENT,
21
+ SET_SELECTED_EDITOR_ID,
22
+ SET_SELECTED_PARENT,
23
+ SET_SITE_PAGE_ID,
24
+ SET_TAB,
25
+ SET_TEMPLATE,
26
+ SET_TEMPLATE_CONFIG,
27
+ SET_USER_EDITING,
28
+ SET_VALIDATED,
26
29
  } from "./constants";
27
- import { IBreadcrumbItem, ISchema, IPage, IErrorItem, IUserEditing } from "@ax/types";
28
30
 
29
31
  export interface ISetEditorContent {
30
32
  type: typeof SET_EDITOR_CONTENT;
@@ -145,6 +147,11 @@ export interface ISetScrollEditorID {
145
147
  payload: { scrollEditorID: number | null };
146
148
  }
147
149
 
150
+ export interface ISetPageAccessGrants {
151
+ type: typeof SET_PAGE_ACCESS_GRANTS;
152
+ payload: { accessGrants: PageAccessGrantsSummary };
153
+ }
154
+
148
155
  export interface IFieldProps {
149
156
  id: number;
150
157
  key: string;
@@ -1,31 +1,41 @@
1
- import type { IPage, IBreadcrumbItem, ISchema, IErrorItem, IUserEditing, IModule, IPageLanguage } from "@ax/types";
1
+ import type {
2
+ IBreadcrumbItem,
3
+ IErrorItem,
4
+ IModule,
5
+ IPage,
6
+ IPageLanguage,
7
+ ISchema,
8
+ IUserEditing,
9
+ PageAccessGrantsSummary,
10
+ } from "@ax/types";
2
11
 
3
12
  import {
4
- SET_EDITOR_CONTENT,
5
- SET_TEMPLATE,
13
+ INITIAL_TEMPLATE,
14
+ RESET_PAGE_EDITOR_STORE,
6
15
  SET_BREADCRUMB,
7
- SET_SCHEMA,
8
- SET_SELECTED_CONTENT,
9
- SET_TAB,
10
- SET_SELECTED_EDITOR_ID,
16
+ SET_COPY_MODULE,
11
17
  SET_CURRENT_PAGE_ID,
12
- SET_CURRENT_PAGE_STATUS,
13
- SET_CURRENT_PAGE_NAME,
14
18
  SET_CURRENT_PAGE_LANGUAGES,
15
- SET_IS_NEW_TRANSLATION,
16
- INITIAL_TEMPLATE,
17
- SET_TEMPLATE_CONFIG,
18
- SET_SELECTED_PARENT,
19
+ SET_CURRENT_PAGE_NAME,
20
+ SET_CURRENT_PAGE_STATUS,
21
+ SET_EDITOR_CONTENT,
19
22
  SET_ERRORS,
20
- SET_VALIDATED,
21
- SET_SITE_PAGE_ID,
22
- SET_USER_EDITING,
23
- SET_LAST_ELEMENT_ADDED_ID,
24
- SET_COPY_MODULE,
25
23
  SET_IS_IA_TRANSLATED,
24
+ SET_IS_NEW_TRANSLATION,
25
+ SET_LAST_ELEMENT_ADDED_ID,
26
26
  SET_LAST_TIMEOUT,
27
- RESET_PAGE_EDITOR_STORE,
27
+ SET_PAGE_ACCESS_GRANTS,
28
+ SET_SCHEMA,
28
29
  SET_SCROLL_EDITOR_ID,
30
+ SET_SELECTED_CONTENT,
31
+ SET_SELECTED_EDITOR_ID,
32
+ SET_SELECTED_PARENT,
33
+ SET_SITE_PAGE_ID,
34
+ SET_TAB,
35
+ SET_TEMPLATE,
36
+ SET_TEMPLATE_CONFIG,
37
+ SET_USER_EDITING,
38
+ SET_VALIDATED,
29
39
  } from "./constants";
30
40
 
31
41
  export interface IPageEditorState {
@@ -52,6 +62,7 @@ export interface IPageEditorState {
52
62
  isIATranslated: boolean;
53
63
  lastTimeout: NodeJS.Timeout | null;
54
64
  scrollEditorID: number | null;
65
+ accessGrants: PageAccessGrantsSummary;
55
66
  }
56
67
 
57
68
  export const initialState = {
@@ -78,6 +89,7 @@ export const initialState = {
78
89
  isIATranslated: false,
79
90
  lastTimeout: null,
80
91
  scrollEditorID: null,
92
+ accessGrants: { users: [], roles: [] },
81
93
  };
82
94
 
83
95
  export function reducer(state = initialState, action: any): IPageEditorState {
@@ -106,6 +118,7 @@ export function reducer(state = initialState, action: any): IPageEditorState {
106
118
  case SET_IS_IA_TRANSLATED:
107
119
  case SET_LAST_TIMEOUT:
108
120
  case SET_SCROLL_EDITOR_ID:
121
+ case SET_PAGE_ACCESS_GRANTS:
109
122
  return { ...state, ...action.payload };
110
123
  case RESET_PAGE_EDITOR_STORE:
111
124
  return { ...initialState, moduleCopy: state.moduleCopy };
@@ -28,6 +28,7 @@ export const initialState = {
28
28
  failed: 0,
29
29
  roles: [],
30
30
  isSuperAdmin: false,
31
+ pagePermissions: [],
31
32
  },
32
33
  currentUser: null,
33
34
  currentPermissions: [],
@@ -15,4 +15,6 @@ const protectFormKeys = (content: any, key: string, editorID: number) => {
15
15
  return formComponent;
16
16
  };
17
17
 
18
- export { protectFormKeys };
18
+ const isValidEmail = (email: string) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
19
+
20
+ export { protectFormKeys, isValidEmail };
@@ -13,7 +13,7 @@ import { useURLSearchParam } from "./location";
13
13
  import { useHandleClickOutside, useModal, useModals, useToast } from "./modals";
14
14
  import { useNetworkStatus } from "./network";
15
15
  import { useResizable } from "./resize";
16
- import { useGlobalPermission, usePermission, usePermissions, usePermissionsForSite } from "./users";
16
+ import { useGlobalPermission, usePermission, usePermissions, usePermissionsForPage, usePermissionsForSite } from "./users";
17
17
  import { useFirefoxScrollLock, useWindowSize } from "./window";
18
18
 
19
19
  export {
@@ -35,6 +35,7 @@ export {
35
35
  useOnMessageReceivedFromOutside,
36
36
  usePermission,
37
37
  usePermissions,
38
+ usePermissionsForPage,
38
39
  usePermissionsForSite,
39
40
  usePrevious,
40
41
  useResizable,
@@ -1,12 +1,19 @@
1
1
  import { useMemo } from "react";
2
2
  import { useSelector } from "react-redux";
3
3
 
4
- import type { IRootState } from "@ax/types";
4
+ import type { IDataLanguage, IPageLanguage, IRootState, PageAccessGrantsSummary } from "@ax/types";
5
+
6
+ const useUserState = () =>
7
+ useSelector((state: IRootState) => ({
8
+ currentUser: state.users.currentUser,
9
+ userPermissions: state.users.currentPermissions,
10
+ globalPermissions: state.users.globalPermissions,
11
+ roles: state.users.roles,
12
+ isSuperAdmin: state.users.currentUser?.isSuperAdmin,
13
+ }));
5
14
 
6
15
  const usePermission = (permission: string | string[] | undefined): boolean => {
7
- const currentUser = useSelector((state: IRootState) => state.users.currentUser);
8
- const userPermissions = useSelector((state: IRootState) => state.users.currentPermissions);
9
- const isSuperAdmin = useSelector((state: IRootState) => state.users.currentUser?.isSuperAdmin);
16
+ const { currentUser, userPermissions, isSuperAdmin } = useUserState();
10
17
 
11
18
  const isAllowedTo = (permissions: string[]) =>
12
19
  userPermissions && permissions.some((permission: string) => userPermissions.includes(permission));
@@ -29,9 +36,7 @@ const usePermission = (permission: string | string[] | undefined): boolean => {
29
36
  };
30
37
 
31
38
  const usePermissions = <T extends Record<string, string | string[]>>(permissions: T): Record<keyof T, boolean> => {
32
- const currentUser = useSelector((state: IRootState) => state.users.currentUser);
33
- const userPermissions = useSelector((state: IRootState) => state.users.currentPermissions);
34
- const isSuperAdmin = useSelector((state: IRootState) => state.users.currentUser?.isSuperAdmin);
39
+ const { currentUser, userPermissions, isSuperAdmin } = useUserState();
35
40
 
36
41
  return useMemo(() => {
37
42
  if (!currentUser) {
@@ -59,9 +64,7 @@ const usePermissions = <T extends Record<string, string | string[]>>(permissions
59
64
  };
60
65
 
61
66
  const useGlobalPermission = (permission: string | string[] | undefined): boolean => {
62
- const currentUser = useSelector((state: IRootState) => state.users.currentUser);
63
- const userPermissions = useSelector((state: IRootState) => state.users.globalPermissions);
64
- const isSuperAdmin = useSelector((state: IRootState) => state.users.currentUser?.isSuperAdmin);
67
+ const { currentUser, globalPermissions: userPermissions, isSuperAdmin } = useUserState();
65
68
 
66
69
  const isAllowedTo = (permissions: string[]) =>
67
70
  userPermissions && permissions.some((permission: string) => userPermissions.includes(permission));
@@ -87,9 +90,7 @@ const usePermissionsForSite = <T extends Record<string, string | string[]>>(
87
90
  siteId: number | string,
88
91
  permissions: T,
89
92
  ): Record<keyof T, boolean> => {
90
- const currentUser = useSelector((state: IRootState) => state.users.currentUser);
91
- const roles = useSelector((state: IRootState) => state.users.roles);
92
- const isSuperAdmin = useSelector((state: IRootState) => state.users.currentUser?.isSuperAdmin);
93
+ const { currentUser, roles, isSuperAdmin } = useUserState();
93
94
 
94
95
  return useMemo(() => {
95
96
  if (!currentUser) {
@@ -145,4 +146,143 @@ const usePermissionsForSite = <T extends Record<string, string | string[]>>(
145
146
  }, [siteId, permissions, currentUser, roles, isSuperAdmin]);
146
147
  };
147
148
 
148
- export { usePermission, usePermissions, useGlobalPermission, usePermissionsForSite };
149
+ const usePermissionsForPage = <T extends Record<string, string | string[]>>(
150
+ siteId: number | string,
151
+ pageId: number,
152
+ permissions: T,
153
+ accessGrants?: PageAccessGrantsSummary | null,
154
+ pageLanguages?: (IDataLanguage | IPageLanguage)[],
155
+ ): Record<keyof T, boolean> => {
156
+ const { currentUser, roles, isSuperAdmin } = useUserState();
157
+
158
+ return useMemo(() => {
159
+ const createPermissionResult = (value: boolean): Record<keyof T, boolean> =>
160
+ Object.keys(permissions).reduce(
161
+ (acc, key) => {
162
+ acc[key as keyof T] = value;
163
+ return acc;
164
+ },
165
+ {} as Record<keyof T, boolean>,
166
+ );
167
+
168
+ if (!currentUser) {
169
+ return createPermissionResult(false);
170
+ }
171
+
172
+ if (isSuperAdmin) {
173
+ return createPermissionResult(true);
174
+ }
175
+
176
+ const userRoles = currentUser.roles.find(
177
+ (roleSite) => roleSite.siteId === siteId || roleSite.siteId === "all",
178
+ )?.roles;
179
+
180
+ // Check if pageId is part of a translation group in pageLanguages
181
+ // If yes, user can access it if they have access to ANY translation
182
+ const getLanguagePageId = (lang: IDataLanguage | IPageLanguage): number | undefined => {
183
+ if ("pageId" in lang) {
184
+ return lang.pageId;
185
+ }
186
+ if ("id" in lang) {
187
+ return lang.id;
188
+ }
189
+ return undefined;
190
+ };
191
+
192
+ const hasAccessToTranslationGroup = pageLanguages?.length
193
+ ? (() => {
194
+ const isPartOfGroup = pageLanguages.some((lang) => getLanguagePageId(lang) === pageId);
195
+ if (!isPartOfGroup) {
196
+ return false; // pageId is not in this translation group
197
+ }
198
+
199
+ // Get all pageIds in this translation group
200
+ const translationPageIds = pageLanguages
201
+ .map((lang) => getLanguagePageId(lang))
202
+ .filter((id): id is number => id !== undefined);
203
+
204
+ // Check if user has access to ANY of the translation pageIds
205
+ if (currentUser.pagePermissions?.length) {
206
+ const siteEntry = currentUser.pagePermissions.find(
207
+ (entry) => entry.siteId === siteId || entry.siteId === "global",
208
+ );
209
+ if (!siteEntry) {
210
+ return false;
211
+ }
212
+ return translationPageIds.some((translationPageId) => siteEntry.pageIds.includes(translationPageId));
213
+ }
214
+
215
+ return true; // No pagePermissions restrictions, allow access
216
+ })()
217
+ : undefined;
218
+
219
+ // If pageId is part of a translation group, use the translation group access result
220
+ const isPagePermissionRestricted =
221
+ hasAccessToTranslationGroup !== undefined
222
+ ? !hasAccessToTranslationGroup
223
+ : currentUser.pagePermissions?.length
224
+ ? (() => {
225
+ const siteEntry = currentUser.pagePermissions.find(
226
+ (entry) => entry.siteId === siteId || entry.siteId === "global",
227
+ );
228
+ // Page is restricted if site is not in pagePermissions or page is not in the site's pageIds
229
+ if (!siteEntry) {
230
+ return true;
231
+ }
232
+ return !siteEntry.pageIds.includes(pageId);
233
+ })()
234
+ : false;
235
+
236
+ // User is restricted by pagePermissions and page is not in their list
237
+ // But they can still access if in accessGrants
238
+ if (isPagePermissionRestricted) {
239
+ const pageHasAccessGrants = accessGrants?.users?.length || accessGrants?.roles?.length;
240
+
241
+ if (pageHasAccessGrants) {
242
+ const hasAccessGrantsAccess =
243
+ accessGrants.users?.includes(currentUser.id || -1) ||
244
+ userRoles?.some((roleId) => accessGrants.roles?.includes(roleId));
245
+
246
+ if (!hasAccessGrantsAccess) {
247
+ return createPermissionResult(false);
248
+ }
249
+ } else {
250
+ return createPermissionResult(false);
251
+ }
252
+ }
253
+
254
+ if (!userRoles?.length) {
255
+ return createPermissionResult(false);
256
+ }
257
+
258
+ const roleMap = new Map(roles?.map((r) => [r.id, r]) || []);
259
+ const sitePermissionsSet = new Set<string>();
260
+
261
+ userRoles.forEach((roleID: number) => {
262
+ const role = roleMap.get(roleID);
263
+ if (role) {
264
+ const permissions = siteId === "global" ? role.permissions.globalPermissions : role.permissions.sitePermissions;
265
+ permissions.forEach((perm) => {
266
+ sitePermissionsSet.add(perm.key);
267
+ });
268
+ }
269
+ });
270
+
271
+ const result: Record<string, boolean> = {};
272
+ for (const key of Object.keys(permissions)) {
273
+ const permission = permissions[key as keyof T];
274
+ const arrayPermission = Array.isArray(permission) ? permission : [permission];
275
+ result[key] = arrayPermission.some((perm: string) => sitePermissionsSet.has(perm));
276
+ }
277
+ return result as Record<keyof T, boolean>;
278
+ }, [siteId, pageId, permissions, accessGrants, currentUser, roles, isSuperAdmin, pageLanguages]);
279
+ };
280
+
281
+ export {
282
+ useUserState,
283
+ usePermission,
284
+ usePermissions,
285
+ useGlobalPermission,
286
+ usePermissionsForSite,
287
+ usePermissionsForPage,
288
+ };
@@ -1,9 +1,9 @@
1
- import React, { useEffect, useState } from "react";
1
+ import { useEffect, useState } from "react";
2
2
 
3
+ import { users } from "@ax/api";
3
4
  import { CheckGroupFilter } from "@ax/components";
4
5
  import { isReqOk } from "@ax/helpers";
5
- import { users } from "@ax/api";
6
- import { IQueryValue, IUser } from "@ax/types";
6
+ import type { IQueryValue, IUser } from "@ax/types";
7
7
 
8
8
  const UserFilter = (props: IUserFilterProps): JSX.Element => {
9
9
  const { filterItems, value } = props;
@@ -39,15 +39,14 @@ const UserFilter = (props: IUserFilterProps): JSX.Element => {
39
39
  useEffect(() => {
40
40
  getUsers()
41
41
  .then((items: IUser[]) => {
42
- items &&
43
- items.forEach((item) => {
44
- const newFilter = {
45
- name: item.id?.toString() || "",
46
- value: item.id?.toString() || "",
47
- title: item.name,
48
- };
49
- filters.push(newFilter);
50
- });
42
+ items?.forEach((item) => {
43
+ const newFilter = {
44
+ name: item.id?.toString() || "",
45
+ value: item.id?.toString() || "",
46
+ title: item.name,
47
+ };
48
+ filters.push(newFilter);
49
+ });
51
50
 
52
51
  setOptions(filters);
53
52
  })
@@ -12,7 +12,7 @@ import {
12
12
  getTemplateDisplayName,
13
13
  slugify,
14
14
  } from "@ax/helpers";
15
- import { useModals, usePermissions } from "@ax/hooks";
15
+ import { useModals, usePermissionsForPage } from "@ax/hooks";
16
16
  import type {
17
17
  ICheck,
18
18
  IColumn,
@@ -85,6 +85,7 @@ const PageItem = (props: IPageItemProps): JSX.Element => {
85
85
  publicationScheduled,
86
86
  haveDraftPage,
87
87
  title,
88
+ accessGrants,
88
89
  } = page;
89
90
 
90
91
  const displayName = getTemplateDisplayName(templateId);
@@ -95,15 +96,21 @@ const PageItem = (props: IPageItemProps): JSX.Element => {
95
96
  const [deleteAllVersions, setDeleteAllVersions] = useState(false);
96
97
  const { toggleModal, isOpen } = useModals(["duplicate", "remove", "unpublish", "delete", "copy"]);
97
98
 
98
- const isAllowedTo = usePermissions({
99
- duplicatePages: "content.duplicatePages",
100
- publishUnpublishPages: "content.publishUnpublishPages",
101
- createPages: "content.createPages",
102
- copyPageInOtherSite: "content.copyPageInOtherSite",
103
- deletePages: "content.deletePages",
104
- deletePublishedPages: "content.deletePublishedPages",
105
- editContentPages: "content.editContentPages",
106
- });
99
+ const isAllowedTo = usePermissionsForPage(
100
+ page.site!,
101
+ page.id,
102
+ {
103
+ duplicatePages: "content.duplicatePages",
104
+ publishUnpublishPages: "content.publishUnpublishPages",
105
+ createPages: "content.createPages",
106
+ copyPageInOtherSite: "content.copyPageInOtherSite",
107
+ deletePages: "content.deletePages",
108
+ deletePublishedPages: "content.deletePublishedPages",
109
+ editContentPages: "content.editContentPages",
110
+ },
111
+ accessGrants,
112
+ pageLanguages,
113
+ );
107
114
 
108
115
  const currentTemplateDataPacks = schemas.templates[templateId].dataPacks;
109
116
 
@@ -47,7 +47,6 @@ import type {
47
47
  ISavePageParams,
48
48
  ISchemaField,
49
49
  ISite,
50
- ISiteRoles,
51
50
  IStructuredData,
52
51
  IStructuredDataContent,
53
52
  IUser,
@@ -176,8 +175,7 @@ const Content = (props: IProps): JSX.Element => {
176
175
  const currentSitePagesTemplatesIds = allSitePages?.map((page) => page.templateId);
177
176
  const currentSitesByLang = sitesByLang?.filter(
178
177
  (site: ISite) =>
179
- user?.isSuperAdmin ||
180
- user?.roles.find((siteRole: ISiteRoles) => siteRole.siteId === site.id || siteRole.siteId === "all"),
178
+ user?.isSuperAdmin || user?.roles.find((siteRole) => siteRole.siteId === site.id || siteRole.siteId === "all"),
181
179
  );
182
180
  const categoryColumns: ISchemaField[] = currentStructuredData?.schema
183
181
  ? currentStructuredData.schema.fields.filter((field: ISchemaField) => field.showList)
@@ -46,6 +46,8 @@ const Editor = (props: IProps) => {
46
46
  isKeywordsPreviewOpen,
47
47
  headingsFilter,
48
48
  keywordsFilter,
49
+ isRestrictedPage,
50
+ onRestrictionsClick,
49
51
  } = props;
50
52
 
51
53
  const actions = {
@@ -77,6 +79,8 @@ const Editor = (props: IProps) => {
77
79
  toggleKeywordsPreview={toggleKeywordsPreview}
78
80
  isKeywordsPreviewOpen={isKeywordsPreviewOpen}
79
81
  keywordsFilter={keywordsFilter}
82
+ isRestrictedPage={isRestrictedPage}
83
+ onRestrictionsClick={onRestrictionsClick}
80
84
  />
81
85
  }
82
86
  rightPanel={
@@ -141,6 +145,8 @@ interface IPageBrowserDispatchProps {
141
145
  isKeywordsPreviewOpen: boolean;
142
146
  headingsFilter: HeadingFilter;
143
147
  keywordsFilter: string[];
148
+ isRestrictedPage?: boolean;
149
+ onRestrictionsClick?(): void;
144
150
  }
145
151
 
146
152
  type IProps = IEditorStateProps & IPageBrowserDispatchProps;
@@ -24,6 +24,8 @@ const PageBrowser = (props: IProps) => {
24
24
  setScrollEditorID,
25
25
  toggleHeadingsPreview,
26
26
  toggleKeywordsPreview,
27
+ isRestrictedPage,
28
+ onRestrictionsClick,
27
29
  } = props;
28
30
 
29
31
  const slugWithSlash = slug ? (slug.startsWith("/") ? slug : `/${slug}`) : "";
@@ -59,6 +61,8 @@ const PageBrowser = (props: IProps) => {
59
61
  headingFilter={headingsFilter}
60
62
  toggleKeywordsPreview={toggleKeywordsPreview}
61
63
  keywordsFilter={keywordsFilter}
64
+ isRestrictedPage={isRestrictedPage}
65
+ onRestrictionsClick={onRestrictionsClick}
62
66
  />
63
67
  );
64
68
  };
@@ -89,6 +93,8 @@ interface IPageBrowserDispatchProps {
89
93
  setScrollEditorID(editorID: number | null): void;
90
94
  toggleHeadingsPreview?(): void;
91
95
  toggleKeywordsPreview?(): void;
96
+ isRestrictedPage?: boolean;
97
+ onRestrictionsClick?(): void;
92
98
  }
93
99
 
94
100
  type IProps = IPageBrowserStateProps & IPageBrowserDispatchProps;
@@ -1,17 +1,19 @@
1
1
  import PageBrowser from "../PageBrowser";
2
+
2
3
  import * as S from "./style";
3
4
 
4
5
  const PreviewBrowser = (props: IProps) => {
5
- const { theme } = props;
6
+ const { theme, isRestrictedPage } = props;
6
7
  return (
7
8
  <S.BrowserWrapper>
8
- <PageBrowser isReadOnly={true} isPreview={true} theme={theme} />
9
+ <PageBrowser isReadOnly={true} isPreview={true} theme={theme} isRestrictedPage={isRestrictedPage} />
9
10
  </S.BrowserWrapper>
10
11
  );
11
12
  };
12
13
 
13
14
  interface IProps {
14
15
  theme: string;
16
+ isRestrictedPage: boolean;
15
17
  }
16
18
 
17
19
  export default PreviewBrowser;