@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,12 +1,22 @@
1
1
  import React, { memo } from "react";
2
2
  import { connect } from "react-redux";
3
3
 
4
- import { IRootState, IStructuredDataContent, ICheck, IDataPack, ILanguage, IDataLanguage, IColumn } from "@ax/types";
4
+ import {
5
+ IRootState,
6
+ IStructuredDataContent,
7
+ ICheck,
8
+ IDataPack,
9
+ ILanguage,
10
+ IDataLanguage,
11
+ IColumn,
12
+ ISite,
13
+ } from "@ax/types";
5
14
  import { getActivatedDataPacksIds, getHumanLastModifiedDate } from "@ax/helpers";
6
15
  import { setIsSavedData } from "@ax/forms";
7
16
  import { structuredDataActions } from "@ax/containers/StructuredData";
8
17
  import { appActions } from "@ax/containers/App";
9
18
  import { CheckField, FloatingMenu, Icon, Flag, LanguageMenu, Tooltip, CategoryCell } from "@ax/components";
19
+ import { usePermission } from "@ax/hooks";
10
20
 
11
21
  import * as S from "./style";
12
22
 
@@ -34,8 +44,22 @@ const StructuredDataItem = (props: IStructuredDataItemProps): JSX.Element => {
34
44
  columns,
35
45
  categoryColors,
36
46
  addCategoryColors,
47
+ currentSiteInfo,
37
48
  } = props;
38
49
 
50
+ const isAllowedToDuplicatePages =
51
+ (!currentSiteInfo && usePermission("global.globalData.duplicateGlobalData")) ||
52
+ (currentSiteInfo && usePermission("content.duplicatePages"));
53
+ const isAllowedToPublishPages =
54
+ (!currentSiteInfo && usePermission("global.globalData.publishUnpublishAllGlobalData")) ||
55
+ (currentSiteInfo && usePermission("content.publishUnpublishPages"));
56
+ const isAllowedToCreatePages =
57
+ (!currentSiteInfo && usePermission("global.globalData.createAllGlobalData")) ||
58
+ (currentSiteInfo && usePermission("content.createPages"));
59
+ const isAllowedToDeletePage =
60
+ (!currentSiteInfo && usePermission("global.globalData.deleteAllGlobalData")) ||
61
+ (currentSiteInfo && usePermission("content.deletePages"));
62
+
39
63
  const { locale } = lang;
40
64
  const { dataLanguages } = structuredData;
41
65
 
