@griddo/ax 1.58.6 → 1.59.2

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 (120) hide show
  1. package/package.json +2 -2
  2. package/src/GlobalStore.tsx +3 -1
  3. package/src/api/checkgroups.tsx +1 -1
  4. package/src/api/domains.tsx +26 -0
  5. package/src/api/index.tsx +3 -1
  6. package/src/api/sites.tsx +25 -8
  7. package/src/api/utils.tsx +1 -1
  8. package/src/components/Browser/index.tsx +8 -3
  9. package/src/components/ElementsTooltip/index.tsx +23 -8
  10. package/src/components/ElementsTooltip/style.tsx +4 -5
  11. package/src/components/ErrorCenter/index.tsx +11 -1
  12. package/src/components/ErrorCenter/style.tsx +4 -3
  13. package/src/components/Fields/CheckGroup/index.tsx +5 -4
  14. package/src/components/Fields/ComponentArray/MixableComponentArray/AddItemButton/index.tsx +1 -0
  15. package/src/components/Fields/ReferenceField/Context/index.tsx +10 -6
  16. package/src/components/Fields/ReferenceField/ItemList/Item/index.tsx +2 -2
  17. package/src/components/Fields/ReferenceField/ItemList/index.tsx +15 -14
  18. package/src/components/FieldsBehavior/index.tsx +2 -1
  19. package/src/components/FloatingMenu/index.tsx +3 -1
  20. package/src/components/FloatingMenu/style.tsx +7 -5
  21. package/src/components/Gallery/GalleryPanel/DetailPanel/index.tsx +17 -19
  22. package/src/components/Gallery/GalleryPanel/DetailPanel/style.tsx +32 -19
  23. package/src/components/Gallery/style.tsx +1 -1
  24. package/src/components/Icon/components/Category.js +5 -6
  25. package/src/components/Icon/components/Refresh.js +12 -0
  26. package/src/components/Icon/svgs/Category.svg +1 -1
  27. package/src/components/Icon/svgs/Refresh.svg +3 -0
  28. package/src/components/Lists/style.tsx +10 -9
  29. package/src/components/MainWrapper/AppBar/index.tsx +16 -5
  30. package/src/components/MainWrapper/AppBar/style.tsx +2 -1
  31. package/src/components/SideModal/index.tsx +10 -4
  32. package/src/components/TableCounter/style.tsx +1 -4
  33. package/src/components/TableFilters/CategoryFilter/index.tsx +92 -0
  34. package/src/{modules/Content/HeaderMenus/Translations → components/TableFilters/CategoryFilter}/style.tsx +4 -3
  35. package/src/components/TableFilters/CustomizeFilters/index.tsx +52 -0
  36. package/src/components/TableFilters/CustomizeFilters/style.tsx +28 -0
  37. package/src/{modules/StructuredData/StructuredDataList/HeaderMenus/Live → components/TableFilters/LiveFilter}/index.tsx +18 -6
  38. package/src/{modules/Content/HeaderMenus/Live → components/TableFilters/LiveFilter}/style.tsx +0 -0
  39. package/src/{modules/StructuredData/StructuredDataList/HeaderMenus/Name → components/TableFilters/NameFilter}/index.tsx +18 -9
  40. package/src/{modules/Content/HeaderMenus/Name → components/TableFilters/NameFilter}/style.tsx +0 -0
  41. package/src/{modules/StructuredData/StructuredDataList/HeaderMenus/Site → components/TableFilters/SiteFilter}/index.tsx +3 -3
  42. package/src/{modules/StructuredData/StructuredDataList/HeaderMenus/Site → components/TableFilters/SiteFilter}/style.tsx +1 -1
  43. package/src/{modules/Content/HeaderMenus/Status → components/TableFilters/StatusFilter}/index.tsx +7 -4
  44. package/src/{modules/Content/HeaderMenus/Status → components/TableFilters/StatusFilter}/style.tsx +0 -0
  45. package/src/{modules/StructuredData/StructuredDataList/HeaderMenus/Translations → components/TableFilters/TranslationsFilter}/index.tsx +4 -4
  46. package/src/{modules/StructuredData/StructuredDataList/HeaderMenus/Translations → components/TableFilters/TranslationsFilter}/style.tsx +0 -0
  47. package/src/{modules/StructuredData/StructuredDataList/HeaderMenus/Types → components/TableFilters/TypeFilter}/index.tsx +13 -9
  48. package/src/{modules/StructuredData/StructuredDataList/HeaderMenus/Types → components/TableFilters/TypeFilter}/style.tsx +1 -1
  49. package/src/components/TableFilters/index.tsx +19 -0
  50. package/src/components/Tag/index.tsx +1 -1
  51. package/src/components/Tag/style.tsx +10 -11
  52. package/src/components/index.tsx +19 -0
  53. package/src/containers/Domains/actions.tsx +51 -0
  54. package/src/containers/Domains/constants.tsx +5 -0
  55. package/src/containers/Domains/index.tsx +4 -0
  56. package/src/containers/Domains/interfaces.tsx +9 -0
  57. package/src/containers/Domains/reducer.tsx +22 -0
  58. package/src/containers/Gallery/actions.tsx +0 -1
  59. package/src/containers/PageEditor/actions.tsx +7 -0
  60. package/src/containers/PageEditor/utils.tsx +1 -1
  61. package/src/containers/Settings/Languages/constants.tsx +3 -3
  62. package/src/containers/Settings/Languages/index.tsx +2 -5
  63. package/src/containers/Sites/actions.tsx +3 -2
  64. package/src/containers/StructuredData/actions.tsx +62 -3
  65. package/src/containers/StructuredData/constants.tsx +4 -0
  66. package/src/containers/StructuredData/interfaces.tsx +13 -1
  67. package/src/containers/StructuredData/reducer.tsx +9 -1
  68. package/src/forms/editor.tsx +4 -0
  69. package/src/forms/elements.tsx +2 -5
  70. package/src/forms/index.tsx +2 -1
  71. package/src/forms/validators.tsx +12 -5
  72. package/src/helpers/arrays.tsx +12 -1
  73. package/src/helpers/index.tsx +4 -1
  74. package/src/helpers/strings.tsx +7 -0
  75. package/src/hooks/content.tsx +41 -0
  76. package/src/hooks/index.tsx +3 -1
  77. package/src/modules/Categories/CategoriesList/CategoryNav/NavItem/style.tsx +9 -9
  78. package/src/modules/Content/BulkHeader/TableHeader/index.tsx +95 -24
  79. package/src/modules/Content/BulkHeader/TableHeader/style.tsx +6 -19
  80. package/src/modules/Content/BulkHeader/index.tsx +16 -0
  81. package/src/modules/Content/ContentFilters/index.tsx +4 -4
  82. package/src/modules/Content/OptionTable/style.tsx +1 -1
  83. package/src/modules/Content/PageItem/atoms.tsx +28 -0
  84. package/src/modules/Content/PageItem/index.tsx +67 -24
  85. package/src/modules/Content/PageItem/style.tsx +14 -7
  86. package/src/modules/Content/hooks.tsx +27 -17
  87. package/src/modules/Content/index.tsx +53 -6
  88. package/src/modules/GlobalEditor/index.tsx +5 -11
  89. package/src/modules/GlobalSettings/Robots/Item/RobotsPanel/index.tsx +61 -0
  90. package/src/modules/GlobalSettings/Robots/Item/RobotsPanel/style.tsx +30 -0
  91. package/src/modules/GlobalSettings/Robots/Item/index.tsx +33 -0
  92. package/src/modules/GlobalSettings/Robots/Item/style.tsx +28 -0
  93. package/src/modules/GlobalSettings/Robots/index.tsx +120 -0
  94. package/src/modules/GlobalSettings/Robots/style.tsx +32 -0
  95. package/src/modules/GlobalSettings/index.tsx +26 -0
  96. package/src/modules/PageEditor/index.tsx +2 -5
  97. package/src/modules/Settings/Globals/style.tsx +1 -1
  98. package/src/modules/StructuredData/Form/ConnectedField/index.tsx +10 -2
  99. package/src/modules/StructuredData/Form/index.tsx +48 -9
  100. package/src/modules/StructuredData/Form/style.tsx +3 -6
  101. package/src/modules/StructuredData/StructuredDataList/BulkHeader/TableHeader/index.tsx +84 -35
  102. package/src/modules/StructuredData/StructuredDataList/BulkHeader/TableHeader/style.tsx +6 -25
  103. package/src/modules/StructuredData/StructuredDataList/BulkHeader/index.tsx +10 -1
  104. package/src/modules/StructuredData/StructuredDataList/GlobalPageItem/atoms.tsx +24 -3
  105. package/src/modules/StructuredData/StructuredDataList/GlobalPageItem/index.tsx +53 -22
  106. package/src/modules/StructuredData/StructuredDataList/GlobalPageItem/style.tsx +16 -9
  107. package/src/modules/StructuredData/StructuredDataList/OptionTable/style.tsx +1 -1
  108. package/src/modules/StructuredData/StructuredDataList/hooks.tsx +9 -2
  109. package/src/modules/StructuredData/StructuredDataList/index.tsx +45 -5
  110. package/src/routes/multisite.tsx +8 -0
  111. package/src/types/index.tsx +28 -11
  112. package/src/modules/Content/HeaderMenus/Live/index.tsx +0 -93
  113. package/src/modules/Content/HeaderMenus/Name/index.tsx +0 -52
  114. package/src/modules/Content/HeaderMenus/Translations/index.tsx +0 -62
  115. package/src/modules/Content/HeaderMenus/Types/index.tsx +0 -73
  116. package/src/modules/Content/HeaderMenus/Types/style.tsx +0 -34
  117. package/src/modules/StructuredData/StructuredDataList/HeaderMenus/Live/style.tsx +0 -37
  118. package/src/modules/StructuredData/StructuredDataList/HeaderMenus/Name/style.tsx +0 -29
  119. package/src/modules/StructuredData/StructuredDataList/HeaderMenus/Status/index.tsx +0 -47
  120. package/src/modules/StructuredData/StructuredDataList/HeaderMenus/Status/style.tsx +0 -30
