@griddo/ax 10.1.96 → 10.2.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.
Files changed (201) hide show
  1. package/package.json +3 -2
  2. package/src/__mocks__/axios/Roles.ts +10 -0
  3. package/src/__mocks__/axios/UserList.ts +545 -0
  4. package/src/__mocks__/store/GenericStore.ts +25 -0
  5. package/src/__mocks__/store/Roles.ts +1050 -0
  6. package/src/__mocks__/store/SitesList.ts +7 -1
  7. package/src/__mocks__/store/UserList.ts +482 -0
  8. package/src/__mocks__/store/UsersCreate.ts +298 -0
  9. package/src/__tests__/components/Avatar/Avatar.test.tsx +49 -48
  10. package/src/__tests__/components/ConfigPanel/ConfigPanel.test.tsx +2 -0
  11. package/src/__tests__/components/ConfigPanel/Form/Form.test.tsx +2 -0
  12. package/src/__tests__/components/ConfigPanel/GlobalPageForm/GlobalPageForm.test.tsx +25 -0
  13. package/src/__tests__/components/Fields/Button/Button.test.tsx +2 -2
  14. package/src/__tests__/components/Fields/ImageField/ImageField.test.tsx +2 -0
  15. package/src/__tests__/components/Fields/IntegrationsField/IntegrationsField.test.tsx +44 -2
  16. package/src/__tests__/components/Fields/Tooltip/Tooltip.test.tsx +0 -1
  17. package/src/__tests__/components/Gallery/Gallery.test.tsx +4 -0
  18. package/src/__tests__/components/Gallery/GalleryPanel/DetailPanel/DetailPanel.test.tsx +14 -0
  19. package/src/__tests__/components/Gallery/GalleryPanel/GalleryPanel.test.tsx +2 -1
  20. package/src/__tests__/components/Lists/Lists.test.tsx +3 -3
  21. package/src/__tests__/components/Login/Login.test.tsx +1 -1
  22. package/src/__tests__/components/TableFilters/DateFilter/DateFilter.test.tsx +1 -1
  23. package/src/__tests__/components/TableFilters/NameFilter/NameFilter.test.tsx +1 -1
  24. package/src/__tests__/components/TableFilters/RoleFilter/RoleFilter.test.tsx +165 -0
  25. package/src/__tests__/components/TableFilters/StatusFilter/StatusFilter.test.tsx +2 -2
  26. package/src/__tests__/components/TableFilters/UsersFilter/UsersFilter.test.tsx +153 -0
  27. package/src/__tests__/components/Tabs/Tabs.test.tsx +1 -1
  28. package/src/__tests__/modules/Settings/Integrations/Integrations.test.tsx +6 -0
  29. package/src/__tests__/modules/Sites/Sites.test.tsx +2 -1
  30. package/src/__tests__/modules/Sites/SitesList/ListView/BulkHeader/BulkHeader.test.tsx +14 -5
  31. package/src/__tests__/modules/Sites/SitesList/SitesList.test.tsx +6 -4
  32. package/src/__tests__/modules/Users/Roles/BulkHeader/BulkHeader.test.tsx +158 -0
  33. package/src/__tests__/modules/Users/Roles/Roles.test.tsx +619 -0
  34. package/src/__tests__/modules/Users/UserCreate/SiteItem/RolesModal/RoleItem/RoleItem.test.tsx +107 -0
  35. package/src/__tests__/modules/Users/UserCreate/SiteItem/RolesModal/RolesModal.test.tsx +159 -0
  36. package/src/__tests__/modules/Users/UserCreate/SiteItem/SiteItem.test.tsx +175 -0
  37. package/src/__tests__/modules/Users/UserCreate/UserCreate.test.tsx +320 -0
  38. package/src/__tests__/modules/Users/UserList/UserItem/UserItem.test.tsx +417 -0
  39. package/src/__tests__/modules/Users/UserList/UserList.test.tsx +310 -0
  40. package/src/api/index.tsx +2 -0
  41. package/src/api/roles.tsx +77 -0
  42. package/src/api/users.tsx +22 -2
  43. package/src/components/ActionMenu/index.tsx +12 -6
  44. package/src/components/Avatar/index.tsx +5 -3
  45. package/src/components/Avatar/style.tsx +8 -9
  46. package/src/components/BulkSelectionOptions/index.tsx +19 -12
  47. package/src/components/BulkSelectionOptions/style.tsx +6 -11
  48. package/src/components/ConfigPanel/Form/index.tsx +24 -1
  49. package/src/components/ConfigPanel/GlobalPageForm/index.tsx +17 -4
  50. package/src/components/ElementsTooltip/index.tsx +1 -1
  51. package/src/components/Fields/IntegrationsField/index.tsx +5 -6
  52. package/src/components/Fields/RadioField/index.tsx +1 -1
  53. package/src/components/Fields/ReferenceField/AutoPanel/index.tsx +3 -3
  54. package/src/components/Fields/ReferenceField/ItemList/index.tsx +1 -1
  55. package/src/components/Fields/ReferenceField/ManualPanel/index.tsx +3 -3
  56. package/src/components/Fields/TagsField/index.tsx +4 -2
  57. package/src/components/Fields/TextField/index.tsx +3 -0
  58. package/src/components/Fields/UrlField/index.tsx +5 -5
  59. package/src/components/Gallery/GalleryPanel/DetailPanel/index.tsx +42 -15
  60. package/src/components/Gallery/GalleryPanel/GalleryDragAndDrop/index.tsx +1 -1
  61. package/src/components/Gallery/GalleryPanel/index.tsx +20 -5
  62. package/src/components/Gallery/index.tsx +12 -6
  63. package/src/components/Icon/index.tsx +9 -1
  64. package/src/components/MainWrapper/AppBar/atoms.tsx +2 -2
  65. package/src/components/MainWrapper/AppBar/index.tsx +12 -10
  66. package/src/components/MainWrapper/AppBar/style.tsx +2 -1
  67. package/src/components/Modal/style.tsx +2 -2
  68. package/src/components/Nav/index.tsx +12 -2
  69. package/src/components/PageFinder/index.tsx +2 -2
  70. package/src/components/SearchField/index.tsx +3 -8
  71. package/src/components/TableFilters/PermissionsFilter/index.tsx +50 -0
  72. package/src/{modules/Users/UserList/HeaderMenus/Name → components/TableFilters/PermissionsFilter}/style.tsx +6 -2
  73. package/src/components/TableFilters/RoleFilter/index.tsx +61 -0
  74. package/src/components/TableFilters/RoleFilter/style.tsx +28 -0
  75. package/src/components/TableFilters/UsersFilter/index.tsx +55 -0
  76. package/src/components/TableFilters/UsersFilter/style.tsx +31 -0
  77. package/src/components/TableFilters/index.tsx +6 -0
  78. package/src/components/TableList/TableItem/style.tsx +2 -2
  79. package/src/components/TableList/style.tsx +1 -1
  80. package/src/components/index.tsx +7 -1
  81. package/src/containers/App/actions.tsx +3 -3
  82. package/src/containers/PageEditor/actions.tsx +14 -20
  83. package/src/containers/Redirects/actions.tsx +1 -0
  84. package/src/containers/Sites/actions.tsx +22 -14
  85. package/src/containers/Sites/interfaces.tsx +3 -3
  86. package/src/containers/Sites/reducer.tsx +1 -1
  87. package/src/containers/StructuredData/actions.tsx +15 -3
  88. package/src/containers/Users/actions.tsx +160 -26
  89. package/src/containers/Users/constants.tsx +8 -10
  90. package/src/containers/Users/interfaces.tsx +25 -3
  91. package/src/containers/Users/reducer.tsx +24 -15
  92. package/src/guards/index.tsx +2 -1
  93. package/src/guards/restricted/index.tsx +21 -0
  94. package/src/hooks/index.tsx +3 -0
  95. package/src/hooks/users.tsx +38 -0
  96. package/src/modules/App/Routing/NavMenu/NavItem/index.tsx +10 -5
  97. package/src/modules/App/Routing/NavMenu/index.tsx +16 -7
  98. package/src/modules/App/Routing/PrivateRoute/index.tsx +13 -5
  99. package/src/modules/App/Routing/index.tsx +17 -6
  100. package/src/modules/Categories/CategoriesList/BulkHeader/TableHeader/style.tsx +1 -0
  101. package/src/modules/Categories/CategoriesList/BulkHeader/index.tsx +2 -10
  102. package/src/modules/Categories/CategoriesList/CategoryItem/index.tsx +27 -12
  103. package/src/modules/Categories/CategoriesList/CategoryItem/style.tsx +4 -2
  104. package/src/modules/Categories/CategoriesList/index.tsx +27 -8
  105. package/src/modules/Content/BulkHeader/index.tsx +7 -3
  106. package/src/modules/Content/PageImporter/index.tsx +1 -1
  107. package/src/modules/Content/PageItem/index.tsx +45 -31
  108. package/src/modules/Content/PageItem/style.tsx +2 -1
  109. package/src/modules/Content/index.tsx +22 -13
  110. package/src/modules/FramePreview/index.tsx +2 -2
  111. package/src/modules/GlobalEditor/index.tsx +68 -53
  112. package/src/modules/GlobalSettings/index.tsx +2 -0
  113. package/src/modules/Navigation/Defaults/BulkHeader/index.tsx +2 -10
  114. package/src/modules/Navigation/Defaults/DefaultsEditor/Editor/DefaultsBrowser/index.tsx +9 -11
  115. package/src/modules/Navigation/Defaults/DefaultsEditor/Editor/index.tsx +5 -1
  116. package/src/modules/Navigation/Defaults/DefaultsEditor/index.tsx +10 -5
  117. package/src/modules/Navigation/Defaults/Item/index.tsx +41 -27
  118. package/src/modules/Navigation/Defaults/Item/style.tsx +2 -1
  119. package/src/modules/Navigation/Defaults/index.tsx +29 -10
  120. package/src/modules/Navigation/Menus/List/Table/Header/index.tsx +7 -5
  121. package/src/modules/Navigation/Menus/List/Table/Item/index.tsx +10 -10
  122. package/src/modules/Navigation/Menus/List/Table/Item/style.tsx +2 -1
  123. package/src/modules/Navigation/Menus/List/index.tsx +6 -2
  124. package/src/modules/Navigation/Menus/index.tsx +12 -7
  125. package/src/modules/PageEditor/Editor/index.tsx +5 -1
  126. package/src/modules/PageEditor/PageBrowser/index.tsx +9 -3
  127. package/src/modules/PageEditor/index.tsx +67 -57
  128. package/src/modules/Redirects/index.tsx +97 -98
  129. package/src/modules/Settings/ContentTypes/DataPacks/AddModal/index.tsx +5 -1
  130. package/src/modules/Settings/ContentTypes/DataPacks/Config/Form/TemplateConfig/TemplateEditor/Editor/TemplateBrowser/index.tsx +8 -9
  131. package/src/modules/Settings/ContentTypes/DataPacks/Config/Form/index.tsx +7 -3
  132. package/src/modules/Settings/ContentTypes/DataPacks/Config/index.tsx +5 -1
  133. package/src/modules/Settings/ContentTypes/DataPacks/Item/index.tsx +5 -1
  134. package/src/modules/Settings/Integrations/BulkHeader/index.tsx +2 -17
  135. package/src/modules/Settings/Integrations/IntegrationForm/index.tsx +6 -2
  136. package/src/modules/Settings/Integrations/IntegrationItem/index.tsx +18 -8
  137. package/src/modules/Settings/Integrations/IntegrationItem/style.tsx +6 -3
  138. package/src/modules/Settings/Integrations/index.tsx +32 -7
  139. package/src/modules/Settings/Languages/LanguagePanel/index.tsx +6 -2
  140. package/src/modules/Settings/Languages/Table/Header/index.tsx +4 -2
  141. package/src/modules/Settings/Languages/Table/Item/index.tsx +19 -43
  142. package/src/modules/Settings/Languages/Table/Item/style.tsx +11 -54
  143. package/src/modules/Settings/Languages/index.tsx +2 -2
  144. package/src/modules/Settings/SeoAnalyticsSettings/Analytics/index.tsx +2 -4
  145. package/src/modules/Settings/SeoAnalyticsSettings/index.tsx +4 -2
  146. package/src/modules/Settings/Social/index.tsx +1 -1
  147. package/src/modules/Settings/index.tsx +17 -11
  148. package/src/modules/Sites/SitesList/GridView/GridSiteItem/index.tsx +31 -18
  149. package/src/modules/Sites/SitesList/ListView/BulkHeader/index.tsx +21 -12
  150. package/src/modules/Sites/SitesList/ListView/ListSiteItem/index.tsx +31 -18
  151. package/src/modules/Sites/SitesList/RecentSiteItem/index.tsx +1 -1
  152. package/src/modules/Sites/SitesList/index.tsx +16 -24
  153. package/src/modules/Sites/index.tsx +7 -3
  154. package/src/modules/StructuredData/Form/index.tsx +1 -1
  155. package/src/modules/StructuredData/StructuredDataList/BulkHeader/index.tsx +8 -5
  156. package/src/modules/StructuredData/StructuredDataList/ContentFilters/index.tsx +8 -5
  157. package/src/modules/StructuredData/StructuredDataList/GlobalPageItem/index.tsx +29 -15
  158. package/src/modules/StructuredData/StructuredDataList/StructuredDataItem/index.tsx +50 -19
  159. package/src/modules/StructuredData/StructuredDataList/index.tsx +9 -6
  160. package/src/modules/Users/Profile/index.tsx +16 -4
  161. package/src/modules/Users/Roles/BulkHeader/TableHeader/index.tsx +52 -0
  162. package/src/modules/Users/Roles/BulkHeader/TableHeader/style.tsx +43 -0
  163. package/src/modules/Users/Roles/BulkHeader/index.tsx +74 -0
  164. package/src/modules/Users/Roles/RoleItem/index.tsx +104 -0
  165. package/src/modules/Users/Roles/RoleItem/style.tsx +127 -0
  166. package/src/modules/Users/Roles/SideModal/index.tsx +81 -0
  167. package/src/modules/Users/Roles/SideModal/style.tsx +132 -0
  168. package/src/modules/Users/Roles/hooks.tsx +78 -0
  169. package/src/modules/Users/Roles/index.tsx +256 -0
  170. package/src/modules/Users/Roles/style.tsx +23 -0
  171. package/src/modules/Users/Roles/utils.tsx +12 -0
  172. package/src/modules/Users/UserCreate/OptionItem/index.tsx +45 -0
  173. package/src/modules/Users/UserCreate/OptionItem/style.tsx +48 -0
  174. package/src/modules/Users/UserCreate/SiteItem/RolesModal/RoleItem/index.tsx +48 -0
  175. package/src/modules/Users/UserCreate/SiteItem/RolesModal/RoleItem/style.tsx +42 -0
  176. package/src/modules/Users/UserCreate/SiteItem/RolesModal/index.tsx +140 -0
  177. package/src/modules/Users/UserCreate/SiteItem/RolesModal/style.tsx +94 -0
  178. package/src/modules/Users/UserCreate/SiteItem/index.tsx +103 -22
  179. package/src/modules/Users/UserCreate/SiteItem/style.tsx +49 -6
  180. package/src/modules/Users/UserCreate/index.tsx +278 -121
  181. package/src/modules/Users/UserCreate/style.tsx +71 -4
  182. package/src/modules/Users/UserEdit/index.tsx +71 -24
  183. package/src/modules/Users/UserForm/atoms.tsx +40 -8
  184. package/src/modules/Users/UserForm/index.tsx +335 -116
  185. package/src/modules/Users/UserForm/style.tsx +70 -6
  186. package/src/modules/Users/UserList/BulkHeader/TableHeader/index.tsx +61 -31
  187. package/src/modules/Users/UserList/BulkHeader/TableHeader/style.tsx +18 -4
  188. package/src/modules/Users/UserList/BulkHeader/index.tsx +10 -3
  189. package/src/modules/Users/UserList/UserItem/index.tsx +121 -38
  190. package/src/modules/Users/UserList/UserItem/style.tsx +32 -14
  191. package/src/modules/Users/UserList/hooks.tsx +13 -8
  192. package/src/modules/Users/UserList/index.tsx +67 -29
  193. package/src/modules/Users/UserList/utils.tsx +1 -1
  194. package/src/modules/Users/index.tsx +20 -3
  195. package/src/routes/index.tsx +9 -17
  196. package/src/routes/multisite.tsx +73 -8
  197. package/src/routes/site.tsx +96 -10
  198. package/src/types/index.tsx +42 -1
  199. package/tsconfig.paths.json +1 -0
  200. package/src/__tests__/components/Avatar/__snapshots__/Avatar.test.tsx.snap +0 -61
  201. package/src/modules/Users/UserList/HeaderMenus/Name/index.tsx +0 -55