@@ -103,7 +127,7 @@ const StructuredDataItem = (props: IStructuredDataItemProps): JSX.Element => {
103
127
  const isDisabled =
104
128
  currentStructuredData && currentStructuredData.local && !activatedDataPacksIds.includes(currentStructuredData.id);
105
129
 
106
- const availableLanguages = isDisabled ? currentLanguages : languages;
130
+ const availableLanguages = isDisabled || !isAllowedToCreatePages ? currentLanguages : languages;
107
131
 
108
132
  const handleLanguage = (language: any) => () => {
109
133
  const {
@@ -156,26 +180,31 @@ const StructuredDataItem = (props: IStructuredDataItemProps): JSX.Element => {
156
180
  "Not translatable"
157
181
  );
158
182
 
159
- const deleteOption = {
160
- label: "delete",
161
- icon: "delete",
162
- action: removeItem,
163
- };
183
+ const menuOptions = [];
164
184
 
165
- const duplicateOption = {
166
- label: "duplicate",
167
- icon: "duplicate",
168
- action: duplicateItem,
169
- };
185
+ if (!isDisabled && isEditable && isAllowedToDuplicatePages) {
186
+ menuOptions.push({
187
+ label: "duplicate",
188
+ icon: "duplicate",
189
+ action: duplicateItem,
190
+ });
191
+ }
170
192
 
171
- const publishOption = {
172
- label: structuredData.draft ? "Publish" : "Unpublish",
173
- icon: structuredData.draft ? "upload-pending" : "offline",
174
- action: structuredData.draft ? publishItem : unpublishItem,
175
- };
193
+ if (isEditable && isAllowedToDeletePage) {
194
+ menuOptions.push({
195
+ label: "delete",
196
+ icon: "delete",
197
+ action: removeItem,
198
+ });
199
+ }
176
200
 
177
- const menuOptionsNoDuplicate = isEditable ? [deleteOption, publishOption] : [publishOption];
178
- const menuOptions = isDisabled || !isEditable ? menuOptionsNoDuplicate : [duplicateOption, ...menuOptionsNoDuplicate];
201
+ if (isAllowedToPublishPages) {
202
+ menuOptions.push({
203
+ label: structuredData.draft ? "Publish" : "Unpublish",
204
+ icon: structuredData.draft ? "upload-pending" : "offline",
205
+ action: structuredData.draft ? publishItem : unpublishItem,
206
+ });
207
+ }
179
208
 
180
209
  const CategoryColumns = categoryColumns.map((col: any) => {
181
210
  const type: any = structuredData && structuredData.content && structuredData.content[col.key];
@@ -250,10 +279,12 @@ interface IStructuredDataItemProps {
250
279
  categoryColors: any;
251
280
  addCategoryColors(cats: string[]): void;
252
281
  setCurrentDataID(id: number | null): void;
282
+ currentSiteInfo: ISite | null;
253
283
  }
254
284
 
255
285
  const mapStateToProps = (state: IRootState) => ({
256
286
  currentStructuredData: state.structuredData.currentStructuredData,
287
+ currentSiteInfo: state.sites.currentSiteInfo,
257
288
  });
258
289
 
259
290
  const mapDispatchToProps = {
@@ -24,7 +24,7 @@ import {
24
24
  ISetCurrentPageNameAction,
25
25
  pageStatus,
26
26
  } from "@ax/containers/PageEditor/interfaces";
27
- import { useBulkSelection, useModal, useToast, useCategoryColors } from "@ax/hooks";
27
+ import { useBulkSelection, useModal, useToast, useCategoryColors, usePermission } from "@ax/hooks";
28
28
  import { appActions } from "@ax/containers/App";
29
29
  import { structuredDataActions } from "@ax/containers/StructuredData";
30
30
  import { sitesActions } from "@ax/containers/Sites";
@@ -129,6 +129,8 @@ const StructuredDataList = (props: IProps): JSX.Element => {
129
129
  subErrors?: { id: number; error: string }[];
130
130
  } | null>(null);
131
131
 
132
+ const allowedToCreatePages = usePermission("global.globalData.createAllGlobalData");
133
+
132
134
  const scope = currentSiteID ? "site" : "global";
133
135
 
134
136
  const isDataEditable = filter === "all-pages" || !currentStructuredData || currentStructuredData.editable;
@@ -287,8 +289,8 @@ const StructuredDataList = (props: IProps): JSX.Element => {
287
289
  } else {
288
290
  emptyState.message = isAllPages
289
291
  ? "You don’t have pages with this content type yet."
290
- : isDataEditable ? "To start using pages in your site, create as many pages as you need." : undefined;
291
- emptyState.button = isAllPages ? "View all content" : isDataEditable ? "Create the first page" : undefined;
292
+ : allowedToCreatePages && isDataEditable ? "To start using pages in your site, create as many pages as you need." : undefined;
293
+ emptyState.button = isAllPages ? "View all content" : allowedToCreatePages && isDataEditable ? "Create the first page" : undefined;
292
294
  emptyState.action = isAllPages ? resetFilterValues : isDataEditable ? addNewAction : undefined;
293
295
  }
294
296
  const isEmpty = isStructuredDataFromPage ? !currentSitePages.length : !currentDataContent.length;
@@ -484,11 +486,11 @@ const StructuredDataList = (props: IProps): JSX.Element => {
484
486
 
485
487
  const addNewAction = isAllPages || isStructuredDataFromPage ? toggleNewModal : createNewData;
486
488
 
487
- const rightButtonProps = {
489
+ const rightButtonProps = allowedToCreatePages ? {
488
490
  label: "New",
489
491
  action: addNewAction,
490
492
  disabled: !isDataEditable,
491
- };
493
+ } : undefined;
492
494
 
493
495
  const options: { filters: IStructuredDataFilter[]; values: IStructuredDataValue[] } = {
494
496
  filters: getOptionFilters(structuredData),
@@ -587,6 +589,7 @@ const StructuredDataList = (props: IProps): JSX.Element => {
587
589
  dynamicValues={structuredData.global}
588
590
  onClick={handleMenuClick}
589
591
  addNew={addNewAction}
592
+ isAllowedToCreate={allowedToCreatePages}
590
593
  />
591
594
  <S.TableListWrapper>
592
595
  {!isDataEditable && (
@@ -730,7 +733,7 @@ interface ICategoriesProps {
730
733
  totalItems: number;
731
734
  lang: { locale: string; id: number | null };
732
735
  globalLangs: ILanguage[];
733
- currentSiteID: number;
736
+ currentSiteID: number | null;
734
737
  activatedDataPacks: IDataPack[];
735
738
  isLoading: boolean;
736
739
  template: string;
@@ -5,20 +5,28 @@ import { appActions } from "@ax/containers/App";
5
5
  import { usersActions } from "@ax/containers/Users";
6
6
  import { sitesActions } from "@ax/containers/Sites";
7
7
  import { Loading, MainWrapper } from "@ax/components";
8
- import { IRootState, IUser } from "@ax/types";
8
+ import { IGetRoles, IRootState, ISite, IUser } from "@ax/types";
9
9
  import { useURLSearchParam } from "@ax/hooks";
10
10
 
11
11
  import UserForm from "../UserForm";
12
12
 
13
13
  const Profile = (props: IProps) => {
14
- const { user, getUser, updateUser, isSaving, isLoading, getSites } = props;
14
+ const { user, getUser, updateUser, isSaving, isLoading, getSites, getRoles, currentSiteInfo } = props;
15
+
16
+ if (!user) {
17
+ throw new Error(`ERROR: User reached Profile with null user`);
18
+ }
15
19
 
16
20
  const isUserInit = useURLSearchParam("init");
17
21
 
18
22
  const [form, setForm] = useState<IUser>({ ...user });
19
23
 
24
+ const isSiteView = !!currentSiteInfo;
25
+
20
26
  useEffect(() => {
21
27
  isUserInit ? getSites() : getUser("me");
28
+ const siteId = isSiteView ? currentSiteInfo.id : "global";
29
+ getRoles({ siteId });
22
30
  // eslint-disable-next-line react-hooks/exhaustive-deps
23
31
  }, []);
24
32
 
@@ -43,7 +51,7 @@ const Profile = (props: IProps) => {
43
51
 
44
52
  return (
45
53
  <MainWrapper title="My Profile" rightButton={rightButtonProps}>
46
- <UserForm form={form} setForm={setForm} user={user} readOnlySites={true} />
54
+ <UserForm form={form} setForm={setForm} user={user} readOnlySites={true} site={currentSiteInfo} isSiteView={isSiteView} />
47
55
  </MainWrapper>
48
56
  );
49
57
  };
@@ -53,6 +61,7 @@ const mapStateToProps = (state: IRootState) => ({
53
61
  isSaving: state.app.isSaving,
54
62
  isLoading: state.app.isLoading,
55
63
  token: state.app.token,
64
+ currentSiteInfo: state.sites.currentSiteInfo,
56
65
  });
57
66
 
58
67
  interface IDispatchProps {
@@ -60,6 +69,7 @@ interface IDispatchProps {
60
69
  getUser(id: string): any;
61
70
  getSites(): Promise<void>;
62
71
  updateUser(id: number, data: any, isProfile: boolean, isList: boolean): any;
72
+ getRoles(params: IGetRoles): Promise<void>;
63
73
  }
64
74
 
65
75
  const mapDispatchToProps = {
@@ -67,13 +77,15 @@ const mapDispatchToProps = {
67
77
  getUser: usersActions.getUser,
68
78
  updateUser: usersActions.updateUser,
69
79
  getSites: sitesActions.getSites,
80
+ getRoles: usersActions.getRoles,
70
81
  };
71
82
 
72
83
  interface IProfileProps {
73
- user: IUser;
84
+ user: IUser | null;
74
85
  isSaving: boolean;
75
86
  isLoading: boolean;
76
87
  token: string;
88
+ currentSiteInfo: ISite | null;
77
89
  }
78
90
 
79
91
  type IProps = IProfileProps & IDispatchProps;
@@ -0,0 +1,52 @@
1
+ import React from "react";
2
+
3
+ import { CheckField, TableCounter, NameFilter, PermissionsFilter, UsersFilter } from "@ax/components";
4
+
5
+ import * as S from "./style";
6
+
7
+ const TableHeader = (props: IProps): JSX.Element => {
8
+ const { totalItems, selectAllItems, isScrolling, sortItems, sortedListStatus, isSiteView } = props;
9
+
10
+ return (
11
+ <S.TableHeader isScrolling={isScrolling} data-testid="roles-table-header">
12
+ <S.CheckHeader>
13
+ <CheckField
14
+ key="selectAll"
15
+ name="selectAll"
16
+ value="selectAll"
17
+ onChange={selectAllItems}
18
+ checked={false}
19
+ error={false}
20
+ />
21
+ </S.CheckHeader>
22
+ <S.NameWrapper>
23
+ <NameFilter sortItems={sortItems} sortedState={sortedListStatus} pointer="name" />
24
+ </S.NameWrapper>
25
+ {isSiteView && (
26
+ <S.UsersWrapper>
27
+ <UsersFilter sortItems={sortItems} sortedState={sortedListStatus} />
28
+ </S.UsersWrapper>
29
+ )}
30
+ <S.PermissionsWrapper>
31
+ <PermissionsFilter sortItems={sortItems} sortedState={sortedListStatus} />
32
+ </S.PermissionsWrapper>
33
+
34
+ <S.ActionsHeader isSiteView={isSiteView}>
35
+ <TableCounter totalItems={totalItems} />
36
+ </S.ActionsHeader>
37
+ </S.TableHeader>
38
+ );
39
+ };
40
+
41
+ interface IProps {
42
+ totalItems: number;
43
+ isScrolling: boolean;
44
+ selectAllItems: () => void;
45
+ filterItems: (filterPointer: string, filtersSelected: string) => void;
46
+ sortItems: any;
47
+ sortedListStatus: any;
48
+ filterValues: any;
49
+ isSiteView: boolean;
50
+ }
51
+
52
+ export default TableHeader;
@@ -0,0 +1,43 @@
1
+ import styled from "styled-components";
2
+ import { Header } from "@ax/components/TableList/style";
3
+
4
+ const TableHeader = styled.div<{ isScrolling?: boolean }>`
5
+ width: 100%;
6
+ display: flex;
7
+ flex-direction: row;
8
+ padding: ${(p) => p.theme.spacing.m};
9
+ border-bottom: ${(p) => (p.isScrolling ? `1px solid ${p.theme.color.uiLine};` : "")};
10
+ `;
11
+
12
+ const CheckHeader = styled(Header)`
13
+ padding-left: ${(p) => p.theme.spacing.m};
14
+ width: 32px;
15
+ `;
16
+
17
+ const NameWrapper = styled.div`
18
+ width: 400px;
19
+ position: relative;
20
+ `;
21
+
22
+ const PermissionsWrapper = styled.div`
23
+ flex-grow: 1;
24
+ display: flex;
25
+ justify-content: center;
26
+ position: relative;
27
+ `;
28
+
29
+ const ActionsHeader = styled(Header as any)<{ isSiteView: boolean }>`
30
+ display: flex;
31
+ width: ${(p) => (p.isSiteView ? "210px" : 'auto')};
32
+ justify-content: end;
33
+ padding-right: 0;
34
+ `;
35
+
36
+ const UsersWrapper = styled.div`
37
+ width: 20%;
38
+ display: flex;
39
+ justify-content: center;
40
+ position: relative;
41
+ `;
42
+
43
+ export { TableHeader, CheckHeader, NameWrapper, PermissionsWrapper, ActionsHeader, UsersWrapper };
@@ -0,0 +1,74 @@
1
+ import React from "react";
2
+ import { BulkSelectionOptions } from "@ax/components";
3
+ import TableHeader from "./TableHeader";
4
+ import { IRole } from "@ax/types";
5
+
6
+ const BulkHeader = (props: IBulkHeaderProps): JSX.Element => {
7
+ const {
8
+ showBulk,
9
+ checkState,
10
+ activateRoles,
11
+ selectItems,
12
+ selectAllItems,
13
+ totalItems,
14
+ isScrolling,
15
+ sortItems,
16
+ filterItems,
17
+ sortedListStatus,
18
+ filterValues,
19
+ isSiteView,
20
+ roles,
21
+ selectedRoles,
22
+ } = props;
23
+
24
+ const deactivatedSelectedRoles = roles.filter((role: IRole) => selectedRoles.includes(role.id) && !role.active);
25
+
26
+ const bulkAction = deactivatedSelectedRoles.length
27
+ ? {
28
+ text: "Activate",
29
+ action: () => activateRoles(true),
30
+ }
31
+ : {
32
+ text: "Deactivate",
33
+ action: () => activateRoles(false),
34
+ };
35
+
36
+ return showBulk ? (
37
+ <BulkSelectionOptions
38
+ checkState={checkState}
39
+ actions={[bulkAction]}
40
+ selectItems={selectItems}
41
+ totalItems={totalItems}
42
+ />
43
+ ) : (
44
+ <TableHeader
45
+ filterValues={filterValues}
46
+ totalItems={totalItems}
47
+ selectAllItems={selectAllItems}
48
+ filterItems={filterItems}
49
+ isScrolling={isScrolling}
50
+ sortItems={sortItems}
51
+ sortedListStatus={sortedListStatus}
52
+ isSiteView={isSiteView}
53
+ />
54
+ );
55
+ };
56
+
57
+ export interface IBulkHeaderProps {
58
+ showBulk: boolean;
59
+ checkState: any;
60
+ activateRoles: (active: boolean) => void;
61
+ selectItems: () => void;
62
+ selectAllItems: () => void;
63
+ totalItems: number;
64
+ isScrolling: boolean;
65
+ sortItems: (orderPointer: string, isAscending: boolean) => void;
66
+ sortedListStatus: any;
67
+ filterValues: any;
68
+ filterItems: (filterPointer: string, filtersSelected: string) => void;
69
+ isSiteView: boolean;
70
+ roles: IRole[];
71
+ selectedRoles: number[];
72
+ }
73
+
74
+ export default BulkHeader;
@@ -0,0 +1,104 @@
1
+ import React, { useState } from "react";
2
+
3
+ import { connect } from "react-redux";
4
+
5
+ import { IRootState, ICheck, IRole, IUser } from "@ax/types";
6
+ import { CheckField, ToggleField, Tag, Tooltip, Avatar } from "@ax/components";
7
+
8
+ import * as S from "./style";
9
+
10
+ const RoleItem = (props: IRoleItemProps): JSX.Element => {
11
+ const { role, users, isSelected, onChange, activateRole, siteId, onClick } = props;
12
+ const isSiteView = siteId !== "global";
13
+ const [isOpen, setIsOpen] = useState(false);
14
+
15
+ const toggleStatus = (value: boolean) => activateRole(value);
16
+
17
+ const roleUsers =
18
+ isSiteView && role?.users?.length > 0 ? users.filter((user: IUser) => role.users.includes(user.id)) : [];
19
+
20
+ const avatarList =
21
+ isSiteView && roleUsers.length
22
+ ? roleUsers.map(
23
+ (user: IUser, i: number) => i < 5 && <Avatar image={user.image?.thumb} name={user.name} size="s" key={i} />
24
+ )
25
+ : [];
26
+
27
+ const tooltipAvatarList =
28
+ isSiteView && roleUsers.length
29
+ ? roleUsers.map((user: IUser) => (
30
+ <S.AvatarContainer addSpacing={true} key={user.id}>
31
+ <Avatar image={user.image?.thumb} name={user.name} size="s" key={user.id} />
32
+ </S.AvatarContainer>
33
+ ))
34
+ : [];
35
+
36
+ const UsersTooltip = () => <S.AvatarsTooltip data-testid="avatars-tooltip">{tooltipAvatarList}</S.AvatarsTooltip>;
37
+
38
+ return (
39
+ <S.RoleRow role="rowgroup" selected={isSelected} data-testid="role-item" key={`${role.name}${role.id}`}>
40
+ <S.CheckCell role="cell">
41
+ <CheckField
42
+ name="check"
43
+ value={role.id ?? ""}
44
+ checked={isSelected}
45
+ onChange={(value: ICheck) => onChange(value)}
46
+ disabled={!role.editable}
47
+ />
48
+ </S.CheckCell>
49
+ <S.RoleCell role="cell" onClick={onClick}>
50
+ <S.Name data-testid="role-item-name">
51
+ <Tag key={role.name} text={role.name} color={role.hex} />
52
+ </S.Name>
53
+ <S.Description>{role.description}</S.Description>
54
+ </S.RoleCell>
55
+ {isSiteView && (
56
+ <S.AvatarCell
57
+ data-testid="avatar-cell"
58
+ onMouseEnter={() => setIsOpen(true)}
59
+ onMouseLeave={() => setIsOpen(false)}
60
+ onClick={onClick}
61
+ >
62
+ {roleUsers.length > 5 && isOpen && <UsersTooltip />}
63
+ <S.AvatarsWrapper>
64
+ {avatarList}
65
+ {roleUsers?.length > 5 ? (
66
+ <S.UsersLength data-testid="users-length"> +{roleUsers.length - 5}</S.UsersLength>
67
+ ) : null}
68
+ </S.AvatarsWrapper>
69
+ </S.AvatarCell>
70
+ )}
71
+ <S.Permissions isSiteView={isSiteView} onClick={onClick} data-testid="role-item-permissions">
72
+ <Tooltip content="Number of permissions of this Role">{role?.permissions?.totalPermissions}</Tooltip>
73
+ </S.Permissions>
74
+ <S.Status>
75
+ <Tooltip content={!role.editable ? "It can't be disabled because it's a main role." : undefined}>
76
+ <ToggleField
77
+ name={role?.name}
78
+ size="s"
79
+ value={role?.active}
80
+ onChange={toggleStatus}
81
+ disabled={!role.editable}
82
+ />
83
+ </Tooltip>
84
+ </S.Status>
85
+ <S.ActionsCell role="cell"></S.ActionsCell>
86
+ </S.RoleRow>
87
+ );
88
+ };
89
+
90
+ interface IRoleItemProps {
91
+ role: IRole;
92
+ users: IUser[];
93
+ isSelected: boolean;
94
+ siteId: string | number;
95
+ onChange: (value: ICheck) => void;
96
+ onClick: () => void;
97
+ activateRole(value: boolean): void;
98
+ }
99
+
100
+ const mapStateToProps = (state: IRootState) => ({
101
+ users: state.users.users,
102
+ });
103
+
104
+ export default connect(mapStateToProps)(RoleItem);
@@ -0,0 +1,127 @@
1
+ import styled from "styled-components";
2
+
3
+ import { Cell, Row } from "@ax/components/TableList/TableItem/style";
4
+
5
+ const RoleRow = styled(Row as any)<{ disabled: boolean }>``;
6
+
7
+ const CheckCell = styled(Cell)`
8
+ justify-content: flex-start;
9
+ padding-right: 0;
10
+ padding-left: ${(p) => p.theme.spacing.m};
11
+ label {
12
+ margin-bottom: ${(p) => p.theme.spacing.s};
13
+ }
14
+ > div {
15
+ width: ${(p) => p.theme.spacing.s};
16
+ }
17
+ `;
18
+
19
+ const RoleCell = styled(Cell)`
20
+ width: 400px;
21
+ flex-direction: column;
22
+ justify-content: flex-start;
23
+ `;
24
+
25
+ const Name = styled.div`
26
+ ${(p) => p.theme.textStyle.uiL};
27
+ color: ${(p) => p.theme.colors.textHighEmphasis};
28
+ `;
29
+
30
+ const Description = styled.div`
31
+ ${(p) => p.theme.textStyle.uiXS};
32
+ color: ${(p) => p.theme.colors.textMediumEmphasis};
33
+ width: 400px;
34
+ `;
35
+
36
+ const AvatarCell = styled(Cell)`
37
+ position: relative;
38
+ align-items: center;
39
+ justify-content: center;
40
+ width: 10%;
41
+ `;
42
+
43
+ const UsersLength = styled.span`
44
+ ${(p) => p.theme.textStyle.uiS};
45
+ position: absolute;
46
+ left: 110px;
47
+ `;
48
+
49
+ const AvatarsWrapper = styled.div`
50
+ display: flex;
51
+ align-items: center;
52
+ position: relative;
53
+
54
+ div {
55
+ position: absolute;
56
+ &:nth-child(1) {
57
+ position: absolute;
58
+ z-index: 5;
59
+ }
60
+ &:nth-child(2) {
61
+ position: absolute;
62
+ z-index: 4;
63
+ left: 20px;
64
+ }
65
+ &:nth-child(3) {
66
+ position: absolute;
67
+ z-index: 3;
68
+ left: 40px;
69
+ }
70
+ &:nth-child(4) {
71
+ position: absolute;
72
+ z-index: 2;
73
+ left: 60px;
74
+ }
75
+ &:nth-child(5) {
76
+ position: absolute;
77
+ z-index: 1;
78
+ left: 80px;
79
+ }
80
+ }
81
+ `;
82
+
83
+ const Status = styled(Cell)`
84
+ display: flex;
85
+ justify-content: center;
86
+ `;
87
+
88
+ const Permissions = styled(Cell)<{ isSiteView: boolean }>`
89
+ text-align: center;
90
+ flex-grow: 1;
91
+ `;
92
+
93
+ const AvatarsTooltip = styled.div`
94
+ position: absolute;
95
+ display: flex;
96
+ flex-wrap: wrap;
97
+ width: 224px;
98
+ border-radius: ${(p) => p.theme.radii.s};
99
+ padding: ${(p) => p.theme.spacing.s};
100
+ box-shadow: ${(p) => p.theme.shadow.shadowL};
101
+ z-index: 6;
102
+ background: ${(p) => p.theme.color.uiBackground02};
103
+ top: 60%;
104
+ left: 50%;
105
+ `;
106
+
107
+ const AvatarContainer = styled.div<{ addSpacing: boolean }>`
108
+ padding: ${(p) => (p.addSpacing ? p.theme.spacing.xxs : 0)};
109
+ `;
110
+
111
+ const ActionsCell = styled(Cell)``;
112
+
113
+ export {
114
+ CheckCell,
115
+ RoleCell,
116
+ Name,
117
+ Description,
118
+ RoleRow,
119
+ Status,
120
+ Permissions,
121
+ UsersLength,
122
+ AvatarCell,
123
+ AvatarsWrapper,
124
+ AvatarsTooltip,
125
+ AvatarContainer,
126
+ ActionsCell,
127
+ };