@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
@@ -129,10 +129,11 @@ const Separator = styled.div`
129
129
  margin-left: ${(p) => p.theme.spacing.m};
130
130
  `;
131
131
 
132
- const IconStatusWrapper = styled.div`
132
+ const IconStatusWrapper = styled.div<{ last: boolean }>`
133
133
  position: relative;
134
134
  height: ${(p) => p.theme.spacing.m};
135
135
  cursor: pointer;
136
+ margin-right: ${(p) => (p.last ? p.theme.spacing.xs : "0")};
136
137
  `;
137
138
 
138
139
  const Header = styled.section<{ inversed?: boolean }>`
@@ -30,7 +30,7 @@ export const ModalOverlay = styled.div`
30
30
  position: fixed;
31
31
  top: 0;
32
32
  left: 0;
33
- z-index: 1240;
33
+ z-index: 1250;
34
34
  width: 100vw;
35
35
  height: 100vh;
36
36
  background: ${(p) => p.theme.color.overlay};
@@ -77,7 +77,7 @@ export const ModalHeader = styled.div`
77
77
  export const ModalContent = styled.div<{ overflow: string | undefined }>`
78
78
  position: relative;
79
79
  flex-grow: 1;
80
- overflow-y: ${(p) => p.overflow};
80
+ overflow: ${(p) => p.overflow};
81
81
  `;
82
82
 
