@griddo/ax 10.1.96 → 10.2.1

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
@@ -19,13 +19,22 @@ const SubTitle = styled.div`
19
19
  `;
20
20
 
21
21
  const ModalContent = styled.div`
22
- padding: ${p => p.theme.spacing.m};
22
+ padding: ${(p) => p.theme.spacing.m};
23
23
  `;
24
24
 
25
25
  const SettingsWrapper = styled.div`
26
26
  position: relative;
27
27
  border-top: 1px solid ${(p) => p.theme.color.uiLine};
28
28
  padding-top: ${(p) => p.theme.spacing.m};
29
+ padding-bottom: ${(p) => p.theme.spacing.s};
30
+ `;
31
+
32
+ const HeadingWrapper = styled.div`
33
+ display: flex;
34
+ align-items: center;
35
+ & button {
36
+ margin-left: auto;
37
+ }
29
38
  `;
30
39
 
31
40
  const Heading = styled.div`
@@ -35,7 +44,7 @@ const Heading = styled.div`
35
44
  `;
36
45
 
37
46
  const SettingContent = styled.div`
38
- padding-bottom: ${(p) => p.theme.spacing.m};
47
+ padding-bottom: ${(p) => p.theme.spacing.s};
39
48
  `;
40
49
 
41
50
  const SettingText = styled.div`
@@ -50,8 +59,55 @@ const SearchFieldWrapper = styled.div`
50
59
  max-width: calc(${(p) => p.theme.spacing.l} * 7);
51
60
  `;
52
61
 
