@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
@@ -1,7 +1,7 @@
1
1
  import React, { useState } from "react";
2
2
  import { connect } from "react-redux";
3
3
 
4
- import { IDataPackConfigImport, IDataPackConfigImportCategory, IRootState, ITemplate } from "@ax/types";
4
+ import { IDataPackConfigImport, IDataPackConfigImportCategory, IRootState, ISite, ITemplate } from "@ax/types";
5
5
  import { dataPacksActions } from "@ax/containers/Settings";
6
6
  import { FieldsBehavior, Modal, Tag } from "@ax/components";
7
7
  import { useModal } from "@ax/hooks";
@@ -13,6 +13,10 @@ const Form = (props: IProps): JSX.Element => {
13
13
  const { currentSite, selected, updateFormValue, configFormData, allStructuredData } = props;
14
14
  const { templates, categories, structuredData } = selected;
15
15
 
16
+ if (!currentSite) {
17
+ throw new Error(`ERROR: User reached Data Pack form with null site info`);
18
+ }
19
+
16
20
  const getSubscribedData = (importValue: IDataPackConfigImport[]) => {
17
21
  const value: Record<string, ICategoryValue[]> = {};
18
22
  if (!importValue) return value;
@@ -176,7 +180,7 @@ const Form = (props: IProps): JSX.Element => {
176
180
  onChange={setIndexDefault}
177
181
  />
178
182
  </S.SectionContent>
179
- <TemplateConfig templates={templates} currentSite={currentSite}/>
183
+ <TemplateConfig templates={templates} currentSite={currentSite} />
180
184
  </S.Config>
181
185
  <Modal
182
186
  isOpen={isOpen}
@@ -212,7 +216,7 @@ interface ICategoryValue {
212
216
 
213
217
  interface IProps {
214
218
  selected: any;
215
- currentSite: number;
219
+ currentSite: ISite | null;
216
220
  updateFormValue: (config?: any) => void;
217
221
  configFormData: any;
218
222
  allStructuredData: any;
@@ -14,6 +14,10 @@ const ConfigPack = (props: IProps): JSX.Element => {
14
14
  const { title, description, categories, templates, modules, structuredData } = selected;
15
15
  const isFromPage = templates && templates.length > 0;
16
16
 
17
+ if (!currentSiteInfo) {
18
+ throw new Error(`ERROR: User reached DataPacks with null site info`);
19
+ }
20
+
17
21
  return (
18
22
  <S.Wrapper>
19
23
  <S.Pack>
@@ -69,7 +73,7 @@ const ConfigPack = (props: IProps): JSX.Element => {
69
73
 
70
74
  interface IProps {
71
75
  selected: any;
72
- currentSiteInfo: ISite;
76
+ currentSiteInfo: ISite | null;
73
77
  }
74
78
 
75
79
  const mapStateToProps = (state: IRootState) => ({
@@ -12,6 +12,10 @@ import * as S from "./style";
12
12
  const Item = (props: IProps): JSX.Element => {
13
13
  const { getActivatedDataPack, pack, toggleToast, deleteSiteDataPack, setDeactivatedPack, currentSiteInfo } = props;
14
14
 
15
+ if (!currentSiteInfo) {
16
+ throw new Error(`ERROR: User reached DataPacks with null site info`);
17
+ }
18
+
15
19
  const { title, id, templates, config } = pack;
16
20
  const isFromPage = templates && templates.length > 0;
17
21
  const { isOpen, toggleModal } = useModal();
@@ -103,7 +107,7 @@ const Item = (props: IProps): JSX.Element => {
103
107
 
104
108
  interface IProps {
105
109
  pack: any;
106
- currentSiteInfo: ISite;
110
+ currentSiteInfo: ISite | null;
107
111
  getActivatedDataPack: (selected: string) => void;
108
112
  toggleToast: () => void;
109
113
  setDeactivatedPack: Dispatch<SetStateAction<string>>;
@@ -6,8 +6,6 @@ const BulkHeader = (props: IProps): JSX.Element => {
6
6
  const {
7
7
  showBulk,
8
8
  checkState,
9
- bulkDelete,
10
- bulkDeactivate,
11
9
  selectItems,
12
10
  selectAllItems,
13
11
  totalItems,
@@ -16,21 +14,9 @@ const BulkHeader = (props: IProps): JSX.Element => {
16
14
  filterValues,
17
15
  sortItems,
18
16
  sortedListStatus,
17
+ bulkActions,
19
18
  } = props;
20
19
 
21
- const bulkActions = [
22
- {
23
- icon: "delete",
24
- text: "delete",
25
- action: bulkDelete,
26
- },
27
- {
28
- icon: "deactivate",
29
- text: "Deactivate",
30
- action: bulkDeactivate,
31
- },
32
- ];
33
-
34
20
  return showBulk ? (
35
21
  <BulkSelectionOptions
36
22
  checkState={checkState}
@@ -54,8 +40,6 @@ const BulkHeader = (props: IProps): JSX.Element => {
54
40
  interface IProps {
55
41
  showBulk: boolean;
56
42
  checkState: any;
57
- bulkDelete: () => void;
58
- bulkDeactivate: () => void;
59
43
  selectItems: () => void;
60
44
  selectAllItems: () => void;
61
45
  totalItems: number;
@@ -64,6 +48,7 @@ interface IProps {
64
48
  filterValues: any;
65
49
  sortItems: (orderPointer: string, isAscending: boolean) => void;
66
50
  sortedListStatus: { isAscending: boolean; sortedByTitle: boolean };
51
+ bulkActions: { icon: string; text: string; action: () => void }[];
67
52
  }
68
53
 
69
54
  export default BulkHeader;
@@ -18,6 +18,10 @@ const IntegrationForm = (props: IProps) => {
18
18
  const { setHistoryPush, createIntegration, updateIntegration, siteID, isSaving, siteLangs, setError, integration } =
19
19
  props;
20
20
 
21
+ if (!siteID) {
22
+ throw new Error(`ERROR: User reached Integrations with null site info`);
23
+ }
24
+
21
25
  const isNew = !integration?.id;
22
26
  const initState: IIntegration = integration
23
27
  ? integration
@@ -288,7 +292,7 @@ const IntegrationForm = (props: IProps) => {
288
292
  const mapStateToProps = (state: IRootState) => ({
289
293
  isSaving: state.app.isSaving,
290
294
  isLoading: state.app.isLoading,
291
- siteID: state.sites.currentSiteInfo.id,
295
+ siteID: state.sites.currentSiteInfo && state.sites.currentSiteInfo.id,
292
296
  siteLangs: state.sites.currentSiteLanguages,
293
297
  integration: state.integrations.currentIntegration,
294
298
  });
@@ -310,7 +314,7 @@ const mapDispatchToProps = {
310
314
  interface IIntegrationFromProps {
311
315
  isSaving: boolean;
312
316
  isLoading: boolean;
313
- siteID: number;
317
+ siteID: number | null;
314
318
  siteLangs: ILanguage[];
315
319
  integration: IIntegration | null;
316
320
  }
@@ -2,9 +2,9 @@ import React from "react";
2
2
  import { connect } from "react-redux";
3
3
  import { DraggableProvided } from "react-beautiful-dnd";
4
4
 
5
+ import { useModal, usePermission, useToast } from "@ax/hooks";
5
6
  import { ICheck, IIntegration } from "@ax/types";
6
7
  import { CheckField, Icon, Modal, Toast, ToggleField } from "@ax/components";
7
- import { useModal, useToast } from "@ax/hooks";
8
8
  import { integrations } from "@ax/api";
9
9
  import { integrationsActions } from "@ax/containers/Integrations";
10
10
  import { appActions } from "@ax/containers/App";
@@ -32,6 +32,11 @@ const IntegrationItem = (props: IIntegrationItemProps): JSX.Element => {
32
32
  const { isOpen: isOpenCopy, toggleModal: toggleModalCopy } = useModal();
33
33
  const { isVisible: isVisibleCopy, toggleToast: toggleToastCopy, setIsVisible: setIsVisibleCopy } = useToast();
34
34
 
35
+ const isAllowedToManageIntegrations = usePermission("general.manageSiteThirdPartyIntegrations");
36
+ const isAllowedToActivateIntegrations = usePermission("general.activateSiteThirdPartyIntegrations");
37
+ const isAllowedToDeactivateIntegrations = usePermission("general.deactivateSiteThirdPartyIntegrations");
38
+ const isAllowedToDeleteIntegrations = usePermission("general.deleteSiteThirdPartyIntegrations");
39
+
35
40
  const handleOnChange = (value: ICheck) => onChange(value);
36
41
 
37
42
  const getContentPresence = (contentPresence: {
@@ -75,12 +80,15 @@ const IntegrationItem = (props: IIntegrationItemProps): JSX.Element => {
75
80
  icon: "copy2",
76
81
  action: toggleModalCopy,
77
82
  },
78
- {
83
+ ];
84
+
85
+ if (isAllowedToDeleteIntegrations) {
86
+ menuOptions.push({
79
87
  label: "delete",
80
88
  icon: "delete",
81
89
  action: toggleModalDelete,
82
- },
83
- ];
90
+ });
91
+ }
84
92
 
85
93
  const mainDeleteModalAction = {
86
94
  title: "Delete add-on",
@@ -115,6 +123,8 @@ const IntegrationItem = (props: IIntegrationItemProps): JSX.Element => {
115
123
  setHistoryPush("addons/edit");
116
124
  };
117
125
 
126
+ const isToggleDisabled = (integration.active && !isAllowedToDeactivateIntegrations) || (!integration.active && !isAllowedToActivateIntegrations);
127
+
118
128
  return (
119
129
  <>
120
130
  <S.ItemRow
@@ -132,18 +142,18 @@ const IntegrationItem = (props: IIntegrationItemProps): JSX.Element => {
132
142
  <S.CheckCell role="cell" hasHandle={listLength >= 2}>
133
143
  <CheckField name="check" value={integration.id ?? ""} checked={isSelected} onChange={handleOnChange} />
134
144
  </S.CheckCell>
135
- <S.NameCell role="cell" onClick={handleClick}>
145
+ <S.NameCell role="cell" onClick={handleClick} clickable={isAllowedToManageIntegrations} >
136
146
  <S.Order>#{integration.correlativeScriptOrder}</S.Order>
137
147
  <div>{integration.name}</div>
138
148
  </S.NameCell>
139
- <S.DescriptionCell role="cell" onClick={handleClick}>
149
+ <S.DescriptionCell role="cell" onClick={handleClick} clickable={isAllowedToManageIntegrations} >
140
150
  {integration.description}
141
151
  </S.DescriptionCell>
142
- <S.AppliedOnCell role="cell" onClick={handleClick}>
152
+ <S.AppliedOnCell role="cell" onClick={handleClick} clickable={isAllowedToManageIntegrations} >
143
153
  Applied on: <S.ContentPresence>{getContentPresence(integration.contentPresence)}</S.ContentPresence>
144
154
  </S.AppliedOnCell>
145
155
  <S.StateCell role="cell">
146
- <ToggleField name="state" value={integration.active} onChange={toggleModalChangeState} />
156
+ <ToggleField name="state" value={integration.active} onChange={toggleModalChangeState} disabled={isToggleDisabled} />
147
157
  </S.StateCell>
148
158
  <S.ActionsCell role="cell">
149
159
  <S.StyledActionMenu icon="more" options={menuOptions} tooltip="Actions" />
@@ -11,8 +11,9 @@ const CheckCell = styled(Cell)<{ hasHandle: boolean }>`
11
11
  }
12
12
  `;
13
13
 
14
- const NameCell = styled(Cell)`
14
+ const NameCell = styled(Cell)<{ clickable: boolean }>`
15
15
  ${(p) => p.theme.textStyle.uiM};
16
+ pointer-events: ${(p) => (p.clickable ? "auto" : "none")};
16
17
  color: ${(p) => p.theme.color.textHighEmphasis};
17
18
  width: 350px;
18
19
  flex-flow: row wrap;
@@ -25,14 +26,16 @@ const Order = styled.div`
25
26
  margin-right: ${(p) => p.theme.spacing.xxs};
26
27
  `;
27
28
 
28
- const DescriptionCell = styled(Cell)`
29
+ const DescriptionCell = styled(Cell)<{ clickable: boolean }>`
29
30
  ${(p) => p.theme.textStyle.uiXS};
31
+ pointer-events: ${(p) => (p.clickable ? "auto" : "none")};
30
32
  color: ${(p) => p.theme.color.textMediumEmphasis};
31
33
  flex: 1;
32
34
  `;
33
35
 
34
- const AppliedOnCell = styled(Cell)`
36
+ const AppliedOnCell = styled(Cell)<{ clickable: boolean }>`
35
37
  ${(p) => p.theme.textStyle.uiXS};
38
+ pointer-events: ${(p) => (p.clickable ? "auto" : "none")};
36
39
  color: ${(p) => p.theme.color.textMediumEmphasis};
37
40
  flex: 1;
38
41
  display: inline;
@@ -6,7 +6,7 @@ import { IEmptyStateProps, IIntegration, IRootState } from "@ax/types";
6
6
  import { MainWrapper, ErrorToast, TableList, EmptyState, Toast } from "@ax/components";
7
7
  import { integrationsActions } from "@ax/containers/Integrations";
8
8
  import { appActions } from "@ax/containers/App";
9
- import { useBulkSelection, useEmptyState, useModal, useToast } from "@ax/hooks";
9
+ import { useBulkSelection, useEmptyState, useModal, usePermission, useToast } from "@ax/hooks";
10
10
 
11
11
  import BulkHeader from "./BulkHeader";
12
12
  import IntegrationItem from "./IntegrationItem";
@@ -55,11 +55,16 @@ const Integrations = (props: IIntegrationsProps): JSX.Element => {
55
55
  state: stateToastChange,
56
56
  } = useToast();
57
57
 
58
+ const isAllowedToManageIntegrations = usePermission("general.manageSiteThirdPartyIntegrations");
59
+ const isAllowedToDeactivateIntegrations = usePermission("general.deactivateSiteThirdPartyIntegrations");
60
+ const isAllowedToDeleteIntegrations = usePermission("general.deleteSiteThirdPartyIntegrations");
61
+
58
62
  const noElementsProps: IEmptyStateProps = {
59
63
  message: "To start using add-ons in your site, create as many Custom Code as you need.",
60
64
  button: "Create custom code",
61
65
  action: () => setHistoryPush(`/sites/settings/addons/new`),
62
66
  };
67
+
63
68
  const fetchState = { isLoading, isFiltered };
64
69
  const { isEmpty, emptyStateProps } = useEmptyState(integrations, fetchState, { noElementsProps });
65
70
 
@@ -136,11 +141,28 @@ const Integrations = (props: IIntegrationsProps): JSX.Element => {
136
141
  setCurrentFilterQuery(filterQuery);
137
142
  };
138
143
 
144
+ const bulkActions: { icon: string; text: string; action: () => void | Promise<void> }[] =
145
+ isAllowedToDeleteIntegrations
146
+ ? [
147
+ {
148
+ icon: "delete",
149
+ text: "delete",
150
+ action: bulkDelete,
151
+ },
152
+ ]
153
+ : [];
154
+
155
+ if (isAllowedToDeactivateIntegrations) {
156
+ bulkActions.push({
157
+ icon: "deactivate",
158
+ text: "Deactivate",
159
+ action: toggleModalDeactivate,
160
+ });
161
+ }
162
+
139
163
  const TableHeader = (
140
164
  <BulkHeader
141
165
  showBulk={areItemsSelected(integrationsIds)}
142
- bulkDelete={toggleModalDelete}
143
- bulkDeactivate={toggleModalDeactivate}
144
166
  selectAllItems={handleSelectAll}
145
167
  totalItems={totalItems}
146
168
  selectItems={selectItems}
@@ -150,6 +172,7 @@ const Integrations = (props: IIntegrationsProps): JSX.Element => {
150
172
  filterValues={filterValues}
151
173
  sortItems={sortItems}
152
174
  sortedListStatus={sortedListStatus}
175
+ bulkActions={bulkActions}
153
176
  />
154
177
  );
155
178
 
@@ -197,10 +220,12 @@ const Integrations = (props: IIntegrationsProps): JSX.Element => {
197
220
  }`,
198
221
  };
199
222
 
200
- const rightButtonProps = {
201
- label: "New Custom Code",
202
- action: () => setHistoryPush(`/sites/settings/addons/new`),
203
- };
223
+ const rightButtonProps = isAllowedToManageIntegrations
224
+ ? {
225
+ label: "New Custom Code",
226
+ action: () => setHistoryPush(`/sites/settings/addons/new`),
227
+ }
228
+ : undefined;
204
229
 
205
230
  const ComponentList = React.memo(function ComponentList({ components }: any) {
206
231
  return components.map((integration: IIntegration, index: number) => {
@@ -12,6 +12,10 @@ import * as S from "./style";
12
12
  const LanguagePanel = (props: IProps): JSX.Element => {
13
13
  const { isOpen, toggleModal, createSiteLanguage, updateSiteLanguage, currentSiteID, languageData, item } = props;
14
14
 
15
+ if (!currentSiteID) {
16
+ throw new Error(`ERROR: User reached Languages with null site info`);
17
+ }
18
+
15
19
  const addItemAction = () => {
16
20
  createSiteLanguage(currentSiteID, languageData);
17
21
  toggleModal();
@@ -55,7 +59,7 @@ const LanguagePanel = (props: IProps): JSX.Element => {
55
59
  };
56
60
 
57
61
  const mapStateToProps = (state: IRootState) => ({
58
- currentSiteID: state.sites.currentSiteInfo.id,
62
+ currentSiteID: state.sites.currentSiteInfo && state.sites.currentSiteInfo.id,
59
63
  languageData: state.languages.form,
60
64
  });
61
65
 
@@ -65,7 +69,7 @@ const mapDispatchToProps = {
65
69
  };
66
70
 
67
71
  interface IStateProps {
68
- currentSiteID: number;
72
+ currentSiteID: number | null;
69
73
  languageData: ISiteLanguage;
70
74
  }
71
75
 
@@ -4,8 +4,8 @@ import { connect } from "react-redux";
4
4
  import { useModal } from "@ax/hooks";
5
5
  import { languagesActions } from "@ax/containers/Settings";
6
6
  import { ILanguage } from "@ax/types";
7
-
8
7
  import { IconAction } from "@ax/components";
8
+ import { Restricted } from "@ax/guards";
9
9
  import LanguagePanel from "../../LanguagePanel";
10
10
 
11
11
  import * as S from "./style";
@@ -27,7 +27,9 @@ const Header = (props: IProps): JSX.Element => {
27
27
  return (
28
28
  <S.Header>
29
29
  <S.Title>{title}</S.Title>
30
- <IconAction icon="add" size="m" onClick={openModal} />
30
+ <Restricted to="general.createLanguages">
31
+ <IconAction icon="add" size="m" onClick={openModal} />
32
+ </Restricted>
31
33
  <LanguagePanel isOpen={isOpen} toggleModal={toggleModal} />
32
34
  </S.Header>
33
35
  );
@@ -1,11 +1,10 @@
1
1
  import React from "react";
2
2
  import { connect } from "react-redux";
3
3
 
4
- import { useModal } from "@ax/hooks";
5
- import { ILanguage, ISiteLanguage, IRootState } from "@ax/types";
4
+ import { useModal, usePermission } from "@ax/hooks";
5
+ import { ILanguage, ISiteLanguage, IRootState, ISite } from "@ax/types";
6
6
  import { languagesActions } from "@ax/containers/Settings";
7
-
8
- import { Icon, IconAction, FloatingMenu, Flag } from "@ax/components";
7
+ import { Flag } from "@ax/components";
9
8
  import LanguagePanel from "../../LanguagePanel";
10
9
 
11
10
  import * as S from "./style";
@@ -13,6 +12,14 @@ import * as S from "./style";
13
12
  const Item = (props: IItemProps): JSX.Element => {
14
13
  const { item, resetForm, setForm, deleteSiteLanguage, currentSiteInfo } = props;
15
14
 
15
+ if (!currentSiteInfo) {
16
+ throw new Error(`ERROR: User reached Site Languages with null site info`);
17
+ }
18
+
19
+ const { isOpen, toggleModal } = useModal();
20
+ const isAllowedToEdit = usePermission("general.editLanguage");
21
+ const isAllowedToDelete = usePermission("general.deleteLanguages");
22
+
16
23
  const siteLanguage: ISiteLanguage = {
17
24
  language: item.id,
18
25
  path: item.path,
@@ -20,48 +27,19 @@ const Item = (props: IItemProps): JSX.Element => {
20
27
  isDefault: item.isDefault,
21
28
  };
22
29
 
23
- const MoreInfoButton = () => (
24
- <S.IconWrapper>
25
- <IconAction icon="more" />
26
- </S.IconWrapper>
27
- );
28
-
29
- const ActionMenuOption = (option: any) => (
30
- <S.ActionItem key={option.icon} onClick={option.action}>
31
- <Icon name={option.icon} />
32
- <S.ActionText>{option.label}</S.ActionText>
33
- </S.ActionItem>
34
- );
35
-
36
- const ActionMenu = (menu: any) => (
37
- <S.ActionMenu>{menu.map((option: any, i: number) => ActionMenuOption(option))}</S.ActionMenu>
38
- );
30
+ const removeItemAction = () => deleteSiteLanguage(currentSiteInfo.id, item.id);
39
31
 
40
- const deleteItem = (item: ILanguage) => {
41
- deleteSiteLanguage(currentSiteInfo.id, item.id);
42
- };
43
-
44
- const removeItemAction = () => {
45
- deleteItem(item);
46
- };
47
-
48
- const actionMenuOptions = [
32
+ const menuOptions = isAllowedToDelete ? [
49
33
  {
50
34
  label: "Delete",
51
35
  icon: "delete",
52
36
  action: removeItemAction,
53
37
  },
54
- ];
38
+ ] : [];
55
39
 
56
- const { isOpen, toggleModal } = useModal();
57
-
58
- const resetValues = () => {
59
- resetForm();
60
- };
40
+ const resetValues = () => resetForm();
61
41
 
62
- const setItem = (item: ISiteLanguage) => {
63
- setForm(item);
64
- };
42
+ const setItem = (item: ISiteLanguage) => setForm(item);
65
43
 
66
44
  const openModal = () => {
67
45
  resetValues();
@@ -71,15 +49,13 @@ const Item = (props: IItemProps): JSX.Element => {
71
49
 
72
50
  return (
73
51
  <>
74
- <S.Component onClick={openModal}>
52
+ <S.Component onClick={openModal} disabled={!isAllowedToEdit}>
75
53
  <S.FlagWrapper>
76
54
  <Flag name={item.locale} />
77
55
  </S.FlagWrapper>
78
56
  {item.language}
79
57
  <S.Default>{item.isDefault ? "Default" : ""}</S.Default>
80
- <FloatingMenu Button={MoreInfoButton}>
81
- {ActionMenu(actionMenuOptions)}
82
- </FloatingMenu>
58
+ <S.StyledActionMenu icon="more" options={menuOptions} />
83
59
  </S.Component>
84
60
  <LanguagePanel isOpen={isOpen} toggleModal={toggleModal} item={item} />
85
61
  </>
@@ -88,7 +64,7 @@ const Item = (props: IItemProps): JSX.Element => {
88
64
 
89
65
  interface IProps {
90
66
  item: ILanguage;
91
- currentSiteInfo: any;
67
+ currentSiteInfo: ISite | null;
92
68
  }
93
69
 
94
70
  const mapStateToProps = (state: IRootState) => ({
@@ -1,57 +1,11 @@
1
1
  import styled from "styled-components";
2
+ import { ActionMenu } from "@ax/components";
2
3
 
3
- export const IconWrapper = styled.div`
4
+ const StyledActionMenu = styled(ActionMenu)`
4
5
  opacity: 0;
5
- position: absolute;
6
- top: ${(p) => p.theme.spacing.xs};
7
- bottom: ${(p) => p.theme.spacing.xs};
8
- right: 0;
9
- width: 30px;
10
- display: flex;
11
- justify-content: center;
12
- align-items: center;
13
- margin-right: ${(p) => p.theme.spacing.xs};
14
- `;
15
-
16
- export const ActionsWrapper = styled.div`
17
- opacity: 0;
18
- transition: opacity 0.1s;
19
- text-align: right;
20
6
  `;
21
7
 
22
- export const ActionMenu = styled.ul`
23
- padding: ${(p) => p.theme.spacing.s};
24
- `;
25
-
26
- export const ActionText = styled.span`
27
- padding-left: ${(p) => p.theme.spacing.xs};
28
- margin-left: ${(p) => p.theme.spacing.xxs};
29
- `;
30
-
31
- export const ActionItem = styled.li`
32
- display: flex;
33
- align-items: center;
34
- ${(p) => p.theme.textStyle.uiM};
35
- color: ${(p) => p.theme.color.textMediumEmphasis};
36
- svg {
37
- path {
38
- fill: ${(p) => p.theme.color.iconMediumEmphasis};
39
- }
40
- }
41
- `;
42
-
43
- export const IconWrapperDrag = styled.div`
44
- margin-right: ${(p) => p.theme.spacing.xxs};
45
- ${(p) => p.theme.textStyle.uiXS};
46
- opacity: 1;
47
- svg {
48
- path {
49
- fill: ${(p) => p.theme.color.textLowEmphasis};
50
- }
51
- }
52
- `;
53
-
54
- export const Component = styled.span`
8
+ const Component = styled.span<{ disabled: boolean }>`
55
9
  color: ${(p) => p.theme.color.textHighEmphasis};
56
10
  position: relative;
57
11
  display: flex;
@@ -67,29 +21,32 @@ export const Component = styled.span`
67
21
  ${(p) => p.theme.textStyle.fieldLabel};
68
22
  text-align: left;
69
23
  cursor: pointer;
24
+ pointer-events: ${(p) => (p.disabled ? "none" : "auto")};
70
25
 
71
26
  &:hover {
72
- background: ${(p) => p.theme.color.overlayHoverPrimary};
73
- ${IconWrapper} {
27
+ background: ${(p) => (p.disabled ? p.theme.color.uiBackground02 : p.theme.color.overlayHoverPrimary)};
28
+ ${StyledActionMenu} {
74
29
  opacity: 1;
75
30
  }
76
31
  }
77
32
 
78
33
  &:focus,
79
34
  &:active {
80
- background: ${(p) => p.theme.color.overlayFocusPrimary};
35
+ background: ${(p) => (p.disabled ? p.theme.color.uiBackground02 : p.theme.color.overlayFocusPrimary)};
81
36
  border: 1px solid ${(p) => p.theme.color.interactive01};
82
37
  outline: none;
83
38
  }
84
39
  `;
85
40
 
86
- export const FlagWrapper = styled.div`
41
+ const FlagWrapper = styled.div`
87
42
  margin-right: ${(p) => p.theme.spacing.xs};
88
43
  `;
89
44
 
90
- export const Default = styled.div`
45
+ const Default = styled.div`
91
46
  ${(p) => p.theme.textStyle.uiM};
92
47
  color: ${(p) => p.theme.color.textMediumEmphasis};
93
48
  margin-left: auto;
94
49
  margin-right: ${(p) => p.theme.spacing.l};
95
50
  `;
51
+
52
+ export { StyledActionMenu, Component, FlagWrapper, Default };
@@ -1,7 +1,7 @@
1
1
  import React, { useEffect } from "react";
2
2
  import { connect } from "react-redux";
3
3
 
4
- import { INavItem, IRootState } from "@ax/types";
4
+ import { INavItem, IRootState, ISite } from "@ax/types";
5
5
  import { sitesActions } from "@ax/containers/Sites";
6
6
  import { appActions } from "@ax/containers/App";
7
7
  import { MainWrapper, Loading, ErrorToast, Nav } from "@ax/components";
@@ -58,7 +58,7 @@ interface IDispatchProps {
58
58
  }
59
59
 
60
60
  interface ILanguagesProps {
61
- currentSiteInfo: any;
61
+ currentSiteInfo: ISite | null;
62
62
  isLoading: boolean;
63
63
  navItems: INavItem[];
64
64
  currentNavItem: INavItem;
@@ -68,7 +68,7 @@ const Analytics = (props: IProps): JSX.Element => {
68
68
  </S.AnalyticsWrapper>
69
69
  )}
70
70
  </>
71
- )
71
+ );
72
72
 
73
73
  return (
74
74
  <>
@@ -76,9 +76,7 @@ const Analytics = (props: IProps): JSX.Element => {
76
76
  <MainWrapper backLink={false} title="Analytics Settings" rightButton={rightButtonProps}>
77
77
  <S.Wrapper>
78
78
  <Nav current={currentNavItem} items={navItems} onClick={setRoute} />
79
- <S.ContentWrapper>
80
- {isLoading ? <Loading /> : analyticsSettings}
81
- </S.ContentWrapper>
79
+ <S.ContentWrapper>{isLoading ? <Loading /> : analyticsSettings}</S.ContentWrapper>
82
80
  </S.Wrapper>
83
81
  </MainWrapper>
84
82
  </>
@@ -9,11 +9,13 @@ const navItems = [
9
9
  title: "SEO",
10
10
  path: "/sites/settings/seo",
11
11
  component: Redirects,
12
+ permission: "seoAnalytics.manageAnalyticsSiteSettings",
12
13
  },
13
14
  {
14
15
  title: "Analytics",
15
16
  path: "/sites/settings/analytics",
16
- component: Analytics
17
+ component: Analytics,
18
+ permission: "seoAnalytics.manageAnalyticsSiteSettings",
17
19
  },
18
20
  ];
19
21
 
@@ -26,7 +28,7 @@ const SeoAnalyticsSettings = (): JSX.Element => {
26
28
  </Route>
27
29
  ))}
28
30
  </Switch>
29
- )
31
+ );
30
32
  };
31
33
 
32
34
  export default SeoAnalyticsSettings;
@@ -20,7 +20,7 @@ const Social = (props: IProps): JSX.Element => {
20
20
  { name: "instagram", title: "Instagram URL" },
21
21
  { name: "linkedIn", title: "LinkedIn URL" },
22
22
  { name: "facebook", title: "Facebook URL" },
23
- { name: "twitter", title: "Twitter URL" },
23
+ { name: "twitter", title: "X/Twitter URL" },
24
24
  { name: "youtube", title: "YouTube URL" },
25
25
  { name: "flicker", title: "Flicker URL" },
26
26
  { name: "tiktok", title: "Tiktok URL" },