@@ -2,15 +2,16 @@ import React, { useEffect, useState, useRef } from "react";
2
2
  import { connect } from "react-redux";
3
3
  import { RouteComponentProps } from "react-router-dom";
4
4
 
5
- import { IErrorItem, INotification, IRootState, ISavePageParams, IUserEditing } from "@ax/types";
5
+ import { IErrorItem, INotification, IRootState, ISavePageParams, ISite, IUserEditing } from "@ax/types";
6
6
  import { MainWrapper, Loading, ErrorToast, Notification, Modal } from "@ax/components";
7
7
  import { pageEditorActions } from "@ax/containers/PageEditor";
8
8
  import { structuredDataActions } from "@ax/containers/StructuredData";
9
+ import { usersActions } from "@ax/containers/Users";
9
10
  import { appActions } from "@ax/containers/App";
10
11
  import { sitesActions } from "@ax/containers/Sites";
11
12
  import { pageStatus } from "@ax/containers/PageEditor/interfaces";
12
13
  import { RouteLeavingGuard } from "@ax/guards";
13
- import { useIsDirty, useModal } from "@ax/hooks";
14
+ import { useIsDirty, useModal, usePermission } from "@ax/hooks";
14
15
  import { getDefaultTheme } from "@ax/helpers";
15
16
 