53
- const SelectAllSitesFieldWrapper = styled.div`
54
- padding-bottom: ${(p) => p.theme.spacing.s};
62
+ const SelectAllSitesFieldWrapper = styled.div``;
63
+
64
+ const GlobalPermissionsFieldWrapper = styled.div`
65
+ padding-bottom: ${(p) => p.theme.spacing.m};
66
+ `;
67
+
68
+ const SiteList = styled.div`
69
+ padding-bottom: ${(p) => p.theme.spacing.xs};
70
+ & > div {
71
+ margin-bottom: 0;
72
+ border-radius: 0;
73
+ border-bottom: none;
74
+
75
+ &:first-child {
76
+ border-radius: ${(p) => `${p.theme.radii.s} ${p.theme.radii.s} 0 0`};
77
+ }
78
+ &:last-child {
79
+ border-bottom: 1px solid ${(p) => p.theme.color.uiLine};
80
+ border-radius: ${(p) => `0 0 ${p.theme.radii.s} ${p.theme.radii.s}`};
81
+ }
82
+ }
83
+ `;
84
+
85
+ const RoleList = styled.div`
86
+ border-bottom: 1px solid ${(p) => p.theme.color.uiLine};
87
+ padding-top: ${(p) => p.theme.spacing.xs};
88
+
89
+ & button {
90
+ margin-top: ${(p) => p.theme.spacing.s};
91
+ margin-bottom: ${(p) => p.theme.spacing.s};
92
+ }
93
+ `;
94
+
95
+ const MemberWrapper = styled.div``;
96
+
97
+ const OptionsWrapper = styled.div`
98
+ padding-bottom: ${(p) => p.theme.spacing.m};
99
+ `;
100
+
101
+ const Label = styled.div`
102
+ ${(p) => p.theme.textStyle.fieldLabel};
103
+ color: ${(p) => p.theme.color.textMediumEmphasis};
104
+ display: block;
105
+ margin-bottom: ${(p) => p.theme.spacing?.xs};
106
+ `;
107
+
108
+ const HelpText = styled.div`
109
+ ${(p) => p.theme.textStyle.uiXS};
110
+ color: ${(p) => p.theme.color?.textMediumEmphasis};
55
111
  `;
56
112
 
57
113
  export {
@@ -64,5 +120,13 @@ export {
64
120
  SettingContent,
65
121
  Heading,
66
122
  SearchFieldWrapper,
67
- SelectAllSitesFieldWrapper
68
- };
123
+ SelectAllSitesFieldWrapper,
124
+ SiteList,
125
+ GlobalPermissionsFieldWrapper,
126
+ RoleList,
127
+ HeadingWrapper,
128
+ Label,
129
+ HelpText,
130
+ OptionsWrapper,
131
+ MemberWrapper,
132
+ };
@@ -1,12 +1,11 @@
1
1
  import React from "react";
2
2
 
3
- import { CheckField, TableCounter, SiteFilter } from "@ax/components";
4
-
5
- import Name from "../../HeaderMenus/Name";
3
+ import { CheckField, TableCounter, SiteFilter, NameFilter, RoleFilter } from "@ax/components";
4
+ import { IRole } from "@ax/types";
6
5
 
7
6
  import * as S from "./style";
8
7
 
9
- const TableHeader = (props: IProps) => {
8
+ const TableHeader = (props: IProps): JSX.Element => {
10
9
  const {
11
10
  totalItems,
12
11
  selectAllItems,
@@ -15,9 +14,27 @@ const TableHeader = (props: IProps) => {
15
14
  filterItems,
16
15
  sortedListStatus,
17
16
  filterValues,
18
- showSiteFilter = true,
17
+ isSiteView,
18
+ roles,
19
19
  } = props;
20
20
 
21
+ const roleFilters = [
22
+ {
23
+ name: "all",
24
+ value: "all",
25
+ title: "All",
26
+ },
27
+ ];
28
+
29
+ roles.forEach((item: IRole) => {
30
+ const newFilter = {
31
+ name: item.id.toString(),
32
+ value: item.id.toString(),
33
+ title: item.name,
34
+ };
35
+ item.active && roleFilters.push(newFilter);
36
+ });
37
+
21
38
  return (
22
39
  <S.TableHeader isScrolling={isScrolling}>
23
40
  <S.CheckHeader>
@@ -32,32 +49,44 @@ const TableHeader = (props: IProps) => {
32
49
  />
33
50
  </S.CheckHeader>
34
51
  <S.NameWrapper>
35
- <Name sortItems={sortItems} sortedState={sortedListStatus} />
52
+ <NameFilter sortItems={sortItems} sortedState={sortedListStatus} pointer="name" />
36
53
  </S.NameWrapper>
37
- {showSiteFilter ? (
38
- <S.NameWrapper>
39
- <SiteFilter
40
- filterItems={filterItems}
41
- value={filterValues}
42
- pointer="filterSites"
43
- center={false}
44
- label="Sites"
45
- selectAllOption="noFilter"
46
- filters={[
47
- {
48
- name: "noFilter",
49
- value: "noFilter",
50
- title: "All",
51
- },
52
- {
53
- name: "all",
54
- value: "all",
55
- title: "Access to all sites",
56
- },
57
- ]}
58
- />
59
- </S.NameWrapper>
60
- ) : null}
54
+ <S.RolesWrapper isSite={isSiteView}>
55
+ <RoleFilter
56
+ filterItems={filterItems}
57
+ filters={roleFilters}
58
+ value={filterValues}
59
+ pointer="filterRoles"
60
+ center={false}
61
+ />
62
+ </S.RolesWrapper>
63
+ {!isSiteView && (
64
+ <>
65
+ <S.SiteWrapper>
66
+ <SiteFilter
67
+ filterItems={filterItems}
68
+ value={filterValues}
69
+ pointer="filterSites"
70
+ center={false}
71
+ label="Sites"
72
+ selectAllOption="noFilter"
73
+ filters={[
74
+ {
75
+ name: "noFilter",
76
+ value: "noFilter",
77
+ title: "All",
78
+ },
79
+ {
80
+ name: "all",
81
+ value: "all",
82
+ title: "Access to all sites",
83
+ },
84
+ ]}
85
+ />
86
+ </S.SiteWrapper>
87
+ <S.StatusHeader />
88
+ </>
89
+ )}
61
90
  <S.ActionsHeader>
62
91
  <TableCounter totalItems={totalItems} />
63
92
  </S.ActionsHeader>
@@ -68,12 +97,13 @@ const TableHeader = (props: IProps) => {
68
97
  interface IProps {
69
98
  totalItems: number;
70
99
  isScrolling: boolean;
71
- showSiteFilter: boolean;
100
+ isSiteView: boolean;
72
101
  selectAllItems: () => void;
73
102
  filterItems: (filterPointer: string, filtersSelected: string) => void;
74
103
  sortItems: any;
75
104
  sortedListStatus: any;
76
105
  filterValues: any;
106
+ roles: IRole[];
77
107
  }
78
108
 
79
109
  export default TableHeader;
@@ -9,7 +9,7 @@ const TableHeader = styled.div<{ isScrolling?: boolean }>`
9
9
  border-bottom: ${(p) => (p.isScrolling ? `1px solid ${p.theme.color.uiLine};` : "")};