83
83
  export const Title = styled.div`
@@ -3,6 +3,7 @@ import { NavLink } from "react-router-dom";
3
3
 
4
4
  import { SubNav, MenuItem } from "@ax/components";
5
5
  import { INavItem } from "@ax/types";
6
+ import { Restricted } from "@ax/guards";
6
7
 
7
8
  import * as S from "./style";
8
9
 
@@ -16,8 +17,9 @@ const Nav = (props: INavProps): JSX.Element => {
16
17
  const isSelected = (current && item.title === current.title) || false;
17
18
  const selectedClass = isSelected ? "selected" : "";
18
19
  const handleClick = () => onClick(item.path);
19
- return (
20
- <MenuItem key={key} onClick={handleClick}>
20
+
21
+ const menuItem = (
22
+ <MenuItem onClick={handleClick} key={key}>
21
23
  <NavLink to="#" className={selectedClass}>
22
24
  <S.Link active={isSelected} data-testid="nav-link">
23
25
  {item.title}
@@ -25,6 +27,14 @@ const Nav = (props: INavProps): JSX.Element => {
25
27
  </NavLink>
26
28
  </MenuItem>
27
29
  );
30
+
31
+ return item.permission ? (
32
+ <Restricted to={item.permission} key={key}>
33
+ {menuItem}
34
+ </Restricted>
35
+ ) : (
36
+ menuItem
37
+ );
28
38
  })}
29
39
  </SubNav>
30
40
  );
@@ -116,7 +116,7 @@ const PageFinder = (props: IPageFinderProps): JSX.Element => {
116
116
  const getAndSetContentTypes = async () => {
117
117
  const { site, lang } = state;
118
118
  const { data } = await structuredData.getContentTypes(site, lang);
119
- const contentTypes = data.items.map((type: IContentType) => ({ label: type.title, value: type.id }));
119
+ const contentTypes = data.items ? data.items.map((type: IContentType) => ({ label: type.title, value: type.id })) : [];
120
120
  changeContentTypeOptions(contentTypes);
121
121
  changeState("type", "all");
122
122
  };
@@ -256,7 +256,7 @@ const PageFinder = (props: IPageFinderProps): JSX.Element => {
256
256
 
257
257
  interface IPageFinderProps {
258
258
  onClick: (value: IPage | IPage[]) => void;
259
- currentSiteID: number;
259
+ currentSiteID: number | null;
260
260
  isOpen: boolean;
261
261
  allSites: ISite[];
262
262
  lang: { locale: string; id: number };
@@ -14,6 +14,7 @@ const SearchField = (props: ISearchFieldProps): JSX.Element => {
14
14
  searchFilters,
15
15
  onFilterChange,
16
16
  small,
17
+ autoFocus = true,
17
18
  size = "M",
18
19
  } = props;
19
20
 
@@ -59,13 +60,6 @@ const SearchField = (props: ISearchFieldProps): JSX.Element => {
59
60
  };
60
61
 
61
62
  const showField = isOpen || !closeOnInactive;
62
- const inputRef: any = useRef(null);
63
-
64
- useEffect(() => {
65
- if (inputRef.current && showField) {
66
- inputRef.current.focus();
67
- }
68
- }, [showField]);
69
63
 
70
64
  return (
71
65
  <S.Wrapper data-testid="search-field-wrapper">
@@ -87,7 +81,6 @@ const SearchField = (props: ISearchFieldProps): JSX.Element => {
87
81
  </>
88
82
  )}
89
83
  <S.Input
90
- ref={inputRef}
91
84
  type="text"
92
85
  value={inputValue}
93
86
  onChange={handleChange}
@@ -97,6 +90,7 @@ const SearchField = (props: ISearchFieldProps): JSX.Element => {
97
90
  disabled={disabled}
98
91
  data-testid="search-input"
99
92
  small={small}
93
+ autoFocus={autoFocus && showField}
100
94
  inputSize={size}
101
95
  />
102
96
  {inputValue.trim() !== "" && searchOnEnter && <S.HelpText>Press ENTER</S.HelpText>}
@@ -128,6 +122,7 @@ export interface ISearchFieldProps {
128
122
  searchFilters?: any;
129
123
  onFilterChange?(filter: string): void;
130
124
  small?: boolean;
125
+ autoFocus?: boolean;
131
126
  size?: "M" | "S" | "XS";
132
127
  }
133
128
 
@@ -0,0 +1,50 @@
1
+ import React from "react";
2
+
3
+ import { Icon, FloatingMenu, ListTitle, ListItem } from "@ax/components";
4
+
5
+ import * as S from "./style";
6
+
7
+ const PermissionsFilter = ({ sortItems, sortedState }: IPermissionsHeaderProps): JSX.Element => {
8
+ const { isAscending, sortedByPermissions } = sortedState;
9
+ const sortAscendingPermissions = () => sortItems("permissions", true);
10
+ const sortDescendingPermissions = () => sortItems("permissions", false);
11
+
12
+ const SortedStateArrow = () =>
13
+ isAscending ? <Icon name="FullArrowUp" size="16" /> : <Icon name="FullArrowDown" size="16" />;
14
+
15
+ const Header = () => (
16
+ <S.PermissionsHeader isActive={sortedByPermissions}>
17
+ Permissions
18
+ <S.IconsWrapper>
19
+ {sortedByPermissions && <SortedStateArrow />}
20
+ <S.InteractiveArrow>
21
+ <Icon name="DownArrow" size="16" />
22
+ </S.InteractiveArrow>
23
+ </S.IconsWrapper>
24
+ </S.PermissionsHeader>
25
+ );
26
+
27
+ const SortedMenu = () => (
28
+ <FloatingMenu Button={Header} position="left">
29
+ <ListTitle>Permissions Sorting</ListTitle>
30
+ <ListItem isSelected={sortedByPermissions && isAscending} onClick={sortAscendingPermissions}>
31
+ Ascendent
32
+ </ListItem>
33
+ <ListItem isSelected={sortedByPermissions && !isAscending} onClick={sortDescendingPermissions}>
34
+ Descendent
35
+ </ListItem>
36
+ </FloatingMenu>
37
+ );
38
+
39
+ return <SortedMenu />;
40
+ };
41
+
42
+ interface IPermissionsHeaderProps {
43
+ sortedState: {
44
+ isAscending: boolean;
45
+ sortedByPermissions: boolean;
46
+ };
47
+ sortItems(orderPointer: string, isAscendent: boolean): void;
48
+ }
49
+
50
+ export default PermissionsFilter;
@@ -1,8 +1,12 @@
1
1
  import styled from "styled-components";
2
2
  import { Header } from "@ax/components/TableList/style";
3
3
 
4
- const NameHeader = styled(Header)<{ isActive: boolean }>`
4
+ const PermissionsHeader = styled(Header)<{ isActive: boolean }>`
5
5
  width: 100%;
6
+ padding: 0;
7
+ display: flex;
8
+ justify-content: center;
9
+
6
10
  &:hover {
7
11
  color: ${(p) => p.theme.color.interactive01};
8
12
  }
@@ -26,4 +30,4 @@ const InteractiveArrow = styled.div`
26
30
  }