16
17
  import Editor from "./Editor";
@@ -42,12 +43,20 @@ const GlobalEditor = (props: IProps) => {
42
43
  userEditing,
43
44
  isNewTranslation,
44
45
  currentSiteErrorPages,
46
+ getUserCurrentPermissions,
45
47
  } = props;
46
48
 
49
+ const isAllowedToPublishPages = usePermission("global.globalData.publishUnpublishAllGlobalData");
50
+ const isAllowedToCreatePages = usePermission("global.globalData.createAllGlobalData");
51
+ const isAllowedToDeletePage = usePermission("global.globalData.deleteAllGlobalData");
52
+ const isAllowedToEditContentPage = usePermission("global.globalData.editAllGlobalData");
53
+
54
+ const defaultTab = isAllowedToEditContentPage ? "edit" : "view";
55
+
47
56
  const { isOpen, toggleModal } = useModal();
48
57
  const { isOpen: isUnpublishOpen, toggleModal: toggleUnpublishModal } = useModal();
49
58
  const [isReadOnly, setIsReadOnly] = useState(false);
50
- const [selectedTab, setSelectedTab] = useState("edit");
59
+ const [selectedTab, setSelectedTab] = useState(defaultTab);
51
60
  const [notification, setNotification] = useState<INotification | null>(null);