10
10
  `;
11
11
 
12
- const CheckHeader = styled(Header as any)`
12
+ const CheckHeader = styled(Header)`
13
13
  padding-left: ${(p) => p.theme.spacing.m};
14
14
  width: 32px;
15
15
  `;
@@ -19,9 +19,23 @@ const NameWrapper = styled.div`
19
19
  position: relative;
20
20
  `;
21
21
 
22
- const ActionsHeader = styled(Header as any)`
23
- width: 92px;
22
+ const ActionsHeader = styled(Header)`
23
+ width: 64px;
24
24
  padding-right: 0;
25
25
  `;
26
26
 
27
- export { TableHeader, CheckHeader, NameWrapper, ActionsHeader };
27
+ const SiteWrapper = styled.div`
28
+ width: 210px;
29
+ position: relative;
30
+ `;
31
+
32
+ const RolesWrapper = styled.div<{ isSite: boolean }>`
33
+ width: ${(p) => (p.isSite ? "450px" : "275px")};
34
+ position: relative;
35
+ `;
36
+
37
+ const StatusHeader = styled(Header)`
38
+ width: 98px;
39
+ `;
40
+
41
+ export { TableHeader, CheckHeader, NameWrapper, ActionsHeader, RolesWrapper, SiteWrapper, StatusHeader };
@@ -1,5 +1,7 @@
1
1
  import React from "react";
2
2
  import { BulkSelectionOptions } from "@ax/components";
3
+ import { IRole } from "@ax/types";
4
+ import { usePermission } from "@ax/hooks";
3
5
  import TableHeader from "./TableHeader";
4
6
 
5
7
  const BulkHeader = (props: IProps): JSX.Element => {
@@ -16,15 +18,18 @@ const BulkHeader = (props: IProps): JSX.Element => {
16
18
  sortedListStatus,
17
19
  filterValues,
18
20
  isSiteView = false,
21
+ roles,
19
22
  } = props;
20
23
 
21
- const bulkActions = [
24
+ const isAllowedToRemoveUsers = usePermission("usersRoles.removeUsers");
25
+
26
+ const bulkActions = isAllowedToRemoveUsers ? [
22
27
  {
23
28
  icon: "delete",
24
29
  text: isSiteView ? "Remove from this site" : "delete",
25
30
  action: bulkDelete,
26
31
  },
27
- ];
32
+ ] : [];
28
33
 
29
34
  return showBulk ? (
30
35
  <BulkSelectionOptions
@@ -42,7 +47,8 @@ const BulkHeader = (props: IProps): JSX.Element => {
42
47
  isScrolling={isScrolling}
43
48
  sortItems={sortItems}
44
49
  sortedListStatus={sortedListStatus}
45
- showSiteFilter={!isSiteView}
50
+ isSiteView={isSiteView}
51
+ roles={roles}
46
52
  />
47
53
  );
48
54
  };
@@ -60,6 +66,7 @@ interface IProps {
60
66
  sortedListStatus: any;
61
67
  filterValues: any;
62
68
  filterItems: (filterPointer: string, filtersSelected: string) => void;
69
+ roles: IRole[];
63
70
  }
64
71
 
65
72
  export default BulkHeader;
@@ -1,45 +1,48 @@
1
- import React from "react";
1
+ import React, { useRef } from "react";
2
2
  import { connect } from "react-redux";
3
3
 
4
- import { ICheck, IUser, ISite } from "@ax/types";
5
- import { useModal, useToast } from "@ax/hooks";
4
+ import { ICheck, IUser, ISite, IRole, ISiteRoles } from "@ax/types";
5
+ import { useAdaptiveText, useModal, usePermission, useToast } from "@ax/hooks";
6
6
  import { getDaysAgo } from "@ax/helpers";
7
7
  import { usersActions } from "@ax/containers/Users";
8
8
  import { CheckField, Avatar, Modal, Tag, Tooltip, Toast, ElementsTooltip } from "@ax/components";
9
9
 
10
10
  import * as S from "./style";
11
11
 
12
- const UserItem = (props: IProps): JSX.Element => {
12
+ const UserItem = (props: IUserItemProps): JSX.Element => {
13
13
  const {
14
14
  user,
15
15
  sites,
16
16
  siteId,
17
17
  isSelected,
18
18
  onChange,
19
- handleClick,
19
+ onClick,
20
20
  deleteUser,
21
21
  updateUser,
22
22
  resendInvitation,
23
23
  isSiteView = false,
24
+ roles,
25
+ toggleDeleteToast,
24
26
  } = props;
25
27
 
26
28
  const { isOpen, toggleModal } = useModal();
27
29
  const { isVisible, toggleToast, setIsVisible } = useToast();
28
30
 
31
+ const userCellRef = useRef<HTMLDivElement>(null);
32
+ const email = useAdaptiveText(userCellRef, user.email);
33
+
34
+ const isAllowedToRemoveUsers = usePermission("usersRoles.removeUsers");
35
+
29
36
  const handleOnChange = (value: ICheck) => onChange(value);
30
- const sitesIds = sites.map((site: ISite) => site.id);
31
37
 
32
- const deleteOption = {
33
- label: isSiteView ? "remove from site" : "delete",
34
- icon: "delete",
35
- action: () => toggleModal(),
36
- };
38
+ const sitesIds = sites.map((site: ISite) => site.id);
37
39
 
38
- const handleDeleteUser = () => {
39
- if (user.id) {
40
- deleteUser(user.id);
40
+ const handleDeleteUser = async () => {
41
+ const deleted = user.id ? await deleteUser(user.id) : false;
42
+ if (deleted) {
43
+ toggleModal();
44
+ toggleDeleteToast();
41
45
  }
42
- toggleModal();
43
46
  };
44
47
 
45
48
  const handleResendInvitation = () => {
@@ -52,6 +55,20 @@ const UserItem = (props: IProps): JSX.Element => {
52
55
  }
53
56
  };
54
57
 
58
+ const handleClick = () => user.id && onClick(user.id);
59
+
60
+ const actionIsDisabled = isSiteView && user.isSuperAdmin;
61
+
62
+ const deleteOption = isAllowedToRemoveUsers
63
+ ? {
64
+ label: isSiteView ? "remove from site" : "delete",
65
+ icon: "delete",
66
+ action: () => toggleModal(),
67
+ disabled: actionIsDisabled,
68
+ helpText: actionIsDisabled ? "This is a superadmin user. You cannot remove it." : "",
69
+ }
70
+ : undefined;
71
+
55
72
  const resendOption = {
56
73
  label: "Resend invitation",
57
74
  icon: "sendEmail",
@@ -60,20 +77,37 @@ const UserItem = (props: IProps): JSX.Element => {
60
77
 
61
78
  const menuOptions = user.status === "invited" ? [resendOption, deleteOption] : [deleteOption];
62
79
 
63
- const getUpdatedSites = (currentUserSiteIds: any) =>
64
- currentUserSiteIds[0] === "all"
65
- ? sitesIds.filter((id: number) => id !== siteId)
66
- : currentUserSiteIds.filter((id: number) => id !== siteId);
80
+ const getUpdatedSites = () => {
81
+ const hasAll = user.roles.find((siteRole: ISiteRoles) => siteRole.siteId === "all");
82
+ if (hasAll) {
83
+ const oldRoleSites = user.roles.filter((siteRole: ISiteRoles) => siteRole.siteId !== "all");
84
+ const roleSites = sitesIds
85
+ .filter((site: number) => site !== siteId)
86
+ .map((siteId: number) => {
87
+ return { siteId, roles: hasAll.roles };
88
+ });
89
+ return [...oldRoleSites, ...roleSites];
90
+ } else {
91
+ return user.roles.filter((siteRole: ISiteRoles) => siteRole.siteId !== siteId);
92
+ }
93
+ };
67
94
 
68
- const removeUserFromSite = () => {
69
- const updatedSites = getUpdatedSites(user.sites);
70
- const updatedUser = { ...user, sites: updatedSites };
71
- user.id && updateUser(user.id, updatedUser, false, true).then(() => toggleModal());
95
+ const removeUserFromSite = async () => {
96
+ if (!user.id) return;
97
+ const updatedSites = getUpdatedSites();
98
+ const updatedUser = { ...user, roles: updatedSites };
99
+ const updated = await updateUser(user.id, updatedUser, false, true);
100
+ if (updated) {
101
+ toggleModal();
102
+ toggleDeleteToast();
103
+ }
72
104
  };
105
+
73
106
  const mainDeleteAction = {
74
107
  title: isSiteView ? "Remove user" : "Delete user",
75
108
  onClick: isSiteView ? removeUserFromSite : handleDeleteUser,
76
109
  };
110
+
77
111
  const secondaryDeleteAction = { title: "Cancel", onClick: toggleModal };
78
112
 
79
113
  const tagColor = user.status === "invited" ? "#FFBB37" : "#AFC628";
@@ -95,31 +129,78 @@ const UserItem = (props: IProps): JSX.Element => {
95
129
  }
96
130
  };
97
131
 
98
- const getElementsNames = () => user?.sites.map((id: string | number) => getSiteNameById(id));
132
+ const getElementsNames = () =>
133
+ user.isSuperAdmin
134
+ ? ["ALL SITES"]
135
+ : user?.roles
136
+ .filter((siteRoles: ISiteRoles) => siteRoles.siteId === "all" || Number.isInteger(siteRoles.siteId))
137
+ .map((siteRoles: ISiteRoles) => getSiteNameById(siteRoles.siteId));
138
+
139
+ let rolesIds: number[] = [];
140
+
141
+ if (isSiteView) {
142
+ const roleSite = user.roles.find(
143
+ (siteRoles: { siteId: number | string; roles: number[] }) =>
144
+ siteRoles.siteId === siteId || siteRoles.siteId === "all"
145
+ );
146
+ rolesIds = roleSite ? roleSite.roles : [];
147
+ } else {
148
+ user.roles.forEach((siteRoles: { siteId: number | string; roles: number[] }) => {
149
+ rolesIds = [...rolesIds, ...siteRoles.roles];
150
+ });
151
+ }
152
+
153
+ const rolesString = user.isSuperAdmin
154
+ ? ["Super - admin"]
155
+ : roles && roles.filter((role: IRole) => rolesIds && rolesIds.includes(role.id)).map((role: IRole) => role.name);
156
+
157
+ const colors = user.isSuperAdmin
158
+ ? { "Super - admin": "#E7CBFE" }
159
+ : rolesString &&
160
+ rolesString.reduce((prev, current) => {
161
+ const color: IRole | undefined = roles.find((role: IRole) => role.name === current);
162
+ return { ...prev, [current]: color?.hex };
163
+ }, {});
99
164
 
100
165
  return (
101
166
  <>
102
- <S.UserRow role="rowgroup" selected={isSelected}>
167
+ <S.UserRow role="rowgroup" selected={isSelected} data-testid="user-item">
103
168
  <S.CheckCell role="cell">
104
- <CheckField name="check" value={user.id ?? ""} checked={isSelected} onChange={handleOnChange} />
169
+ <CheckField
170
+ name={user.name}
171
+ value={user.id ?? ""}
172
+ checked={isSelected}
173
+ onChange={handleOnChange}
174
+ disabled={actionIsDisabled}
175
+ />
105
176
  </S.CheckCell>
106
- <S.UserCell role="cell" onClick={handleClick}>
177
+ <S.UserCell role="cell" onClick={handleClick} data-testid="user-cell" clickable={!actionIsDisabled}>
107
178
  <S.AvatarWrapper>
108
179
  <Avatar image={user.image?.thumb} name={user.name} />
109
180
  </S.AvatarWrapper>
110
- <S.UserInfo>
181
+ <S.UserInfo ref={userCellRef}>
111
182
  <S.UserName>{user.name}</S.UserName>
112
- <S.UserEmail>{user.email}</S.UserEmail>
183
+ <S.UserEmail width={email.width}>{email.text}</S.UserEmail>
113
184
  <S.UserUsername>@{user.username}</S.UserUsername>
114
185
  </S.UserInfo>
115
186
  </S.UserCell>
187
+ <S.RolesCell role="cell" onClick={handleClick} isSite={isSiteView} clickable={!actionIsDisabled}>
188
+ <ElementsTooltip
189
+ elements={rolesString}
190
+ maxChar={30}
191
+ rounded={true}
192
+ defaultElements={isSiteView ? 4 : 2}
193
+ elementsPerRow={2}
194
+ colors={colors}
195
+ />
196
+ </S.RolesCell>
116
197
  {isSiteView ? null : (
117
- <S.UserCell role="cell" onClick={handleClick}>
118
- {user?.sites?.length > 0 && <ElementsTooltip elements={getElementsNames()} elementsPerRow={3} defaultElements={3} />}
119
- </S.UserCell>
198
+ <S.SitesCell role="cell" onClick={handleClick} clickable={!actionIsDisabled} data-testid="sites-cell">
199
+ <ElementsTooltip elements={getElementsNames()} elementsPerRow={3} defaultElements={2} maxChar={15} />
200
+ </S.SitesCell>
120
201
  )}
121
202
  {isSiteView ? null : (
122
- <S.StatusCell>
203
+ <S.StatusCell data-testid="status-cell">
123
204
  <Tooltip content={tooltipText} hideOnClick>
124
205
  <Tag type="status" text={user.status ?? ""} color={tagColor} />
125
206
  </Tooltip>
@@ -137,7 +218,7 @@ const UserItem = (props: IProps): JSX.Element => {
137
218
  mainAction={mainDeleteAction}
138
219
  >
139
220
  {isOpen ? (
140
- <S.ModalContent>
221
+ <S.ModalContent data-testid="modal-delete-content">
141
222
  {isSiteView ? (
142
223
  <p>
143
224
  Are you sure you want to remove <strong>{user.email}</strong> from this site? If you remove it, this
@@ -160,14 +241,16 @@ const UserItem = (props: IProps): JSX.Element => {
160
241
  );
161
242
  };
162
243
 
163
- interface IUserItemProps {
244
+ interface IProps {
164
245
  user: IUser;
165
246
  siteId?: number;
166
247
  sites: ISite[];
167
248
  isSelected: boolean;
168
249
  isSiteView?: boolean;
250
+ roles: IRole[];
169
251
  onChange: (value: ICheck) => void;
170
- handleClick: (id: number) => void;
252
+ onClick: (id: number) => void;
253
+ toggleDeleteToast: () => void;
171
254
  }
172
255
 
173
256
  const mapDispatchToProps = {
@@ -177,11 +260,11 @@ const mapDispatchToProps = {
177
260
  };
178
261
 
179
262
  interface IDispatchProps {
180
- updateUser(id: number, data: any, isProfile: boolean, isList?: boolean): any;
263
+ updateUser(id: number, data: any, isProfile: boolean, isList?: boolean): Promise<boolean>;
181
264
  deleteUser(id: number): Promise<boolean>;
182
265
  resendInvitation(id: number): Promise<boolean>;
183
266
  }
184
267
 
185
- type IProps = IUserItemProps & IDispatchProps;
268
+ export type IUserItemProps = IProps & IDispatchProps;
186
269
 
187
270
  export default connect(null, mapDispatchToProps)(UserItem);
@@ -3,7 +3,7 @@ import styled from "styled-components";
3
3
  import { Cell, Row } from "@ax/components/TableList/TableItem/style";
4
4
  import { ActionMenu } from "@ax/components";
5
5
 
6
- const CheckCell = styled(Cell as any)`
6
+ const CheckCell = styled(Cell)`
7
7
  padding-right: 0;
8
8
  padding-left: ${(p) => p.theme.spacing.m};
9
9
  label {
@@ -12,28 +12,37 @@ const CheckCell = styled(Cell as any)`
12
12
  }