27
31
  `;
28
32
 
29
- export { NameHeader, IconsWrapper, InteractiveArrow };
33
+ export { PermissionsHeader, IconsWrapper, InteractiveArrow };
@@ -0,0 +1,61 @@
1
+ import React, { useLayoutEffect, useState } from "react";
2
+
3
+ import { CheckGroup, FloatingMenu, Icon, ListTitle } from "@ax/components";
4
+ import { areEquals } from "@ax/helpers";
5
+ import { IFilterValue } from "@ax/types";
6
+
7
+ import * as S from "./style";
8
+
9
+ const RoleFilter = (props: IRoleFilterProps): JSX.Element => {
10
+ const { filterItems, value, pointer, center = true, label = "Roles", selectAllOption = "all", filters } = props;
11
+
12
+ const initialState = [selectAllOption];
13
+ const [selectedValue, setSelectedValue] = useState([selectAllOption]);
14
+
15
+ useLayoutEffect(() => {
16
+ const storedValue = value && value[pointer] ? value[pointer].split(",") : [];
17
+ setSelectedValue(storedValue);
18
+ // eslint-disable-next-line react-hooks/exhaustive-deps
19
+ }, [value]);
20
+
21
+ const setQuery = (selection: any) => {
22
+ if (!selection.length) {
23
+ selection = initialState;
24
+ }
25
+ setSelectedValue(selection);
26
+ const queryFilters = selection.join(",");
27
+ filterItems(pointer, queryFilters);
28
+ };
29
+
30
+ const isActive = !areEquals(selectedValue, initialState);
31
+
32
+ const Header = () => (
33
+ <S.Wrapper isActive={isActive} center={center}>
34
+ {label}
35
+ <S.IconsWrapper>
36
+ {isActive ? <Icon name="Filter" size="16" /> : <Icon name="DownArrow" size="16" />}
37
+ </S.IconsWrapper>
38
+ </S.Wrapper>
39
+ );
40
+
41
+ return (
42
+ <FloatingMenu Button={Header} position="left" closeOnSelect={false} isCheckGroup={true}>
43
+ <ListTitle>Filter by Role</ListTitle>
44
+ <S.ChecksWrapper>
45
+ <CheckGroup options={filters} value={selectedValue} onChange={setQuery} selectAllOption={selectAllOption} />
46
+ </S.ChecksWrapper>
47
+ </FloatingMenu>
48
+ );
49
+ };
50
+
51
+ export interface IRoleFilterProps {
52
+ filterItems(pointer: string, filter: string): void;
53
+ value: any;
54
+ pointer: string;
55
+ center?: boolean;
56
+ label?: string;
57
+ selectAllOption?: string;
58
+ filters?: IFilterValue[];
59
+ }
60
+
61
+ export default RoleFilter;
@@ -0,0 +1,28 @@
1
+ import React from "react";
2
+ import styled from "styled-components";
3
+ import { Header } from "@ax/components/TableList/style";
4
+
5
+ const Wrapper = styled((props) => <Header {...props} />)<{ isActive: boolean; center: boolean }>`
6
+ width: 275px;
7
+ justify-content: ${(p) => (p.center ? "center" : "flex-start")};
8
+ &:hover {
9
+ color: ${(p) => p.theme.color.interactive01};
10
+ }
11
+ `;
12
+
13
+ const IconsWrapper = styled.div`
14
+ display: flex;
15
+ align-items: center;
16
+ flex-direction: row;
17
+ svg {
18
+ margin-left: 4px;
19
+ }
20
+ `;
21
+
22
+ const ChecksWrapper = styled.div`
23
+ padding: ${(p) => p.theme.spacing.xs} ${(p) => p.theme.spacing.s};
24
+ height: calc(${(p) => p.theme.spacing.xl} * 3);
25
+ overflow-y: scroll;
26
+ `;
27
+
28
+ export { Wrapper, IconsWrapper, ChecksWrapper };
@@ -0,0 +1,55 @@
1
+ import React from "react";
2
+
3
+ import { Icon, FloatingMenu, ListTitle, ListItem } from "@ax/components";
4
+
5
+ import * as S from "./style";
6
+
7
+ const UsersFilter = (props: IUsersFilterProps): JSX.Element => {
8
+ const { sortItems, sortedState } = props;
9
+ const { isAscending, sortedByUsers } = sortedState;
10
+
11
+ const sortByUsers = (isAscending: boolean) => sortItems('users', isAscending);
12
+ const sortAscendingUsers = () => sortByUsers(true);
13
+ const sortDescendingUsers = () => sortByUsers(false);
14
+
15
+ const SortedStateArrow = () =>
16
+ isAscending ? <Icon name="FullArrowUp" size="16" /> : <Icon name="FullArrowDown" size="16" />;
17
+
18
+ const isActive = sortedByUsers;
19
+ const title = 'Users';
20
+
21
+ const Header = () => (
22
+ <S.UsersHeader isActive={isActive} data-testid="users-filter-header">
23
+ {title}
24
+ <S.IconsWrapper>
25
+ {isActive ? (
26
+ <SortedStateArrow />
27
+ ) : (
28
+ <S.InteractiveArrow data-testid="users-filter-interactive-arrow">
29
+ <Icon name="DownArrow" size="16" />
30
+ </S.InteractiveArrow>
31
+ )}
32
+ </S.IconsWrapper>
33
+ </S.UsersHeader>
34
+ );
35
+
36
+ return (
37
+ <FloatingMenu Button={Header} position="left">
38
+ <ListTitle>Number of users</ListTitle>
39
+ <ListItem isSelected={sortedByUsers && isAscending} onClick={sortAscendingUsers}>
40
+ Ascendent
41
+ </ListItem>
42
+ <ListItem isSelected={sortedByUsers && !isAscending} onClick={sortDescendingUsers}>
43
+ Descendent
44
+ </ListItem>
45
+ </FloatingMenu>
46
+ );
47
+ };
48
+
49
+ export interface IUsersFilterProps {
50
+ sortedState: any;
51
+ sortItems(orderPointer: string, isAscendent: boolean): void;
52
+ pointer?: string;
53
+ }
54
+
55
+ export default UsersFilter;
@@ -0,0 +1,31 @@
1
+ import React from "react";
2
+ import styled from "styled-components";
3
+ import { Header } from "@ax/components/TableList/style";
4
+
5
+ const UsersHeader = styled((props) => <Header {...props} />)<{ isActive: boolean }>`
6
+ width: 100%;
7
+ min-width: 88px;
8
+ &:hover {
9
+ color: ${(p) => p.theme.color.interactive01};
10
+ }
11
+ `;
12
+
13
+ const IconsWrapper = styled.div`
14
+ display: flex;
15
+ align-items: center;
16
+ flex-direction: row;
17
+ svg {
18
+ margin-left: 4px;
19
+ }
20
+ `;
21
+
22
+ const InteractiveArrow = styled.div`
23
+ display: flex;
24
+ svg {
25
+ path {
26
+ fill: ${(p) => p.theme.color.interactive01};
27
+ }
28
+ }
29
+ `;
30
+
31
+ export { UsersHeader, IconsWrapper, InteractiveArrow };
@@ -10,6 +10,9 @@ import DateFilter from "./DateFilter";
10
10
  import CheckGroupFilter from "./CheckGroupFilter";
11
11
  import StateFilter from "./StateFilter";
12
12
  import LastAccessFilter from "./LastAccessFilter";
13
+ import PermissionsFilter from "./PermissionsFilter";
14
+ import UsersFilter from "./UsersFilter";
15
+ import RoleFilter from "./RoleFilter";
13
16
 
14
17
  export {
15
18
  CategoryFilter,
@@ -24,4 +27,7 @@ export {
24
27
  CheckGroupFilter,
25
28
  StateFilter,
26
29
  LastAccessFilter,
30
+ PermissionsFilter,
31
+ UsersFilter,
32
+ RoleFilter,
27
33
  };
@@ -24,13 +24,13 @@ export const Row = styled.div<{ selected: boolean; global?: boolean }>`
24
24
  display: flex;