52
61
  const { isDirty, setIsDirty, resetDirty } = useIsDirty(editorContent, isNewTranslation);
53
62
  const [errorPagesChecked, setErrorPagesChecked] = useState(false);
@@ -67,8 +76,8 @@ const GlobalEditor = (props: IProps) => {
67
76
  const theme = getDefaultTheme();
68
77
 
69
78
  useEffect(() => {
70
- const { pageID, getPage, setTab, setCurrentSiteInfo, sendPagePing, setStructuredDataFilter } = props;
71
- setCurrentSiteInfo(null);
79
+ const { pageID, getPage, setTab, sendPagePing, setStructuredDataFilter } = props;
80
+
72
81
  editorContent && editorContent.structuredData && setStructuredDataFilter(editorContent.structuredData);
73
82
  const defaultTab = "content";
74
83
  const handleGetPage = async () => await getPage(pageID, true);
@@ -248,7 +257,7 @@ const GlobalEditor = (props: IProps) => {
248
257
  };
249
258
 
250
259
  const handleNewTranlation = (isNewTranslation: boolean) => {
251
- setSelectedTab("edit");
260
+ isAllowedToEditContentPage && setSelectedTab("edit");
252
261
  createNewTranslation && createNewTranslation(isNewTranslation);
253
262
  };
254
263
 
@@ -258,45 +267,44 @@ const GlobalEditor = (props: IProps) => {
258
267
  getContent: getPage,
259
268
  };
260
269
 
261
- const unpublishOption =
262
- props.pageStatus === pageStatus.PUBLISHED && !hasDraft && isDirty
263
- ? {
264
- label: "Unpublish",
265
- icon: "offline",
266
- action: isDraft ? toggleUnpublishModal : unpublishPage,
267
- }
268
- : undefined;
269
-
270
- const discardOption =
271
- isDraft || (isPublished && isDirty)
272
- ? {
273
- label: "Discard changes",
274
- icon: "close",
275
- action: isDraft ? handleDiscardDraft : handleDiscarChanges,
276
- }
277
- : undefined;
278
-
279
- const deleteOption = !isDraft
280
- ? {
281
- label: "Delete",
282
- icon: "delete",
283
- action: removePage,
284
- }
285
- : undefined;
270
+ const menuOptions = [];
271
+
272
+ if (isAllowedToEditContentPage) {
273
+ menuOptions.push({
274
+ label: "Review",
275
+ icon: "question",
276
+ action: reviewPage,
277
+ });
278
+ }
279
+
280
+ if (isAllowedToEditContentPage && (isDraft || (isPublished && isDirty))) {
281
+ menuOptions.push({
282
+ label: "Discard changes",
283
+ icon: "close",
284
+ action: isDraft ? handleDiscardDraft : handleDiscarChanges,
285
+ });
286
+ }
287
+
288
+ if (props.pageStatus === pageStatus.PUBLISHED && !hasDraft && isDirty && isAllowedToPublishPages) {
289
+ menuOptions.push({
290
+ label: "Unpublish",
291
+ icon: "offline",
292
+ action: isDraft ? toggleUnpublishModal : unpublishPage,
293
+ });
294
+ }
295
+
296
+ if (!isDraft && isAllowedToDeletePage) {
297
+ menuOptions.push({
298
+ label: "Delete",
299
+ icon: "delete",
300
+ action: removePage,
301
+ });
302
+ }
286
303
 
287
304
  const downArrowMenu = {
288
305
  displayed: !isReadOnly,
289
- button: getPublishButton(props.pageStatus),
290
- options: [
291
- {
292
- label: "Review",
293
- icon: "question",
294
- action: reviewPage,
295
- },
296
- unpublishOption,
297
- discardOption,
298
- deleteOption,
299
- ],
306
+ button: isAllowedToPublishPages ? getPublishButton(props.pageStatus) : undefined,
307
+ options: menuOptions,
300
308
  };
301
309
 
302
310
  const isEditable = editorContent && editorContent.editable;
@@ -338,11 +346,11 @@ const GlobalEditor = (props: IProps) => {
338
346
  }
339
347
  };
340
348
 
341
- const rightButtonProps = {
349
+ const rightButtonProps = isAllowedToEditContentPage ? {
342
350
  label: isSaving ? "Saving" : getSaveLabel(),
343
351
  disabled: (!isDirty && pageID !== null && !isNewTranslation) || isSaving || isReadOnly,
344
352
  action: isPublished ? publishChanges : handleSavePage,
345
- };
353
+ } : undefined;
346
354
 
347
355
  const goToLivePage = () => {
348
356
  const currentPageUrl = editorContent.fullUrl;
@@ -381,10 +389,11 @@ const GlobalEditor = (props: IProps) => {
381
389
  ]
382
390
  : pageStatusActions;
383
391
 
384
- const handleClickNotification = () => {
392
+ const goBackToSite = () => {
385
393
  if (sitePageID) {
386
394
  setCurrentSiteInfo(savedSiteInfo);
387
395
  setCurrentPageID(sitePageID);
396
+ getUserCurrentPermissions();
388
397
  const path = "/sites/pages/editor";
389
398
  setHistoryPush(path, true);
390
399
  }
@@ -406,11 +415,15 @@ const GlobalEditor = (props: IProps) => {
406
415
 
407
416
  const mainUnpublishAction = { title: "Ok", onClick: toggleUnpublishModal };
408
417
 
418
+ const tabIcons = isAllowedToEditContentPage
419
+ ? [
420
+ { name: "edit", text: "Edit mode" },
421
+ { name: "view", text: "Preview mode" },
422
+ ]
423
+ : [{ name: "view", text: "Preview mode" }];
424
+
409
425
  const tabsPreview = {
410
- icons: [
411
- { name: "edit", text: "Edit mode" },
412
- { name: "view", text: "Preview mode" },
413
- ],
426
+ icons: tabIcons,
414
427
  selectedTab,
415
428
  action: (tab: string) => setSelectedTab(tab),
416
429
  };
@@ -430,7 +443,7 @@ const GlobalEditor = (props: IProps) => {
430
443
  pageStatus={props.pageStatus}
431
444
  language={lang}
432
445
  languageActions={languageActions}
433
- availableLanguages={globalLangs}
446
+ availableLanguages={isAllowedToCreatePages ? globalLangs : pageLanguages}
434
447
  pageLanguages={pageLanguages}
435
448
  currentPageID={pageID}
436
449
  fullWidth={true}
@@ -454,7 +467,7 @@ const GlobalEditor = (props: IProps) => {
454
467
  type="info"
455
468
  text={globalNotificationText}
456
469
  btnText="Go Back"
457
- onClick={handleClickNotification}
470
+ onClick={goBackToSite}
458
471
  />
459
472
  </S.NotificationWrapper>
460
473
  )}
@@ -538,7 +551,7 @@ const mapStateToProps = (state: IRootState): IPageEditorStateProps => ({
538
551
  sitePageID: state.pageEditor.sitePageID,
539
552
  savedSiteInfo: state.sites.savedSiteInfo,
540
553
  userEditing: state.pageEditor.userEditing,
541
- currentUserID: state.users.currentUser.id,
554
+ currentUserID: state.users.currentUser && state.users.currentUser.id,
542
555
  isNewTranslation: state.pageEditor.isNewTranslation,
543
556
  currentSiteErrorPages: state.sites.currentSiteErrorPages,
544
557
  skipReviewOnPublish: state.app.globalSettings.skipReviewOnPublish,
@@ -580,6 +593,7 @@ const mapDispatchToProps = {
580
593
  sendPagePing: pageEditorActions.sendPagePing,
581
594
  setStructuredDataFilter: structuredDataActions.setFilter,
582
595
  discardDraft: pageEditorActions.discardDraft,
596
+ getUserCurrentPermissions: usersActions.getUserCurrentPermissions,
583
597
  };
584
598
 
585
599
  interface IPageEditorDispatchProps {
@@ -593,11 +607,12 @@ interface IPageEditorDispatchProps {
593
607
  createNewTranslation?(isNewTranslation: boolean): void;
594
608
  setTab(tab: string): void;
595
609
  setSelectedContent(editorID: number): void;
596
- setCurrentSiteInfo(currentSiteInfo: any): void;
610
+ setCurrentSiteInfo(currentSiteInfo: ISite | null): void;
597
611
  setCurrentPageID(currentPageID: number): void;
598
612
  sendPagePing(pageID: number): Promise<boolean>;
599
613
  setStructuredDataFilter(filter: string | null): void;
600
614
  discardDraft(): Promise<void>;
615
+ getUserCurrentPermissions(): void;
601
616
  }
602
617
 
603
618
  type IProps = IPageEditorStateProps & IPageEditorDispatchProps & RouteComponentProps;
@@ -9,11 +9,13 @@ const navItems = [
9
9
  title: "Robots.txt Editor",
10
10
  path: "/settings/robots",
11
11
  component: Robots,
12
+ permission: "global.seoAnalytics.editSeoAnalyticsInGlobalPages",
12
13
  },
13
14
  {
14
15
  title: "URL Redirect Manager",
15
16
  path: "/settings/redirects",
16
17
  component: Redirects,
18
+ permission: "global.seoAnalytics.editSeoAnalyticsInGlobalPages",
17
19
  },
18
20
  ];
19
21
 
@@ -3,15 +3,7 @@ import { BulkSelectionOptions } from "@ax/components";
3
3
  import TableHeader from "./TableHeader";
4
4
 
5
5
  const BulkHeader = (props: IProps): JSX.Element => {
6
- const { showBulk, checkState, bulkDelete, selectItems, selectAllItems, totalItems, isScrolling } = props;
7
-
8
- const bulkActions = [
9
- {
10
- icon: "delete",
11
- text: "delete",
12
- action: bulkDelete,
13
- },
14
- ];
6
+ const { showBulk, checkState, bulkActions, selectItems, selectAllItems, totalItems, isScrolling } = props;
15
7
 
16
8
  return showBulk ? (
17
9
  <BulkSelectionOptions
@@ -28,7 +20,7 @@ const BulkHeader = (props: IProps): JSX.Element => {
28
20
  interface IProps {
29
21
  showBulk: boolean;
30
22
  checkState: any;
31
- bulkDelete: () => void;
23
+ bulkActions: { icon: string; text: string; action: () => void }[];
32
24
  selectItems: () => void;
33
25
  selectAllItems: () => void;
34
26
  totalItems: number;
@@ -3,18 +3,16 @@ import { connect } from "react-redux";
3
3
  import { navigationActions } from "@ax/containers/Navigation/Defaults";
4
4
 
5
5
  import { Browser } from "@ax/components";
6
- import { ILanguage, IRootState, ISocialState } from "@ax/types";
6
+ import { ILanguage, IRootState, ISite, ISocialState } from "@ax/types";
7
7
 
8
8
  const DefaultsBrowser = (props: IProps) => {
9
- const {
10
- socials,
11
- cloudinaryName,
12
- content,
13
- currentSiteInfo: { theme, id: siteID },
14
- siteLangs,
15
- browserRef,
16
- actions,
17
- } = props;
9
+ const { socials, cloudinaryName, content, currentSiteInfo, siteLangs, browserRef, actions } = props;
10
+
11
+ if (!currentSiteInfo) {
12
+ throw new Error(`ERROR: User reached Page Editor with null site info`);
13
+ }
14
+
15
+ const { theme, id: siteID } = currentSiteInfo;
18
16
 
19
17
  const updatedContent = { ...content };
20
18
 
@@ -42,7 +40,7 @@ interface IDefaultsBrowserProps {
42
40
  interface IDefaultsBrowserStateProps {
43
41
  // TODO: Define content Type
44
42
  content: any;
45
- currentSiteInfo: any;
43
+ currentSiteInfo: ISite | null;
46
44
  socials: ISocialState;
47
45
  cloudinaryName: string | null;
48
46
  siteLangs: ILanguage[];
@@ -30,6 +30,10 @@ const Editor = (props: IProps) => {
30
30
  browserRef,
31
31
  } = props;
32
32
 
33
+ if (!site) {
34
+ throw new Error(`ERROR: User reached Editor with null site info`);
35
+ }
36
+
33
37
  const actions = {
34
38
  deleteModuleAction: deleteModule,
35
39
  addComponentAction: addComponent,
@@ -75,7 +79,7 @@ interface IEditorStateProps {
75
79
  activatedModules: string[];
76
80
  selectedTab: string;
77
81
  isLoading: boolean;
78
- site: ISite;
82
+ site: ISite | null;
79
83
  }
80
84
 
81
85
  interface IPageBrowserDispatchProps {
@@ -1,8 +1,8 @@
1
1
  import React, { useEffect, useRef, useState } from "react";
2
2
  import { connect } from "react-redux";
3
3
 
4
- import { INotification, IRootState } from "@ax/types";
5
- import { useIsDirty, useModal } from "@ax/hooks";
4
+ import { IRootState, ISite, INotification } from "@ax/types";
5
+ import { useIsDirty, useModal, usePermission } from "@ax/hooks";
6
6
  import { RouteLeavingGuard } from "@ax/guards";
7
7
 
8
8
  import { appActions } from "@ax/containers/App";
@@ -43,6 +43,9 @@ const DefaultsEditor = (props: IProps) => {
43
43
  const isSetAsDefault = editorContent && editorContent.setAsDefault;
44
44
  const browserRef = useRef<HTMLDivElement>(null);
45
45
 
46
+ const isAllowedToCreateHeaders = usePermission("navigation.createSiteHeaders") && selectedDefault === "Headers";
47
+ const isAllowedToCreateFooters = usePermission("navigation.createSiteFooters") && selectedDefault === "Footers";
48
+
46
49
  useEffect(() => {
47
50
  getValues();
48
51
  if (isNew) {
@@ -57,7 +60,7 @@ const DefaultsEditor = (props: IProps) => {
57
60
  }, [lang]);
58
61
 
59
62
  useEffect(() => {
60
- const navigationModuleComponent = currentSiteInfo.navigationModules?.[editorContent?.type];
63
+ const navigationModuleComponent = currentSiteInfo && currentSiteInfo.navigationModules?.[editorContent?.type];
61
64
  const currentNavigation = currentDefaultsContent?.find((item: any) => item.id === editorContent?.id);
62
65
  if (navigationModuleComponent && editorContent && currentNavigation) {
63
66
  const isNavigationModuleChanged = navigationModuleComponent !== currentNavigation.component;
@@ -123,6 +126,8 @@ const DefaultsEditor = (props: IProps) => {
123
126
  const secondaryModalAction = { title: "Cancel", onClick: toggleModal };
124
127
  const goBack = (path: string) => setHistoryPush(path, true);
125
128
 
129
+ const availableLanguages = isAllowedToCreateHeaders || isAllowedToCreateFooters ? siteLanguages : navLanguages;
130
+
126
131
  return isLoading ? (
127
132
  <Loading />
128
133
  ) : (
@@ -135,7 +140,7 @@ const DefaultsEditor = (props: IProps) => {
135
140
  fixedAppBar={true}
136
141
  language={lang}
137
142
  languageActions={languageActions}
138
- availableLanguages={siteLanguages}
143
+ availableLanguages={availableLanguages}
139
144
  pageLanguages={navLanguages}
140
145
  fullWidth={true}
141
146
  >
@@ -196,7 +201,7 @@ interface IStateProps {
196
201
  footer: number | null;
197
202
  navLanguages: any[];
198
203
  isNewTranslation: boolean;
199
- currentSiteInfo: any;
204
+ currentSiteInfo: ISite | null;
200
205
  }
201
206
 
202
207
  const mapDispatchToProps = {
@@ -2,7 +2,7 @@ import React, { useState } from "react";
2
2
  import { connect } from "react-redux";
3
3
 
4
4
  import { IHeader, IFooter, ICheck } from "@ax/types";
5
- import { useModal } from "@ax/hooks";
5
+ import { useModal, usePermission } from "@ax/hooks";
6
6
  import { appActions } from "@ax/containers/App";
7
7
  import { navigationActions } from "@ax/containers/Navigation";
8
8
  import { CheckField, FieldsBehavior, Modal } from "@ax/components";
@@ -40,14 +40,19 @@ const DefaultItem = (props: IProps): JSX.Element => {
40
40
  const { locale } = lang;
41
41
  const { navigationLanguages, type } = defaultContent;
42
42
 
43
+ const isAllowedToEditHeaders = usePermission("navigation.editSiteHeaders") && type === "header";
44
+ const isAllowedToEditFooters = usePermission("navigation.editSiteFooters") && type === "footer";
45
+ const isAllowedToCreateHeaders = usePermission("navigation.createSiteHeaders") && type === "header";
46
+ const isAllowedToCreateFooters = usePermission("navigation.createSiteFooters") && type === "footer";
47
+ const isAllowedToDeleteHeaders = usePermission("navigation.deleteSiteHeaders") && type === "header";
48
+ const isAllowedToDeleteFooters = usePermission("navigation.deleteSiteFooters") && type === "footer";
49
+
43
50
  const goToEditor = () => {
44
51
  handleClick(defaultContent);
45
52
  setHistoryPush("/sites/navigations/editor", true);
46
53
  };
47
54
 
48
- const handleOnChange = (value: ICheck) => {
49
- onChange(value);
50
- };
55
+ const handleOnChange = (value: ICheck) => onChange(value);
51
56
 
52
57
  const handleRenameItem = () => {
53
58
  const updatedItem = { ...defaultContent, title: inputValue };
@@ -66,27 +71,34 @@ const DefaultItem = (props: IProps): JSX.Element => {
66
71
  }
67
72
  };
68
73
 
69
- let menuOptions = [
70
- {
71
- label: "Rename",
72
- icon: "edit",
73
- action: toggleRenameModal,
74
- },
75
- {
76
- label: "Delete",
77
- icon: "delete",
78
- action: removeItem,
79
- },
80
- ];
81
-
82
- if (!defaultContent.setAsDefault) {
83
- const setAsDefaultOption = {
84
- label: "Set as default",
85
- icon: "modules",
86
- action: toggleDefaultModal,
87
- };
88
- menuOptions = [setAsDefaultOption, ...menuOptions];
89
- }
74
+ const renameOption =
75
+ isAllowedToEditFooters || isAllowedToEditHeaders
76
+ ? {
77
+ label: "Rename",
78
+ icon: "edit",
79
+ action: toggleRenameModal,
80
+ }
81
+ : undefined;
82
+
83
+ const deleteOption =
84
+ isAllowedToDeleteFooters || isAllowedToDeleteHeaders
85
+ ? {
86
+ label: "Delete",
87
+ icon: "delete",
88
+ action: removeItem,
89
+ }
90
+ : undefined;
91
+
92
+ const setAsDefaultOption =
93
+ !defaultContent.setAsDefault && (isAllowedToEditHeaders || isAllowedToEditFooters)
94
+ ? {
95
+ label: "Set as default",
96
+ icon: "modules",
97
+ action: toggleDefaultModal,
98
+ }
99
+ : undefined;
100
+
101
+ const menuOptions = [setAsDefaultOption, renameOption, deleteOption];
90
102
 
91
103
  const getCurrentLanguages = () => {
92
104
  const availables: any[] = [];
@@ -139,9 +151,11 @@ const DefaultItem = (props: IProps): JSX.Element => {
139
151
  setHistoryPush(path, true);
140
152
  };
141
153
 
154
+ const availableLanguages = isAllowedToCreateFooters || isAllowedToCreateHeaders ? languages : currentLanguages;
155
+
142
156
  return (
143
157
  <>
144
- <S.DefaultRow role="rowgroup" selected={isSelected}>
158
+ <S.DefaultRow role="rowgroup" selected={isSelected} clickable={isAllowedToEditHeaders || isAllowedToEditFooters}>
145
159
  <S.CheckCell role="cell">
146
160
  <CheckField name="check" value={defaultContent.id} checked={isSelected} onChange={handleOnChange} />
147
161
  </S.CheckCell>
@@ -153,7 +167,7 @@ const DefaultItem = (props: IProps): JSX.Element => {
153
167
  handleLanguage={handleLanguage}
154
168
  currentLanguages={currentLanguages}
155
169
  locale={locale}
156
- languages={languages}
170
+ languages={availableLanguages}
157
171
  />
158
172
  </S.TransCell>
159
173
  <S.DefaultCell role="cell" onClick={goToEditor}>
@@ -39,7 +39,8 @@ const StyledActionMenu = styled(ActionMenu)`
39
39
  margin-left: auto;
40
40
  `;
41
41
 
42
- const DefaultRow = styled(Row)`
42
+ const DefaultRow = styled(Row)<{ clickable: boolean }>`
43
+ pointer-events: ${(p) => (p.clickable ? "auto" : "none")};
43
44
  &:hover {
44
45
  ${StyledActionMenu} {
45
46
  opacity: 1;
@@ -3,8 +3,8 @@ import { connect } from "react-redux";
3
3
 
4
4
  import { appActions } from "@ax/containers/App";
5
5
  import { menuActions } from "@ax/containers/Navigation";
6
- import { IRootState, IHeader, IFooter } from "@ax/types";
7
- import { useBulkSelection, useModal, useToast } from "@ax/hooks";
6
+ import { IRootState, IHeader, IFooter, ISite } from "@ax/types";
7
+ import { useBulkSelection, usePermission, useToast, useModal } from "@ax/hooks";
8
8
  import { capitalize, isMultipleNavigationModules } from "@ax/helpers";
9
9
  import { navigationActions } from "@ax/containers/Navigation";
10
10
  import { MainWrapper, TableList, ErrorToast, Toast, Notification } from "@ax/components";
@@ -12,7 +12,6 @@ import { MainWrapper, TableList, ErrorToast, Toast, Notification } from "@ax/com
12
12
  import DefaultItem from "./Item";
13
13
  import DefaultNav from "./Nav";
14
14
  import BulkHeader from "./BulkHeader";
15
-
16
15
  import { NavigationModulesWarning } from "./atoms";
17
16
  import ReplaceNavModal from "./ReplaceNavModal";
18
17
 
@@ -49,6 +48,11 @@ const DefaultsList = (props: IProps): JSX.Element => {
49
48
  const [isNavigationNotificationOpen, setIsNavigationNotificationOpen] = useState(false);
50
49
  const { isOpen: isReplaceOpened, toggleModal: toggleReplaceModal } = useModal();
51
50
 
51
+ const isAllowedToCreateHeaders = usePermission("navigation.createSiteHeaders") && selectedDefault === "Headers";
52
+ const isAllowedToCreateFooters = usePermission("navigation.createSiteFooters") && selectedDefault === "Footers";
53
+ const isAllowedToDeleteHeaders = usePermission("navigation.deleteSiteHeaders") && selectedDefault === "Headers";
54
+ const isAllowedToDeleteFooters = usePermission("navigation.deleteSiteFooters") && selectedDefault === "Footers";
55
+
52
56
  const navIds = currentDefaultsContent && currentDefaultsContent.map((nav: any) => nav.id);
53
57
 
54
58
  const {
@@ -104,9 +108,10 @@ const DefaultsList = (props: IProps): JSX.Element => {
104
108
 
105
109
  useEffect(() => {
106
110
  const isNavigationModulesChanged =
111
+ currentSiteInfo &&
107
112
  currentSiteInfo.navigationModules?.[currentType] &&
108
113
  currentDefaultsContent.some(
109
- (navigation) => navigation.component !== currentSiteInfo.navigationModules[currentType]
114
+ (navigation) => navigation.component !== currentSiteInfo?.navigationModules[currentType]
110
115
  );
111
116
  setIsNavigationNotificationOpen(isNavigationModulesChanged);
112
117
  // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -129,10 +134,13 @@ const DefaultsList = (props: IProps): JSX.Element => {
129
134
  setHistoryPush(path, true);
130
135
  };
131
136
 
132
- const rightButtonProps = {
133
- label: "New",
134
- action: () => addNewDefault(),
135
- };
137
+ const rightButtonProps =
138
+ isAllowedToCreateHeaders || isAllowedToCreateFooters
139
+ ? {
140
+ label: "New",
141
+ action: () => addNewDefault(),
142
+ }
143
+ : undefined;
136
144
 
137
145
  const languageActions = {
138
146
  setLanguage,
@@ -186,10 +194,21 @@ const DefaultsList = (props: IProps): JSX.Element => {
186
194
 
187
195
  const onScroll = (e: any) => setIsScrolling(e.target.scrollTop > 0);
188
196
 
197
+ const bulkActions =
198
+ isAllowedToDeleteFooters || isAllowedToDeleteHeaders
199
+ ? [
200
+ {
201
+ icon: "delete",
202
+ text: "delete",
203
+ action: bulkDelete,
204
+ },
205
+ ]
206
+ : [];
207
+
189
208
  const TableHeader = (
190
209
  <BulkHeader
191
210
  showBulk={areItemsSelected(navIds)}
192
- bulkDelete={bulkDelete}
211
+ bulkActions={bulkActions}
193
212
  selectAllItems={handleSelectAll}
194
213
  totalItems={totalItems}
195
214
  selectItems={selectItems}
@@ -292,7 +311,7 @@ interface IDefaultsProps {
292
311
  selectedDefault: string;
293
312
  currentDefaultsContent: (IHeader | IFooter)[];
294
313
  totalItems: number;
295
- currentSiteInfo: any;
314
+ currentSiteInfo: ISite | null;
296
315
  }
297
316
 
298
317
  type IProps = IDefaultsProps & IDispatchProps;
@@ -1,14 +1,14 @@
1
1
  import React, { useState } from "react";
2
-
3
2
  import { connect } from "react-redux";
3
+
4
4
  import { menuActions } from "@ax/containers/Navigation";
5
5
  import { IRootState } from "@ax/types";
6
-
7
6
  import { IconAction } from "@ax/components";
8
- import SidePanel from "../SidePanel";
9
-
7
+ import { Restricted } from "@ax/guards";
10
8
  import { useModal } from "@ax/hooks";
11
9
 
10
+ import SidePanel from "../SidePanel";
11
+
12
12
  import * as S from "./style";
13
13
 
14
14
  const Header = (props: IProps): JSX.Element => {
@@ -31,7 +31,9 @@ const Header = (props: IProps): JSX.Element => {
31
31
  return (
32
32
  <S.Header>
33
33
  <S.Title>{title}</S.Title>
34
- <IconAction icon="add" size="m" onClick={openModal} />
34
+ <Restricted to="navigation.manageSiteMenu">
35
+ <IconAction icon="add" size="m" onClick={openModal} />
36
+ </Restricted>
35
37
  <SidePanel
36
38
  isOpen={isOpen}
37
39
  isOpenedSecond={isOpenedSecond}