@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,17 +2,17 @@ import { useState } from "react";
2
2
  import { IUsersQueryValues } from "@ax/types";
3
3
 
4
4
  const useSortedListStatus = () => {
5
- const sortedInitialState: {isAscending: boolean; sortedByName: boolean; sortedByDateCreated: boolean;} = {
5
+ const sortedInitialState: { isAscending: boolean; sortedByName: boolean; sortedByDateCreated: boolean } = {
6
6
  isAscending: false,
7
7
  sortedByName: false,
8
- sortedByDateCreated: true
8
+ sortedByDateCreated: true,
9
9
  };
10
10
 
11
- const [ sortedListStatus, setSortedListStatus ] = useState(sortedInitialState);
11
+ const [sortedListStatus, setSortedListStatus] = useState(sortedInitialState);
12
12
 
13
13
  return {
14
14
  sortedListStatus,
15
- setSortedListStatus
15
+ setSortedListStatus,
16
16
  };
17
17
  };
18
18
 
@@ -20,34 +20,39 @@ const useFilterQuery = (): IUseFilterQuery => {
20
20
  const initialQueryValues = {
21
21
  order: "",
22
22
  filterSites: "noFilter",
23
+ filterRoles: "all",
23
24
  };
24
25
 
25
26
  const [query, setQuery] = useState(initialQueryValues);
26
27
 
27
28
  const setFilterQuery = (filterValues: IUsersQueryValues) => {
28
- const { order, filterSites } = filterValues;
29
+ const { order, filterSites, filterRoles } = filterValues;
30
+
31
+ const filterRolesValue = filterRoles === "all" ? "" : filterRoles;
29
32
  let filterQuery = "";
30
33
 
31
34
  const currentQuery = (pointer: string, values: string) => {
32
35
  return filterQuery ? filterQuery.concat(`&${pointer}=${values}`) : `?${pointer}=${values}`;
33
36
  };
34
37
 
35
- const isNotInitialValue = (pointer: keyof IUsersQueryValues ) => {
38
+ const isNotInitialValue = (pointer: keyof IUsersQueryValues) => {
36
39
  return filterValues[pointer] && initialQueryValues[pointer] !== filterValues[pointer];
37
40
  };
38
41
 
39
42
  if (isNotInitialValue("order")) filterQuery = currentQuery("order", order);
40
43
  if (isNotInitialValue("filterSites")) filterQuery = currentQuery("filterSites", filterSites);
44
+ if (isNotInitialValue("filterRoles")) filterQuery = currentQuery("filterRoles", filterRolesValue);
41
45
 
42
46
  return filterQuery;
43
47
  };
44
48
 
45
49
  const setFiltersSelection = (pointer: string, filter: string, isAscendent?: boolean) => {
46
- const { order, filterSites } = query;
50
+ const { order, filterSites, filterRoles } = query;
47
51
  const orderMethod = isAscendent ? "asc" : "desc";
48
52
  const filterValues = {
49
53
  order: pointer === "order" ? `${filter}-${orderMethod}` : order,
50
54
  filterSites: pointer === "filterSites" ? filter : filterSites,
55
+ filterRoles: pointer === "filterRoles" ? filter : filterRoles,
51
56
  };
52
57
 
53
58
  setQuery(filterValues);
@@ -72,4 +77,4 @@ interface IUseFilterQuery {
72
77
  filterValues: IUsersQueryValues;
73
78
  }
74
79
 
75
- export { useSortedListStatus, useFilterQuery };
80
+ export { useSortedListStatus, useFilterQuery };
@@ -1,13 +1,13 @@
1
1
  import React, { useEffect, useRef, useState } from "react";
2
2
  import { connect } from "react-redux";
3
3
 
4
- import { IRootState, IUser, ISite } from "@ax/types";
5
- import { useBulkSelection, useModal } from "@ax/hooks";
4
+ import { IRootState, IUser, ISite, IGetRoles, IRole, IGetSitesParams } from "@ax/types";
5
+ import { useBulkSelection, useModal, usePermission, useToast } from "@ax/hooks";
6
6
  import { appActions } from "@ax/containers/App";
7
7
  import { usersActions } from "@ax/containers/Users";
8
8
  import { sitesActions } from "@ax/containers/Sites";
9
9
 
10
- import { MainWrapper, TableList, ErrorToast, EmptyState, Modal, Nav } from "@ax/components";
10
+ import { MainWrapper, TableList, ErrorToast, EmptyState, Modal, Nav, Toast } from "@ax/components";
11
11
 
12
12
  import BulkHeader from "./BulkHeader";
13
13
  import UserItem from "./UserItem";
@@ -16,7 +16,7 @@ import { getSortedListStatus } from "./utils";
16
16
 
17
17
  import * as S from "./style";
18
18
 
19
- const UserList = (props: IProps): JSX.Element => {
19
+ const UserList = (props: IUserListProps): JSX.Element => {
20
20
  const {
21
21
  currentSiteInfo,
22
22
  users,
@@ -29,6 +29,9 @@ const UserList = (props: IProps): JSX.Element => {
29
29
  sites,
30
30
  deleteUser,
31
31
  removeUsersBulk,
32
+ getRoles,
33
+ roles,
34
+ getSites,
32
35
  } = props;
33
36
 
34
37
  const itemsPerPage = 50;
@@ -38,24 +41,21 @@ const UserList = (props: IProps): JSX.Element => {
38
41
  const [isScrolling, setIsScrolling] = useState(false);
39
42
  const [searchQuery, setSearchQuery] = useState<string>("");
40
43
  const [currentFilterQuery, setCurrentFilterQuery] = useState("");
44
+ const [usersDeleted, setUSersDeleted] = useState(1);
41
45
 
42
46
  const { sortedListStatus, setSortedListStatus } = useSortedListStatus();
43
47
  const { setFiltersSelection, setFilterQuery, filterValues } = useFilterQuery();
48
+ const { isVisible, toggleToast, setIsVisible } = useToast();
44
49
 
45
50
  const tableRef = useRef<HTMLDivElement>(null);
46
51
  const wrapperRef = useRef<HTMLDivElement>(null);
47
52
  const isSiteView = !!currentSiteInfo;
48
53
 
49
54
  const { isOpen, toggleModal } = useModal();
50
- const filteredUsers = isSiteView
51
- ? users.filter((user: IUser) => {
52
- const { id } = currentSiteInfo;
53
- const { sites } = user;
54
- return sites.includes(parseInt(id)) || sites.includes("all");
55
- })
56
- : users;
57
55
 
58
- const usersIds = filteredUsers.map((user: any) => user.id);
56
+ const allowedToCreateUsers = usePermission("usersRoles.createUsers");
57
+
58
+ const usersIds = users.map((user: IUser) => user.id);
59
59
 
60
60
  const {
61
61
  resetBulkSelection,
@@ -70,8 +70,10 @@ const UserList = (props: IProps): JSX.Element => {
70
70
  useEffect(() => {
71
71
  const handleGetUsers = async () => {
72
72
  const query = searchQuery ? (currentFilterQuery ? `&query=${searchQuery}` : `?query=${searchQuery}`) : "";
73
- await getUsers({ filterQuery: currentFilterQuery, query });
74
- }
73
+ const currentFilterQuerySite =
74
+ isSiteView && currentFilterQuery ? `${currentFilterQuery}&site=${currentSiteInfo.id}` : currentFilterQuery;
75
+ await getUsers({ filterQuery: currentFilterQuerySite, query }, currentSiteInfo?.id);
76
+ };
75
77
  handleGetUsers();
76
78
  // eslint-disable-next-line react-hooks/exhaustive-deps
77
79
  }, [currentFilterQuery, searchQuery]);
@@ -83,6 +85,16 @@ const UserList = (props: IProps): JSX.Element => {
83
85
  // eslint-disable-next-line react-hooks/exhaustive-deps
84
86
  }, [users]);
85
87
 
88
+ useEffect(() => {
89
+ const handleRolesSites = async () => {
90
+ const siteId = isSiteView ? currentSiteInfo.id : "global";
91
+ await getRoles({ siteId });
92
+ await getSites({ pagination: false, recentSitesNumber: 0 });
93
+ };
94
+ handleRolesSites();
95
+ // eslint-disable-next-line react-hooks/exhaustive-deps
96
+ }, []);
97
+
86
98
  const handleMenuClick = (path: string) => {
87
99
  setHistoryPush(path);
88
100
  };
@@ -95,11 +107,11 @@ const UserList = (props: IProps): JSX.Element => {
95
107
 
96
108
  const onScroll = (e: any) => setIsScrolling(e.target.scrollTop > 0);
97
109
 
98
- const totalItems = filteredUsers.length;
110
+ const totalItems = users.length;
99
111
 
100
112
  const firstPageUser = (page - 1) * itemsPerPage;
101
- const pageUsers = filteredUsers.slice(firstPageUser, firstPageUser + itemsPerPage);
102
- const isEmpty = filteredUsers && filteredUsers.length === 0;
113
+ const pageUsers = users.slice(firstPageUser, firstPageUser + itemsPerPage);
114
+ const isEmpty = !users || users.length === 0;
103
115
  const BASE_URL = isSiteView ? "/sites/users" : "/users";
104
116
  const pagination = {
105
117
  setPage,
@@ -115,13 +127,17 @@ const UserList = (props: IProps): JSX.Element => {
115
127
  } else {
116
128
  deleteUser(selectedItems.all);
117
129
  }
130
+ setUSersDeleted(selectedItems.all.length);
118
131
  toggleModal();
132
+ toggleToast();
119
133
  };
120
134
 
121
- const rightButtonProps = {
122
- label: "New",
123
- action: () => setHistoryPush(`${BASE_URL}/new`),
124
- };
135
+ const rightButtonProps = allowedToCreateUsers
136
+ ? {
137
+ label: "New",
138
+ action: () => setHistoryPush(`${BASE_URL}/new`),
139
+ }
140
+ : undefined;
125
141
 
126
142
  const sortItems = async (orderPointer: string, isAscending: boolean) => {
127
143
  setPage(firstPage);
@@ -159,15 +175,28 @@ const UserList = (props: IProps): JSX.Element => {
159
175
  sortItems={sortItems}
160
176
  filterItems={filterItems}
161
177
  sortedListStatus={sortedListStatus}
178
+ roles={roles}
162
179
  />
163
180
  );
164
181
 
182
+ const suffix = usersDeleted > 1 ? "s" : "";
183
+
184
+ const toastProps = {
185
+ setIsVisible,
186
+ message: isSiteView ? `${usersDeleted} User${suffix} removed from site` : `${usersDeleted} User${suffix} deleted`,
187
+ };
188
+
189
+ const handleToggleToast = () => {
190
+ setUSersDeleted(1);
191
+ toggleToast();
192
+ };
193
+
165
194
  const mainDeleteAction = { title: isSiteView ? "Remove from this site" : "Delete Users", onClick: bulkDelete };
166
195
  const secondaryDeleteAction = { title: "Cancel", onClick: toggleModal };
167
196
 
168
197
  return (
169
198
  <MainWrapper title="Users & Roles" rightButton={rightButtonProps} searchAction={setSearchQuery}>
170
- <S.UsersWrapper ref={wrapperRef}>
199
+ <S.UsersWrapper ref={wrapperRef} data-testid="users-wrapper">
171
200
  <Nav current={currentNavItem} items={navItems} onClick={handleMenuClick} />
172
201
  <S.TableListWrapper>
173
202
  <ErrorToast />
@@ -179,7 +208,7 @@ const UserList = (props: IProps): JSX.Element => {
179
208
  tableRef={tableRef}
180
209
  >
181
210
  {isEmpty ? (
182
- <S.EmptyWrapper>
211
+ <S.EmptyWrapper data-testid="empty-wrapper">
183
212
  <EmptyState message="No users found" />
184
213
  </S.EmptyWrapper>
185
214
  ) : (
@@ -195,7 +224,9 @@ const UserList = (props: IProps): JSX.Element => {
195
224
  sites={sites}
196
225
  isSelected={isItemSelected}
197
226
  onChange={addToBulkSelection}
198
- handleClick={handleClick(user.id)}
227
+ onClick={handleClick(user.id)}
228
+ roles={roles}
229
+ toggleDeleteToast={handleToggleToast}
199
230
  />
200
231
  );
201
232
  })
@@ -211,7 +242,7 @@ const UserList = (props: IProps): JSX.Element => {
211
242
  mainAction={mainDeleteAction}
212
243
  >
213
244
  {isOpen ? (
214
- <S.ModalContent>
245
+ <S.ModalContent data-testid="user-delete-bulk-modal">
215
246
  <p>
216
247
  {isSiteView
217
248
  ? "Are you sure you want to remove these users from this site? If you remove them, these users will no longer have access to this site but they will still be able to log in. This action cannot be undone."
@@ -224,6 +255,7 @@ const UserList = (props: IProps): JSX.Element => {
224
255
  </S.ModalContent>
225
256
  ) : null}
226
257
  </Modal>
258
+ {isVisible && <Toast {...toastProps} />}
227
259
  </MainWrapper>
228
260
  );
229
261
  };
@@ -232,6 +264,7 @@ const mapStateToProps = (state: IRootState) => ({
232
264
  users: state.users.users,
233
265
  currentSiteInfo: state.sites.currentSiteInfo,
234
266
  sites: state.sites.sites,
267
+ roles: state.users.roles,
235
268
  });
236
269
 
237
270
  const mapDispatchToProps = {
@@ -241,25 +274,30 @@ const mapDispatchToProps = {
241
274
  setHistoryPush: appActions.setHistoryPush,
242
275
  deleteUser: usersActions.deleteUser,
243
276
  removeUsersBulk: sitesActions.removeUsersBulk,
277
+ getRoles: usersActions.getRoles,
278
+ getSites: sitesActions.getSites,
244
279
  };
245
280
 
246
281
  interface IDispatchProps {
247
- getUsers(params?: any): Promise<void>;
282
+ getUsers(params: any, siteID?: number | null): Promise<void>;
248
283
  getUser(id: number): Promise<void>;
249
284
  resetUserData(): void;
250
285
  setHistoryPush(route: string): void;
251
286
  deleteUser(id: number[]): Promise<boolean>;
252
287
  removeUsersBulk(siteId: number, users: number[]): void;
288
+ getRoles(params: IGetRoles): Promise<void>;
289
+ getSites(params: IGetSitesParams): Promise<void>;
253
290
  }
254
291
 
255
- interface IUserListProps {
292
+ interface IProps {
256
293
  navItems: any[];
257
294
  currentNavItem: any;
258
295
  users: IUser[];
259
- currentSiteInfo: any;
296
+ currentSiteInfo: ISite | null;
260
297
  sites: ISite[];
298
+ roles: IRole[];
261
299
  }
262
300
 
263
- type IProps = IUserListProps & IDispatchProps;
301
+ export type IUserListProps = IProps & IDispatchProps;
264
302
 
265
303
  export default connect(mapStateToProps, mapDispatchToProps)(UserList);
@@ -2,7 +2,7 @@ const getSortedListStatus = (orderPointer: string, isAscending: boolean) => {
2
2
  const sortedListStatus = {
3
3
  isAscending,
4
4
  sortedByName: orderPointer === "name",
5
- sortedByDateCreated: orderPointer === "dateCreated"
5
+ sortedByDateCreated: orderPointer === "dateCreated",
6
6
  };
7
7
 
8
8
  return sortedListStatus;
@@ -1,6 +1,7 @@
1
1
  import React from "react";
2
2
  import { Switch, Route } from "react-router-dom";
3
3
 
4
+ import Roles from "./Roles";
4
5
  import List from "./UserList";
5
6
 
6
7
  const navItems = [
@@ -8,21 +9,37 @@ const navItems = [
8
9
  title: "Users",
9
10
  path: "/users",
10
11
  component: List,
12
+ global: true,
13
+ },
14
+ {
15
+ title: "Roles",
16
+ path: "/roles",
17
+ component: Roles,
18
+ global: true,
11
19
  },
12
20
  {
13
21
  title: "Users",
14
22
  path: "/sites/users",
15
23
  component: List,
16
24
  },
25
+ {
26
+ title: "Roles",
27
+ path: "/sites/roles",
28
+ component: Roles,
29
+ },
17
30
  ];
18
31
 
19
32
  const Users = (props: any): JSX.Element => {
20
33
  const { pathname } = props.location;
21
- const currentNavItems = navItems.filter((item) => item.path === pathname);
34
+
35
+ const isSiteView = pathname.includes("sites");
36
+ const currentNavItems = navItems.filter((item) =>
37
+ isSiteView ? item.path.includes("sites") : !item.path.includes("sites")
38
+ );
22
39
 
23
40
  return (
24
41
  <Switch>
25
- {currentNavItems.map((item, index) => (
42
+ {navItems.map((item, index) => (
26
43
  <Route exact path={item.path} key={index}>
27
44
  {React.createElement(item.component, { navItems: currentNavItems, currentNavItem: item }, null)}
28
45
  </Route>
@@ -31,4 +48,4 @@ const Users = (props: any): JSX.Element => {
31
48
  );
32
49
  };
33
50
 
34
- export default Users;
51
+ export default Users;
@@ -4,33 +4,25 @@ import multisite from "./multisite";
4
4
  import site from "./site";
5
5
  import publicRoutes from "./publicRoutes";
6
6
 
7
- const privateRoutes = [
8
- ...multisite,
9
- ...site
10
- ];
7
+ const privateRoutes = [...multisite, ...site];
11
8
 
12
- const routes = [
13
- ...privateRoutes,
14
- ...publicRoutes
15
- ];
9
+ const routes = [...privateRoutes, ...publicRoutes];
16
10
  export interface IRouter {
17
11
  path: string;
18
12
  component: any;
19
13
  name: string;
20
- routesGroups?: Array<{ name: string; routes: Array<{ path: string; component: any; name: string }>; showInNav?: boolean }>;
14
+ routesGroups?: Array<{
15
+ name: string;
16
+ routes: Array<{ path: string; component: any; name: string; permission?: string }>;
17
+ showInNav?: boolean;
18
+ }>;
21
19
  showInNav?: boolean;
22
20
  icon?: string;
23
21
  hideNav?: boolean;
24
22
  onClick?: () => void;
25
23
  url?: string;
26
24
  target?: string;
25
+ permission?: string | string[];
27
26
  }
28
27
 
29
- export {
30
- privateRoutes,
31
- publicRoutes,
32
- routes,
33
- history,
34
- multisite,
35
- site
36
- };
28
+ export { privateRoutes, publicRoutes, routes, history, multisite, site };
@@ -12,21 +12,82 @@ import AnalyticsSettings from "../modules/Analytics";
12
12
  import FramePreview from "../modules/FramePreview";
13
13
 
14
14
  export default [
15
- { path: "/sites", component: Sites, name: "Sites", showInNav: true, icon: "Project" },
16
- { path: "/data", component: StructuredDataList, name: "Global Data", showInNav: true, icon: "Data" },
17
- { path: "/data/:id/editor", component: StructuredData, showInNav: false, name: "New StructuredData" },
18
- { path: "/categories", component: CategoriesList, name: "Categories", showInNav: true, icon: "Category" },
19
- { path: "/users", component: Users, name: "Users", showInNav: true, icon: "Users" },
15
+ {
16
+ path: "/sites",
17
+ component: Sites,
18
+ name: "Sites",
19
+ showInNav: true,
20
+ icon: "Project",
21
+ permission: "",
22
+ },
23
+ {
24
+ path: "/data",
25
+ component: StructuredDataList,
26
+ name: "Global Data",
27
+ showInNav: true,
28
+ icon: "Data",
29
+ permission: "global.globalData.accessToGlobalData",
30
+ },
31
+ {
32
+ path: "/data/:id/editor",
33
+ component: StructuredData,
34
+ showInNav: false,
35
+ name: "New StructuredData",
36
+ permission: "global.globalData.readGlobalData",
37
+ },
38
+ {
39
+ path: "/categories",
40
+ component: CategoriesList,
41
+ name: "Categories",
42
+ showInNav: true,
43
+ icon: "Category",
44
+ permission: "global.globalData.accessToTaxonomies",
45
+ },
46
+ {
47
+ path: "/users",
48
+ component: Users,
49
+ name: "Users",
50
+ showInNav: true,
51
+ icon: "Users",
52
+ permission: "global.usersRoles.accessToUsersRoles",
53
+ },
20
54
  { path: "/profile", component: Profile, name: "Profile", showInNav: false, icon: "User" },
21
- { path: "/users/new", component: UserCreate, name: "New User", showInNav: false },
22
- { path: "/users/edit", component: UserEdit, name: "New User", showInNav: false },
23
- { path: `/data/pages/editor`, component: Editor, name: "Page Editor", showInNav: false, hideNav: true },
55
+ {
56
+ path: "/roles",
57
+ component: Users,
58
+ name: "Roles",
59
+ showInNav: false,
60
+ permission: "global.usersRoles.accessToUsersRoles",
61
+ },
62
+ {
63
+ path: "/users/new",
64
+ component: UserCreate,
65
+ name: "New User",
66
+ showInNav: false,
67
+ permission: "global.usersRoles.createUsers",
68
+ },
69
+ {
70
+ path: "/users/edit",
71
+ component: UserEdit,
72
+ name: "New User",
73
+ showInNav: false,
74
+ permission: "global.usersRoles.editUsers",
75
+ },
76
+ {
77
+ path: `/data/pages/editor`,
78
+ component: Editor,
79
+ name: "Page Editor",
80
+ showInNav: false,
81
+ hideNav: true,
82
+ permission: "global.globalData.readGlobalData",
83
+ },
24
84
  {
25
85
  path: `/data/pages/editor/new`,
26
86
  component: Editor,
27
87
  name: "New Page Editor",
28
88
  showInNav: false,
29
89
  hideNav: true,
90
+ permission: "global.globalData.createAllGlobalData",
30
91
  },
31
92
  {
32
93
  path: `/settings`,
@@ -34,6 +95,7 @@ export default [
34
95
  name: "Settings",
35
96
  showInNav: true,
36
97
  icon: "Settings",
98
+ permission: "global.seoAnalytics.editSeoAnalyticsInGlobalPages",
37
99
  routesGroups: [
38
100
  {
39
101
  name: "Settings",
@@ -42,11 +104,13 @@ export default [
42
104
  path: `/settings/robots`,
43
105
  component: GlobalSettings,
44
106
  name: "SEO tools",
107
+ permission: "global.seoAnalytics.editSeoAnalyticsInGlobalPages",
45
108
  },
46
109
  {
47
110
  path: `/settings/analytics`,
48
111
  component: AnalyticsSettings,
49
112
  name: "Analytics tools",
113
+ permission: "global.seoAnalytics.editSeoAnalyticsInGlobalPages",
50
114
  },
51
115
  ],
52
116
  },
@@ -57,6 +121,7 @@ export default [
57
121
  component: GlobalSettings,
58
122
  name: "Settings",
59
123
  showInNav: false,
124
+ permission: "global.seoAnalytics.editSeoAnalyticsInGlobalPages",
60
125
  },
61
126
  {
62
127
  path: `/editor/page-preview`,