13
13
  `;
14
14
 
15
- const UserCell = styled(Cell as any)`
16
- width: 35%;
15
+ const UserCell = styled(Cell)<{ clickable: boolean }>`
17
16
  flex-grow: 1;
18
17
  flex-direction: row;
19
18
  align-items: center;
20
19
  justify-content: flex-start;
20
+ pointer-events: ${(p) => (p.clickable ? "auto" : "none")};
21
+ flex-wrap: nowrap;
21
22
  `;
22
23
 
23
24
  const AvatarWrapper = styled.div`
24
25
  margin-right: ${(p) => p.theme.spacing.s};
25
26
  `;
26
27
 
27
- const UserInfo = styled.div``;
28
+ const UserInfo = styled.div`
29
+ display: flex;
30
+ flex-flow: column nowrap;
31
+ width: 100%;
32
+ `;
28
33
 
29
34
  const UserName = styled.div`
30
35
  ${(p) => p.theme.textStyle.uiL};
31
36
  color: ${(p) => p.theme.colors.textHighEmphasis};
32
37
  `;
33
38
 
34
- const UserEmail = styled.div`
39
+ const UserEmail = styled.div<{ width: number }>`
35
40
  ${(p) => p.theme.textStyle.uiXS};
36
41
  color: ${(p) => p.theme.colors.textMediumEmphasis};