@@ -17,4 +17,4 @@ const FormWrapper = styled.div`
17
17
  margin: ${(p) => `${p.theme.spacing.m} 0 0 ${p.theme.spacing.m}`};
18
18
  `;
19
19
 
20
- export { Wrapper, ContentWrapper, FormWrapper }
20
+ export { Wrapper, ContentWrapper, FormWrapper };
@@ -1,7 +1,7 @@
1
1
  import React from "react";
2
2
  import { connect } from "react-redux";
3
3
 
4
- import { IRootState } from "@ax/types";
4
+ import { IErrorItem, IRootState } from "@ax/types";
5
5
  import { structuredDataActions } from "@ax/containers/StructuredData";
6
6
  import { FieldsBehavior } from "@ax/components";
7
7
  import { getStructuredDataInnerFields } from "@ax/forms";
@@ -9,9 +9,10 @@ import { getStructuredDataInnerFields } from "@ax/forms";
9
9
  import * as S from "./style";
10
10
 
11
11
  const ConnectedField = (props: IProps) => {
12
- const { field, site, form, fieldKey, updateFormValue, disabled } = props;
12
+ const { field, site, form, fieldKey, updateFormValue, disabled, errors, deleteError } = props;
13
13
 
14
14
  const value = form.content && form.content[fieldKey];
15
+ const error = errors.find((err: any) => err.key === field.key);
15
16
 
16
17
  const handleChange = (newValue: any) => updateFormValue({ [fieldKey]: newValue });
17
18
 
@@ -25,6 +26,7 @@ const ConnectedField = (props: IProps) => {
25
26
  }
26
27
 
27
28
  const fieldProps = {
29
+ objKey: field.key,
28
30
  value,
29
31
  onChange: handleChange,
30
32
  site,
@@ -32,6 +34,8 @@ const ConnectedField = (props: IProps) => {
32
34
  fieldType: field.type,
33
35
  ...field,
34
36
  innerFields,
37
+ error,
38
+ deleteError,
35
39
  };
36
40
 
37
41
  return (
@@ -47,15 +51,19 @@ interface IProps {
47
51
  site: any;
48
52
  fieldKey: string;
49
53
  disabled: boolean;
54
+ errors: IErrorItem[];
50
55
  updateFormValue: (value: any) => void;
56
+ deleteError: (error: IErrorItem) => void;
51
57
  }
52
58
 
53
59
  const mapStateToProps = (state: IRootState) => ({
54
60
  form: state.structuredData.form,
61
+ errors: state.structuredData.errors,
55
62
  });
56
63
 
57
64
  const mapDispatchToProps = {
58
65
  updateFormValue: structuredDataActions.updateFormValue,
66
+ deleteError: structuredDataActions.deleteError,
59
67
  };
60
68
 
61
69
  export default connect(mapStateToProps, mapDispatchToProps)(ConnectedField);
@@ -1,7 +1,7 @@
1
1
  import React, { useState } from "react";
2
2
  import { connect } from "react-redux";
3
3
 
4
- import { IDataPack, IRootState } from "@ax/types";
4
+ import { IDataPack, IErrorItem, IRootState } from "@ax/types";
5
5
  import { structuredDataActions } from "@ax/containers/StructuredData";
6
6
  import { MainWrapper, ErrorToast, Notification, Loading } from "@ax/components";
7
7
  import { getActivatedDataPacksIds } from "@ax/helpers";
@@ -36,9 +36,12 @@ const Form = (props: IProps) => {
36
36
  getSiteDataPack,
37
37
  setDataStatus,
38
38
  deleteStructuredDataContent,
39
+ errors,
40
+ validated,
39
41
  } = props;
40
42
 
41
- const [isNewStructuredData, setisNewStructuredData] = useState(!form.id);
43
+ const [isNewStructuredData, setIsNewStructuredData] = useState(!form.id);
44
+ const { isDirty, resetDirty } = useIsDirty(form);
42
45
 
43
46
  const { fields } = schema;
44
47
 
@@ -58,7 +61,7 @@ const Form = (props: IProps) => {
58
61
  return <ConnectedField fieldKey={key} field={field} key={`${type}${i}`} site={site} disabled={isDisabled} />;
59
62
  });
60
63
 
61
- const handleSave = (publish?: boolean) => {
64
+ const handleSave = async (publish?: boolean) => {
62
65
  setIsSavedData(true);
63
66
  const status = isNewStructuredData ? true : form.draft;
64
67
 
@@ -74,9 +77,14 @@ const Form = (props: IProps) => {
74
77
  payload = { ...payload, ...form };
75
78
  }
76
79
 
77
- isNewStructuredData
78
- ? createStructuredDataContent(payload).then((created: boolean) => created && setisNewStructuredData(false))
79
- : updateStructuredDataContent(payload);
80
+ let saved = false;
81
+ if (isNewStructuredData) {
82
+ saved = await createStructuredDataContent(payload);
83
+ saved && setIsNewStructuredData(false);
84
+ } else {
85
+ saved = await updateStructuredDataContent(payload);
86
+ }
87
+ saved && resetDirty();
80
88
  };
81
89
 
82
90
  const getSaveLabel = () => {
@@ -92,7 +100,7 @@ const Form = (props: IProps) => {
92
100
 
93
101
  const inversed = !currentSite;
94
102
 
95
- const createNewTranslation = (value: boolean) => setisNewStructuredData(value);
103
+ const createNewTranslation = (value: boolean) => setIsNewStructuredData(value);
96
104
 
97
105
  const languageActions = {
98
106
  setLanguage,
@@ -126,7 +134,6 @@ const Form = (props: IProps) => {
126
134
 
127
135
  const setRoute = (path: string) => setHistoryPush(path);
128
136
 
129
- const { isDirty } = useIsDirty(form);
130
137
  const modalText = (
131
138
  <>
132
139
  Some content <strong>is not saved</strong> on this page.
@@ -182,10 +189,20 @@ const Form = (props: IProps) => {
182
189
  };
183
190
  };
184
191
 
192
+ const reviewForm = async () => {
193
+ const { validateForm } = props;
194
+ await validateForm();
195
+ };
196
+
185
197
  const downArrowMenu = {
186
198
  displayed: true,
187
199
  button: getPublishButton(form.draft),
188
200
  options: [
201
+ {
202
+ label: "Review",
203
+ icon: "question",
204
+ action: reviewForm,
205
+ },
189
206
  {
190
207
  label: "Delete",
191
208
  icon: "delete",
@@ -201,6 +218,11 @@ const Form = (props: IProps) => {
201
218
  languageActions: isDataTranslatable ? languageActions : null,
202
219
  };
203
220
 
221
+ const errorNotificationText =
222
+ "There are some errors on the page so you can not publish yet. Please review them in the error panel.";
223
+
224
+ const validatedNotificationText = "Everything seems ok, you can publish the page.";
225
+
204
226
  return isLoading ? (
205
227
  <Loading />
206
228
  ) : (
@@ -220,6 +242,7 @@ const Form = (props: IProps) => {
220
242
  downArrowMenu={downArrowMenu}
221
243
  isFromEditor={true}
222
244
  currentPageID={form.id}
245
+ errors={errors}
223
246
  >
224
247
  {isDisabled && (
225
248
  <S.NotificationWrapper>
@@ -231,6 +254,16 @@ const Form = (props: IProps) => {
231
254
  />
232
255
  </S.NotificationWrapper>
233
256
  )}
257
+ {errors.length > 0 && (
258
+ <S.NotificationWrapper>
259
+ <Notification type="error" text={errorNotificationText} />
260
+ </S.NotificationWrapper>
261
+ )}
262
+ {validated && (
263
+ <S.NotificationWrapper>
264
+ <Notification type="success" text={validatedNotificationText} />
265
+ </S.NotificationWrapper>
266
+ )}
234
267
  <ErrorToast size="l" />
235
268
  <S.Wrapper>{Fields}</S.Wrapper>
236
269
  </MainWrapper>
@@ -250,14 +283,17 @@ interface IProps {
250
283
  currentSite: any;
251
284
  lang: { locale: string; id: number | null };
252
285
  activatedDataPacks: IDataPack[];
286
+ errors: IErrorItem[];
287
+ validated: boolean;
253
288
  createStructuredDataContent: (payload: any) => Promise<boolean>;
254
- updateStructuredDataContent: (payload: any) => void;
289
+ updateStructuredDataContent: (payload: any) => Promise<boolean>;
255
290
  setLanguage(lang: { locale: string; id: number | null }): void;
256
291
  getDataContent(id: number): void;
257
292
  setHistoryPush(path: string, isEditor?: boolean): void;
258
293
  getSiteDataPack(packID: string): void;
259
294
  setDataStatus(id: number, status: string): Promise<boolean>;
260
295
  deleteStructuredDataContent(id: number): Promise<boolean>;
296
+ validateForm(): Promise<boolean>;
261
297
  }
262
298
 
263
299
  const mapStateToProps = (state: IRootState) => ({
@@ -272,6 +308,8 @@ const mapStateToProps = (state: IRootState) => ({
272
308
  globalLangs: state.app.globalLangs,
273
309
  currentSite: state.sites.currentSiteInfo && state.sites.currentSiteInfo.id,
274
310
  activatedDataPacks: state.dataPacks.activated,
311
+ errors: state.structuredData.errors,
312
+ validated: state.structuredData.validated,
275
313
  });
276
314
 
277
315
  const mapDispatchToProps = {
@@ -283,6 +321,7 @@ const mapDispatchToProps = {
283
321
  getSiteDataPack: dataPacksActions.getSiteDataPack,
284
322
  setDataStatus: structuredDataActions.setStatusStructuredDataContent,
285
323
  deleteStructuredDataContent: structuredDataActions.deleteStructuredDataContent,
324
+ validateForm: structuredDataActions.validateForm,
286
325
  };
287
326
 
288
327
  export default connect(mapStateToProps, mapDispatchToProps)(Form);
@@ -8,13 +8,10 @@ const Wrapper = styled.section`
8
8
  const NotificationWrapper = styled.div`
9
9
  position: fixed;
10
10
  width: 100%;
11
- top: ${p => `calc(${p.theme.spacing.s} * 4)`};
11
+ top: ${(p) => `calc(${p.theme.spacing.s} * 4)`};
12
12
  left: 0;
13
13
  right: 0;
14
- z-index: 1100;
14
+ z-index: 2;
15
15
  `;
16
16
 
17
- export {
18
- Wrapper,
19
- NotificationWrapper
20
- };
17
+ export { Wrapper, NotificationWrapper };
@@ -1,14 +1,19 @@
1
1
  import React from "react";
2
2
 
3
- import { CheckField, TableCounter } from "@ax/components";
4
- import { IStructuredDataQueryValues } from "@ax/types";
5
-
6
- import Name from "../../HeaderMenus/Name";
7
- import Status from "../../HeaderMenus/Status";
8
- import Types from "../../HeaderMenus/Types";
9
- import Site from "../../HeaderMenus/Site";
10
- import Translations from "../../HeaderMenus/Translations";
11
- import Live from "../../HeaderMenus/Live";
3
+ import {
4
+ CheckField,
5
+ TableCounter,
6
+ CustomizeFilters,
7
+ CategoryFilter,
8
+ NameFilter,
9
+ TypeFilter,
10
+ StatusFilter,
11
+ SiteFilter,
12
+ LiveFilter,
13
+ TranslationsFilter,
14
+ } from "@ax/components";
15
+ import { IColumn, IStructuredDataQueryValues } from "@ax/types";
16
+ import { getGlobalPageTypes } from "@ax/helpers";
12
17
 
13
18
  import * as S from "./style";
14
19
 
@@ -24,8 +29,29 @@ const TableHeader = (props: IProps): JSX.Element => {
24
29
  sortedListStatus,
25
30
  isAllPages,
26
31
  checkState,
32
+ categoryColumns,
33
+ columns,
34
+ setColumns,
27
35
  } = props;
28
36
 
37
+ const activeColumns = Object.keys(columns).filter((col: string) => columns[col].show);
38
+
39
+ const CategoryColumns =
40
+ !isAllPages &&
41
+ categoryColumns.map(
42
+ (col: any) =>
43
+ activeColumns.includes(col.key) && (
44
+ <S.HeaderWrapper key={col.key}>
45
+ <CategoryFilter filterItems={filterItems} value={filterValues.categories} structuredData={col} />
46
+ </S.HeaderWrapper>
47
+ )
48
+ );
49
+
50
+ const globalPageTypes = getGlobalPageTypes();
51
+ const typeFilters = globalPageTypes.map(({ type, title }) => ({ name: type, value: type, title }));
52
+ const allFilter = { name: "all", value: "all", title: "All types" };
53
+ typeFilters.unshift(allFilter);
54
+
29
55
  return (
30
56
  <S.TableHeader isScrolling={isScrolling}>
31
57
  <S.CheckHeader>
@@ -42,39 +68,59 @@ const TableHeader = (props: IProps): JSX.Element => {
42
68
  {isFromPage ? (
43
69
  <>
44
70
  <S.NameWrapper>
45
- <Name sortItems={sortItems} sortedState={sortedListStatus} />
71
+ <NameFilter sortItems={sortItems} sortedState={sortedListStatus} urlSorting={true} />
46
72
  </S.NameWrapper>
47
- {isAllPages ? (
48
- <S.TypesWrapper>
49
- <Types filterItems={filterItems} />
50
- </S.TypesWrapper>
51
- ) : (
52
- <S.SiteWrapper>
53
- <Site filterItems={filterItems} value={filterValues.filterSites} />
54
- </S.SiteWrapper>
73
+ {isAllPages && activeColumns.includes("type") && (
74
+ <S.HeaderWrapper>
75
+ <TypeFilter filterItems={filterItems} filters={typeFilters} pointer="types" />
76
+ </S.HeaderWrapper>
77
+ )}
78
+ {!isAllPages && activeColumns.includes("site") && (
79
+ <S.HeaderWrapper>
80
+ <SiteFilter filterItems={filterItems} value={filterValues.filterSites} />
81
+ </S.HeaderWrapper>
55
82
  )}
56
- <S.LiveWrapper>
57
- <Live filterItems={filterItems} value={filterValues.liveStatus} />
58
- </S.LiveWrapper>
59
- <S.StatusWrapper>
60
- <Status sortItems={sortItems} sortedState={sortedListStatus} />
61
- </S.StatusWrapper>
62
- <S.TranslationsWrapper>
63
- <Translations filterItems={filterItems} value={filterValues.translated} />
64
- </S.TranslationsWrapper>
65
- <S.SeoHeader>SEO</S.SeoHeader>
83
+ {activeColumns.includes("live") && (
84
+ <S.HeaderWrapper>
85
+ <LiveFilter filterItems={filterItems} value={filterValues.liveStatus} />
86
+ </S.HeaderWrapper>
87
+ )}
88
+ {CategoryColumns}
89
+ {activeColumns.includes("status") && (
90
+ <S.HeaderWrapper>
91
+ <StatusFilter sortItems={sortItems} sortedState={sortedListStatus} />
92
+ </S.HeaderWrapper>
93
+ )}
94
+ {activeColumns.includes("translation") && (
95
+ <S.HeaderWrapper>
96
+ <TranslationsFilter filterItems={filterItems} value={filterValues.translated} />
97
+ </S.HeaderWrapper>
98
+ )}
99
+ {activeColumns.includes("seo") && <S.SeoHeader>SEO</S.SeoHeader>}
100
+ <S.ActionsHeader>
101
+ <TableCounter totalItems={totalItems} />
102
+ <CustomizeFilters columns={columns} setColumns={setColumns} value={activeColumns} />
103
+ </S.ActionsHeader>
66
104
  </>
67
105
  ) : (
68
106
  <>
69
- <S.NameHeader>Name</S.NameHeader>
70
- <S.LiveHeader>Live</S.LiveHeader>
71
- <S.StatusHeader>Status</S.StatusHeader>
72
- <S.TransHeader>Translations</S.TransHeader>
107
+ <S.NameWrapper>
108
+ <NameFilter sortItems={sortItems} sortedState={sortedListStatus} />
109
+ </S.NameWrapper>
110
+ <S.HeaderWrapper>
111
+ <LiveFilter filterItems={filterItems} value={filterValues.liveStatus} isStructuredData={true} />
112
+ </S.HeaderWrapper>
113
+ <S.HeaderWrapper>
114
+ <StatusFilter sortItems={sortItems} sortedState={sortedListStatus} isStructuredData={true} />
115
+ </S.HeaderWrapper>
116
+ <S.HeaderWrapper>
117
+ <TranslationsFilter filterItems={filterItems} value={filterValues.translated} />
118
+ </S.HeaderWrapper>
119
+ <S.ActionsHeader>
120
+ <TableCounter totalItems={totalItems} />
121
+ </S.ActionsHeader>
73
122
  </>
74
123
  )}
75
- <S.ActionsHeader>
76
- <TableCounter totalItems={totalItems} />
77
- </S.ActionsHeader>
78
124
  </S.TableHeader>
79
125
  );
80
126
  };
@@ -90,6 +136,9 @@ interface IProps {
90
136
  isAllPages: boolean;
91
137
  filterValues: IStructuredDataQueryValues;
92
138
  checkState: Record<string, boolean>;
139
+ categoryColumns: any[];
140
+ columns: Record<string, IColumn>;
141
+ setColumns: (columns: Record<string, IColumn>) => void;
93
142
  }
94
143
 
95
144
  export default TableHeader;
@@ -15,12 +15,11 @@ const CheckHeader = styled(Header)`
15
15
  `;
16
16
 
17
17
  const NameHeader = styled(Header)`
18
- width: 35%;
19
18
  flex-grow: 1;
20
19
  `;
21
20
 
22
21
  const SiteHeader = styled(Header)`
23
- width: 230px;
22
+ width: 170px;
24
23
  justify-content: center;
25
24
  `;
26
25
 
@@ -40,8 +39,10 @@ const TransHeader = styled(Header)`
40
39
  `;
41
40
 
42
41
  const ActionsHeader = styled(Header)`
43
- width: 92px;
42
+ width: 100px;
44
43
  padding-right: 0;
44
+ justify-content: flex-end;
45
+ align-items: center;
45
46
  `;
46
47
 
47
48
  const SeoHeader = styled(Header)`
@@ -53,23 +54,7 @@ const NameWrapper = styled.div`
53
54
  position: relative;
54
55
  `;
55
56
 
56
- const TypesWrapper = styled.div`
57
- position: relative;
58
- `;
59
-
60
- const LiveWrapper = styled.div`
61
- position: relative;
62
- `;
63
-
64
- const StatusWrapper = styled.div`
65
- position: relative;
66
- `;
67
-
68
- const TranslationsWrapper = styled.div`
69
- position: relative;
70
- `;
71
-
72
- const SiteWrapper = styled.div`
57
+ const HeaderWrapper = styled.div`
73
58
  position: relative;
74
59
  `;
75
60
 
@@ -83,10 +68,6 @@ export {
83
68
  ActionsHeader,
84
69
  SiteHeader,
85
70
  NameWrapper,
86
- TypesWrapper,
87
- LiveWrapper,
88
- StatusWrapper,
89
- TranslationsWrapper,
90
- SiteWrapper,
71
+ HeaderWrapper,
91
72
  SeoHeader,
92
73
  };
@@ -2,7 +2,7 @@ import React from "react";
2
2
  import { BulkSelectionOptions } from "@ax/components";
3
3
  import TableHeader from "./TableHeader";
4
4
 
5
- import { IStructuredDataQueryValues, IStructuredDataSortedInitialState } from "@ax/types";
5
+ import { IColumn, IStructuredDataQueryValues, IStructuredDataSortedInitialState } from "@ax/types";
6
6
 
7
7
  const BulkHeader = (props: IProps): JSX.Element => {
8
8
  const {
@@ -22,6 +22,9 @@ const BulkHeader = (props: IProps): JSX.Element => {
22
22
  filterValues,
23
23
  sortedListStatus,
24
24
  isAllPages,
25
+ categoryColumns,
26
+ columns,
27
+ setColumns,
25
28
  } = props;
26
29
 
27
30
  const deleteAction = {
@@ -65,6 +68,9 @@ const BulkHeader = (props: IProps): JSX.Element => {
65
68
  filterValues={filterValues}
66
69
  isAllPages={isAllPages}
67
70
  checkState={checkState}
71
+ categoryColumns={categoryColumns}
72
+ columns={columns}
73
+ setColumns={setColumns}
68
74
  />
69
75
  );
70
76
  };
@@ -86,6 +92,9 @@ interface IProps {
86
92
  sortedListStatus: IStructuredDataSortedInitialState;
87
93
  isAllPages: boolean;
88
94
  filterValues: IStructuredDataQueryValues;
95
+ categoryColumns: any[];
96
+ columns: Record<string, IColumn>;
97
+ setColumns: (columns: Record<string, IColumn>) => void;
89
98
  }
90
99
 
91
100
  export default BulkHeader;
@@ -1,7 +1,7 @@
1
- import React from "react";
1
+ import React, { useEffect } from "react";
2
2
 
3
3
  import { IModal } from "@ax/types";
4
- import { Modal, FieldsBehavior } from "@ax/components";
4
+ import { Modal, FieldsBehavior, ElementsTooltip } from "@ax/components";
5
5
  import { slugify } from "@ax/helpers";
6
6
 
7
7
  import * as S from "./style";
@@ -124,6 +124,27 @@ const UnpublishModal = (props: IModal): JSX.Element => {
124
124
  );
125
125
  };
126
126
 
127
+ const CategoryCell = (props: ICategoryCellProps): JSX.Element => {
128
+ const { categories, categoryColors, addCategoryColors } = props;
129
+
130
+ useEffect(() => {
131
+ addCategoryColors(categories);
132
+ // eslint-disable-next-line react-hooks/exhaustive-deps
133
+ }, [categories]);
134
+
135
+ return (
136
+ <S.CategoryCell>
137
+ <ElementsTooltip elements={categories} colors={categoryColors} maxChar={30} rounded={true} />
138
+ </S.CategoryCell>
139
+ );
140
+ };
141
+
142
+ interface ICategoryCellProps {
143
+ categories: any;
144
+ categoryColors: any;
145
+ addCategoryColors(cats: string[]): void;
146
+ }
147
+
127
148
  interface IDeleteModal extends IModal {
128
149
  title: string;
129
150
  isTranslated: boolean;
@@ -136,4 +157,4 @@ interface IDuplicateModal extends IModal {
136
157
  setDuplicateModalState: React.Dispatch<React.SetStateAction<{ title: string; slug: string }>>;
137
158
  }
138
159
 
139
- export { DeleteModal, DuplicateModal, UnpublishModal };
160
+ export { DeleteModal, DuplicateModal, UnpublishModal, CategoryCell };
@@ -1,17 +1,17 @@
1
1
  import React, { memo, useState } from "react";
2
2
  import { connect } from "react-redux";
3
3
 
4
- import { ICheck, IAvailableSites, ISavePageParams, ILanguage, IPageLanguage, IPage } from "@ax/types";
4
+ import { ICheck, IAvailableSites, ISavePageParams, ILanguage, IPageLanguage, IPage, IColumn } from "@ax/types";
5
5
  import { getHumanLastModifiedDate, getStructuredDataTitle } from "@ax/helpers";
6
6
  import { appActions } from "@ax/containers/App";
7
7
  import { pageStatus, ISetCurrentPageIDAction } from "@ax/containers/PageEditor/interfaces";
8
8
  import { CheckField, FloatingMenu, Icon, Flag, LanguageMenu, Tooltip, ElementsTooltip } from "@ax/components";
9
9
  import { pageEditorActions } from "@ax/containers/PageEditor";
10
10
  import { useModal } from "@ax/hooks";
11
+ import { DeleteModal, DuplicateModal, UnpublishModal, CategoryCell } from "./atoms";
12
+ import { getCurrentLanguages } from "./utils";
11
13
 
12
14
  import * as S from "./style";
13
- import { DeleteModal, DuplicateModal, UnpublishModal } from "./atoms";
14
- import { getCurrentLanguages } from "./utils";
15
15
 
16
16
  const GlobalPageItem = (props: IGlobalPageItemProps): JSX.Element => {
17
17
  const {
@@ -35,8 +35,14 @@ const GlobalPageItem = (props: IGlobalPageItemProps): JSX.Element => {
35
35
  toggleToast,
36
36
  setDeletedItem,
37
37
  deleteBulk,
38
+ categoryColumns,
39
+ columns,
40
+ categoryColors,
41
+ addCategoryColors,
38
42
  } = props;
39
43
 
44
+ const activeColumns = Object.keys(columns).filter((col: string) => columns[col].show);
45
+
40
46
  const initValue = { title: "", slug: "" };
41
47
  const [duplicateModalState, setDuplicateModalState] = useState(initValue);
42
48
  const { isOpen: isDuplicateOpen, toggleModal: toggleDuplicateModal } = useModal();
@@ -287,9 +293,7 @@ const GlobalPageItem = (props: IGlobalPageItemProps): JSX.Element => {
287
293
  );
288
294
 
289
295
  const translations = isTranslatable ? (
290
- <FloatingMenu Button={FlagsButton}>
291
- {languageMenu()}
292
- </FloatingMenu>
296
+ <FloatingMenu Button={FlagsButton}>{languageMenu()}</FloatingMenu>
293
297
  ) : (
294
298
  "Not translatable"
295
299
  );
@@ -300,6 +304,21 @@ const GlobalPageItem = (props: IGlobalPageItemProps): JSX.Element => {
300
304
 
301
305
  const mainUnpublishAction = { title: "Ok", onClick: toggleUnpublishModal };
302
306
 
307
+ const CategoryColumns = categoryColumns.map((col: any) => {
308
+ const type = globalPage.template[col.from];
309
+ const categories = type && type.map((cat: any) => cat.title);
310
+ return (
311
+ activeColumns.includes(col.key) && (
312
+ <CategoryCell
313
+ key={col.key}
314
+ categories={categories}
315
+ categoryColors={categoryColors}
316
+ addCategoryColors={addCategoryColors}
317
+ />
318
+ )
319
+ );
320
+ });
321
+
303
322
  return (
304
323
  <>
305
324
  <S.StructuredDataRow role="rowgroup" selected={isSelected} disabled={!isEditable}>
@@ -309,27 +328,35 @@ const GlobalPageItem = (props: IGlobalPageItemProps): JSX.Element => {
309
328
  <S.NameCell role="cell" onClick={_handleClick}>
310
329
  {title}
311
330
  </S.NameCell>
312
- {isAllPages ? (
331
+ {isAllPages && activeColumns.includes("type") && (
313
332
  <S.TypeCell role="cell">{structuredData && getStructuredDataTitle(structuredData)}</S.TypeCell>
314
- ) : (
333
+ )}
334
+ {!isAllPages && activeColumns.includes("site") && (
315
335
  <S.SiteCell role="cell">
316
336
  <ElementsTooltip elements={availableSiteNames} />
317
337
  </S.SiteCell>
318
338
  )}
319
- <S.LiveCell role="cell" onClick={_handleClick}>
320
- <Tooltip content={publishedTooltip[getLiveStatus()]}>
321
- <Icon name={getLiveStatus()} />
322
- </Tooltip>
323
- </S.LiveCell>
324
- <S.StatusCell role="cell" onClick={_handleClick}>
325
- <S.ModDate>{`Mod. ${getHumanLastModifiedDate(globalPage.modified)}`}</S.ModDate>
326
- </S.StatusCell>
327
- <S.TransCell role="cell">{translations}</S.TransCell>
328
- <S.SeoCell role="cell">
329
- <SeoItems.Index />
330
- {SeoTitleMenu()}
331
- {SeoDescriptionMenu()}
332
- </S.SeoCell>
339
+ {activeColumns.includes("live") && (
340
+ <S.LiveCell role="cell" onClick={_handleClick}>
341
+ <Tooltip content={publishedTooltip[getLiveStatus()]}>
342
+ <Icon name={getLiveStatus()} />
343
+ </Tooltip>
344
+ </S.LiveCell>
345
+ )}
346
+ {CategoryColumns}
347
+ {activeColumns.includes("status") && (
348
+ <S.StatusCell role="cell" onClick={_handleClick}>
349
+ <S.ModDate>{`Mod. ${getHumanLastModifiedDate(globalPage.modified)}`}</S.ModDate>
350
+ </S.StatusCell>
351
+ )}
352
+ {activeColumns.includes("translation") && <S.TransCell role="cell">{translations}</S.TransCell>}
353
+ {activeColumns.includes("seo") && (
354
+ <S.SeoCell role="cell">
355
+ <SeoItems.Index />
356
+ {SeoTitleMenu()}
357
+ {SeoDescriptionMenu()}
358
+ </S.SeoCell>
359
+ )}
333
360
  <S.ActionsCell role="cell">
334
361
  <S.StyledActionMenu icon="more" options={menuOptions} tooltip="Actions" />
335
362
  </S.ActionsCell>
@@ -378,6 +405,10 @@ interface IGlobalPageItemProps {
378
405
  toggleToast(): void;
379
406
  setDeletedItem(item: number): void;
380
407
  deleteBulk(ids: number[]): Promise<boolean>;
408
+ categoryColumns: any[];
409
+ columns: Record<string, IColumn>;
410
+ categoryColors: any;
411
+ addCategoryColors(cats: string[]): void;
381
412
  }
382
413
 
383
414
  const mapDispatchToProps = {