25
25
  flex-flow: row;
26
26
  border: 1px solid ${(p) => p.theme.color.uiLine};
27
- border-radius: 4px;
27
+ border-radius: ${(p) => p.theme.radii.s};
28
28
  margin-bottom: ${(p) => p.theme.spacing.xs};
29
29
  cursor: pointer;
30
30
  :before {
31
31
  content: "";
32
32
  background-color: ${(p) => (p.selected ? p.theme.color.overlayPressedPrimary : `transparent`)};
33
- border-radius: 4px;
33
+ border-radius: ${(p) => p.theme.radii.s};
34
34
  position: absolute;
35
35
  top: 0;
36
36
  left: 0;
@@ -18,7 +18,7 @@ const TableHeader = styled.div<{hasFixedHeader?: boolean}>`
18
18
  width: 100%;
19
19
  position: relative; /* fallback */
20
20
  position: ${(p) => p.hasFixedHeader ? `sticky` : `relative`};
21
- z-index: 1;
21
+ z-index: 6;
22
22
  top: 0;
23
23
  background: ${(p) => p.theme.color.uiBackground01};
24
24
  `;
@@ -45,9 +45,12 @@ import {
45
45
  TranslationsFilter,
46
46
  TypeFilter,
47
47
  DateFilter,
48
+ LastAccessFilter,
49
+ PermissionsFilter,
50
+ UsersFilter,
51
+ RoleFilter,
48
52
  CheckGroupFilter,
49
53
  StateFilter,
50
- LastAccessFilter,
51
54
  } from "./TableFilters";
52
55
 
53
56
  import ActionMenu from "./ActionMenu";
@@ -151,6 +154,9 @@ export {
151
154
  TypeFilter,
152
155
  StateFilter,
153
156
  LastAccessFilter,
157
+ PermissionsFilter,
158
+ UsersFilter,
159
+ RoleFilter,
154
160
  // Components
155
161
  ActionMenu,
156
162
  Avatar,
@@ -196,13 +196,13 @@ function getGlobalSettings(): (dispatch: Dispatch) => Promise<void> {
196
196
  try {
197
197
  const response: { status: number; data: any } = await global.getSettings();
198
198
 
199
- if (isReqOk(response.status)) {
199
+ if (isReqOk(response?.status)) {
200
200
  dispatch(setGlobalSettings(response.data));
201
201
  } else {
202
- console.log("Error en getSettings"); // TODO: capturar errores mejor
202
+ console.log("Error en getSettings");
203
203
  }
204
204
  } catch (e) {
205
- console.log(e); // TODO: capturar error bien
205
+ console.log(e);
206
206
  }
207
207
  };
208
208
  }
@@ -34,7 +34,8 @@ import {
34
34
  import { appActions } from "@ax/containers/App";
35
35
  import { navigationActions } from "@ax/containers/Navigation";
36
36
  import { structuredDataActions } from "@ax/containers/StructuredData";
37
- import { setCurrentSiteErrorPages } from "@ax/containers/Sites/actions";
37
+ import { sitesActions } from "@ax/containers/Sites";
38
+ import { usersActions } from "@ax/containers/Users";
38
39
  import { pages, sites, structuredData } from "@ax/api";
39
40
  import {
40
41
  getDefaultPageNavigation,
@@ -76,6 +77,7 @@ import {
76
77
  IUserEditing,
77
78
  IStructuredDataContent,
78
79
  INotification,
80
+ IPageLanguage,
79
81
  } from "@ax/types";
80
82
  import {
81
83
  ISetBreadcrumb,
@@ -207,29 +209,20 @@ function setTranslatedParent(): (dispatch: Dispatch, getState: any) => void {
207
209
  try {
208
210
  const {
209
211
  app: { lang },
210
- pageEditor: {
211
- selectedEditorID,
212
- editorContent: { parent, site, entity, language },
213
- },
212
+ pageEditor: { editorContent },
214
213
  } = getState();
215
214
 
216
- const responseActions = {
217
- handleSuccess: (data: any) => {
218
- const { items } = data;
219
- const translatedParent = items.filter(
220
- (item: any) => (item.languageId === lang.id && language !== lang.id && item.pageId) || null
221
- );
222
- const translatedParentId = translatedParent && translatedParent[0] ? translatedParent[0].pageId : null;
223
- updateEditorContent(selectedEditorID, "parent", translatedParentId)(dispatch, getState);
224
- },
225
- handleError: (response: any) => handleError(response)(dispatch),
226
- };
215
+ const { language, pageLanguages } = editorContent;
227
216
 
228
- const callback = async () => pages.getPageLanguages(parent, site, entity);
217
+ const translatedParent = pageLanguages.find(
218
+ (item: IPageLanguage) => (item.languageId !== lang.id && language !== lang.id && item.pageId) || null
219
+ );
220
+ const translatedParentId = translatedParent ? translatedParent.pageId : null;
221
+ const updatedContent = { ...editorContent, parent: translatedParentId };
229
222
 
230
- await handleRequest(callback, responseActions, [])(dispatch);
223
+ dispatch(setEditorContent(updatedContent));
231
224
  } catch (e) {
232
- console.log(e); // TODO: capturar error bien
225
+ console.log(e);
233
226
  }
234
227
  };
235
228
  }
@@ -591,7 +584,7 @@ function updatePageStatus(
591
584
  if (errors.length) pagesWithErrors.push(page.id);
592
585
  });
593
586
 
594
- dispatch(setCurrentSiteErrorPages(pagesWithErrors));
587
+ dispatch(sitesActions.setCurrentSiteErrorPages(pagesWithErrors));
595
588
  }
596
589
 
597
590
  const validIds = ids.filter((id) => !pagesWithErrors.includes(id));
@@ -1265,6 +1258,7 @@ function getGlobalFromLocalPage(): (dispatch: Dispatch, getState: any) => Promis
1265
1258
  dispatch(setSitePageID(currentPageID));
1266
1259
  dispatch(setCurrentPageID(originalGlobalPage));
1267
1260
  structuredDataActions.setSelectedStructuredData(structuredData, "global")(dispatch, getState);
1261
+ usersActions.getUserCurrentPermissions()(dispatch, getState);
1268
1262
  } catch (e) {
1269
1263
  console.log(e);
1270
1264
  }
@@ -30,6 +30,7 @@ function setTotalImports(totalImports: number): ISetTotalImports {
30
30
  function getRedirects(params: any, filters?: string): (dispatch: any) => Promise<void> {
31
31
  return async (dispatch) => {
32
32
  try {
33
+ dispatch(setRedirects([]));
33
34
  const callback = async () => redirects.getRedirects(params, filters);
34
35
 
35
36
  const responseActions = {
@@ -56,7 +56,7 @@ const { setIsLoading, setIsSaving, setLanguage } = appActions;
56
56
  const { resetDefaultsValues } = navigationActions;
57
57
  const { resetMenuValues } = menuActions;
58
58
  const { getAnalytics } = analyticsActions;
59
- const { getUsers } = usersActions;
59
+ const { getUsers, getUserCurrentPermissions, getRoles } = usersActions;
60
60
 
61
61
  function setSites(sitesList: ISite[]): ISetSitesAction {
62
62
  return { type: SET_SITES, payload: { sites: sitesList } };
@@ -74,7 +74,7 @@ function setSitesByLang(sitesList: ISite[]): ISetSitesByLangAction {
74
74
  return { type: SET_SITES_BY_LANG, payload: { sitesByLang: sitesList } };
75
75
  }
76
76
 
77
- function setCurrentSiteInfo(currentSiteInfo: ISite): ISetCurrentSiteInfoAction {
77
+ function setCurrentSiteInfo(currentSiteInfo: ISite | null): ISetCurrentSiteInfoAction {
78
78
  return { type: SET_CURRENT_SITE_INFO, payload: { currentSiteInfo } };
79
79
  }
80
80
 
@@ -210,8 +210,10 @@ function setSiteInfo(currentSiteInfo: ISite): (dispatch: any, getState: any) =>
210
210
 
211
211
  dispatch(setIsLoading(true));
212
212
 
213
- resetSiteValues(dispatch);
213
+ resetSiteValues(currentSiteInfo.id)(dispatch);
214
+ dispatch(structuredDataActions.resetStructuredData());
214
215
  dispatch(setCurrentSiteInfo(currentSiteInfo));
216
+ await getRoles({ siteId: currentSiteInfo.id }, undefined, false)(dispatch);
215
217
 
216
218
  // get site languages
217
219
  const response: any = await languages.getSiteLanguages(currentSiteInfo.id);
@@ -275,6 +277,9 @@ function setSiteInfo(currentSiteInfo: ISite): (dispatch: any, getState: any) =>
275
277
  } else {
276
278
  console.log("Error en sites getAnalytics"); // FIXME: capturar errores mejor
277
279
  }
280
+
281
+ getUserCurrentPermissions()(dispatch, getState);
282
+
278
283
  } catch (e) {
279
284
  console.log(e); // FIXME: capturar errores
280
285
  }
@@ -442,14 +447,16 @@ function unpublishSitesBulk(ids: number[], params?: IGetSitesParams): (dispatch:
442
447
  };
443
448
  }
444
449
 
445
- const resetSiteValues = (dispatch: Dispatch) => {
446
- dispatch(setFilter("unique-pages"));
447
- resetDefaultsValues()(dispatch);
448
- resetPageEditor()(dispatch);
449
- resetMenuValues(dispatch);
450
- dispatch(setCurrentSitePages([]));
451
- dispatch(setTotalItems(0));
452
- getAnalytics()(dispatch);
450
+ function resetSiteValues(siteID: number): (dispatch: Dispatch) => void {
451
+ return async (dispatch) => {
452
+ dispatch(setFilter("unique-pages"));
453
+ resetDefaultsValues()(dispatch);
454
+ resetPageEditor()(dispatch);
455
+ resetMenuValues(dispatch);
456
+ dispatch(setCurrentSitePages([]));
457
+ dispatch(setTotalItems(0));
458
+ getAnalytics(siteID)(dispatch);
459
+ }
453
460
  };
454
461
 
455
462
  function saveCurrentSiteInfo(): (dispatch: Dispatch, getState: any) => Promise<void> {
@@ -460,6 +467,7 @@ function saveCurrentSiteInfo(): (dispatch: Dispatch, getState: any) => Promise<v
460
467
  } = getState();
461
468
 
462
469
  dispatch(setSavedSiteInfo(currentSiteInfo));
470
+ dispatch(setCurrentSiteInfo(null));
463
471
  } catch (e) {
464
472
  console.log(e);
465
473
  }
@@ -505,13 +513,13 @@ function importPageFromGlobal(pageID: number | number[]): (dispatch: any, getSta
505
513
  };
506
514
  }
507
515
 
508
- function removeUsersBulk(siteId: number, users: number[]): (dispatch: Dispatch, getState: any) => Promise<void> {
509
- return async (dispatch, getState) => {
516
+ function removeUsersBulk(siteId: number, users: number[]): (dispatch: Dispatch) => Promise<void> {
517
+ return async (dispatch) => {
510
518
  try {
511
519
  const response = await sites.removeUsersBulk(siteId, users);
512
520
  if (isReqOk(response.status)) {
513
521
  const params = { filterQuery: "?order=dateCreated" };
514
- getUsers(params)(dispatch);
522
+ getUsers(params, siteId)(dispatch);
515
523
  }
516
524
  } catch (e) {
517
525
  console.log(e); // TODO: capturar error bien
@@ -12,7 +12,7 @@ import {
12
12
  SET_CURRENT_SITE_ERROR_PAGES,
13
13
  SET_CONTENT_FILTERS,
14
14
  SET_SITES_TOTAL_ITEMS,
15
- SET_CONFIG
15
+ SET_CONFIG,
16
16
  } from "./constants";
17
17
  import { ISite, ISiteListConfig } from "@ax/types";
18
18
 
@@ -43,7 +43,7 @@ export interface ISetSitesByLangAction {
43
43
 
44
44
  export interface ISetCurrentSiteInfoAction {
45
45
  type: typeof SET_CURRENT_SITE_INFO;
46
- payload: { currentSiteInfo: ISite };
46
+ payload: { currentSiteInfo: ISite | null };
47
47
  }
48
48
 
49
49
  export interface ISetCurrentSitePagesAction {
@@ -80,10 +80,10 @@ export interface ISetContentFilters {
80
80
  type: typeof SET_CONTENT_FILTERS;
81
81
  payload: { contentFilters: Record<string, string> | null };
82
82
  }
83
+
83
84
  export interface ISetConfig {
84
85
  type: typeof SET_CONFIG;
85
86
  payload: { config: ISiteListConfig };
86
87
  }
87
88
 
88
89
  export type SitesActionsCreators = ISetSitesAction & ISetCurrentSiteInfoAction;
89
-