42
+ overflow: hidden;
43
+ white-space: nowrap;
44
+ text-overflow: ellipsis;
45
+ width: ${(p) => `${p.width}px`};
37
46
  `;
38
47
 
39
48
  const UserUsername = styled.div`
@@ -41,12 +50,22 @@ const UserUsername = styled.div`
41
50
  color: ${(p) => p.theme.colors.textMediumEmphasis};
42
51
  `;
43
52
 
44
- const StatusCell = styled(Cell as any)`
45
- width: 98px;
53
+ const StatusCell = styled(Cell)`
54
+ flex: 0 0 98px;
55
+ `;
56
+
57
+ const ActionsCell = styled(Cell)`
58
+ flex: 0 0 64px;
46
59
  `;
47
60
 
48
- const ActionsCell = styled(Cell as any)`
49
- width: 60px;
61
+ const RolesCell = styled(Cell)<{ isSite: boolean; clickable: boolean }>`
62
+ flex: ${(p) => (p.isSite ? "0 0 450px" : "0 0 275px")};
63
+ pointer-events: ${(p) => (p.clickable ? "auto" : "none")};
64
+ `;
65
+
66
+ const SitesCell = styled(Cell)<{ clickable: boolean }>`
67
+ flex: 0 0 210px;
68
+ pointer-events: ${(p) => (p.clickable ? "auto" : "none")};
50
69
  `;
51
70
 
52
71
  const ActionsWrapper = styled.div`
@@ -62,16 +81,13 @@ const StyledActionMenu = styled(ActionMenu)`
62
81
  margin-left: auto;
63
82
  `;
64
83
 
65
- const UserRow = styled(Row as any)<{ disabled: boolean }>`
66
- cursor: ${(p) => (p.disabled ? "default" : "pointer")};
84
+ const UserRow = styled(Row)`
85
+ cursor: pointer;
67
86
  &:hover {
68
87
  ${StyledActionMenu} {
69
88
  opacity: 1;
70
89
  }
71
90
  }
72
- ${UserCell} {
73
- pointer-events: ${(p) => (p.disabled ? "none" : "auto")};
74
- }
75
91
  `;
76
92
 
77
93
  const ModalContent = styled.div`
@@ -95,4 +111,6 @@ export {
95
111
  UserRow,
96
112
  ModalContent,
97
113
  StatusCell,
114
+ RolesCell,
115
+ SitesCell,
98
116
  };