@griddo/ax 10.6.5 → 10.6.6

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.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@griddo/ax",
3
3
  "description": "Griddo Author Experience",
4
- "version": "10.6.5",
4
+ "version": "10.6.6",
5
5
  "authors": [
6
6
  "Álvaro Sánchez' <alvaro.sanches@secuoyas.com>",
7
7
  "Carlos Torres <carlos.torres@secuoyas.com>",
@@ -233,5 +233,5 @@
233
233
  "publishConfig": {
234
234
  "access": "public"
235
235
  },
236
- "gitHead": "4a065853330bcae74912ddb0f0785af16b0e261a"
236
+ "gitHead": "9ffcd2b0b5b1f5983045cf9d3c77769cec0a2a8d"
237
237
  }
@@ -1,6 +1,6 @@
1
1
  import { template } from "./config";
2
2
  import { IServiceConfig, sendRequest, sendInitialRequest } from "./utils";
3
- import { ICategoryGroupParams, IGetStructuredDataParams, IOrderCategoryParams } from "@ax/types";
3
+ import { ICategoryGroupParams, IExportDataParams, IGetStructuredDataParams, IOrderCategoryParams } from "@ax/types";
4
4
  import { AxiosResponse } from "axios";
5
5
 
6
6
  const SERVICES: { [key: string]: IServiceConfig } = {
@@ -114,6 +114,12 @@ const SERVICES: { [key: string]: IServiceConfig } = {
114
114
  endpoint: "/categories/order/",
115
115
  method: "PUT",
116
116
  },
117
+ EXPORT_DATA_CONTENT: {
118
+ ...template,
119
+ endpoint: ["/structured_data_content/", "/site/", "/export"],
120
+ method: "POST",
121
+ responseType: "blob",
122
+ },
117
123
  };
118
124
 
119
125
  const getData = (token: string | null, siteID?: number | null): Promise<AxiosResponse> => {
@@ -328,6 +334,19 @@ const orderCategory = (data: IOrderCategoryParams): Promise<AxiosResponse> => {
328
334
  return sendRequest(SERVICES.ORDER_CATEGORY, { ...data });
329
335
  };
330
336
 
337
+ const exportDataContent = (
338
+ structuredDataID: string,
339
+ siteID: number | "global",
340
+ data: IExportDataParams
341
+ ): Promise<AxiosResponse> => {
342
+ const { host, endpoint } = SERVICES.EXPORT_DATA_CONTENT;
343
+ const [prefix, infix, suffix] = endpoint;
344
+
345
+ SERVICES.EXPORT_DATA_CONTENT.dynamicUrl = `${host}${prefix}${structuredDataID}${infix}${siteID}${suffix}`;
346
+
347
+ return sendRequest(SERVICES.EXPORT_DATA_CONTENT, { ...data });
348
+ };
349
+
331
350
  export default {
332
351
  getData,
333
352
  getDataContent,
@@ -351,4 +370,5 @@ export default {
351
370
  deleteGroupBulk,
352
371
  orderCategory,
353
372
  getGroup,
373
+ exportDataContent,
354
374
  };
@@ -1,12 +1,12 @@
1
1
  import React from "react";
2
2
 
3
- import { Button, CheckField, TableCounter } from "@ax/components";
3
+ import { Button, CheckField, ExportButton, TableCounter } from "@ax/components";
4
4
  import { IBulkAction } from "@ax/types";
5
5
 
6
6
  import * as S from "./style";
7
7
 
8
8
  const BulkSelectionOptions = (props: IBulkSelectionProps): JSX.Element => {
9
- const { isScrolling, checkState, actions, selectItems, totalItems, className } = props;
9
+ const { isScrolling, checkState, actions, selectItems, totalItems, className, exportAction } = props;
10
10
 
11
11
  const filteredActions = actions.filter((action: IBulkAction | undefined | null) => !!action);
12
12
 
@@ -34,6 +34,7 @@ const BulkSelectionOptions = (props: IBulkSelectionProps): JSX.Element => {
34
34
  </Button>
35
35
  )
36
36
  )}
37
+ {exportAction && <ExportButton onClick={exportAction} />}
37
38
  </S.BulkActions>
38
39
  <S.Counter>
39
40
  <TableCounter totalItems={totalItems} />
@@ -50,6 +51,7 @@ interface IBulkSelectionProps {
50
51
  totalItems: number;
51
52
  isScrolling?: boolean;
52
53
  className?: string;
54
+ exportAction?: (formats: (string | number)[]) => void;
53
55
  }
54
56
 
55
57
  export default BulkSelectionOptions;
@@ -0,0 +1,52 @@
1
+ import React, { useState } from "react";
2
+ import { CheckGroup, Button, FloatingMenu } from "@ax/components";
3
+
4
+ import * as S from "./style";
5
+
6
+ const ExportButton = (props: IExportButtonProps): JSX.Element => {
7
+ const { onClick } = props;
8
+
9
+ const [state, setState] = useState<(string | number)[]>([]);
10
+
11
+ const handleChange = (value: string | (string | number)[]) => Array.isArray(value) && setState(value);
12
+
13
+ const handleClick = () => onClick(state);
14
+
15
+ const options = [
16
+ { name: "csv", value: "csv", title: ".csv" },
17
+ { name: "xml", value: "xml", title: ".xml" },
18
+ { name: "json", value: "json", title: ".json" },
19
+ ];
20
+
21
+ const LinkButton = () => (
22
+ <S.ButtonWrapper>
23
+ <Button className="button" type="button" buttonStyle="text" icon="download">
24
+ Export Data
25
+ </Button>
26
+ </S.ButtonWrapper>
27
+ );
28
+
29
+ return (
30
+ <S.Wrapper>
31
+ <FloatingMenu Button={LinkButton} position="left" closeOnSelect={false} offset={-25}>
32
+ <S.MenuWrapper>
33
+ <S.HelpText>Select the format(s) in which you want to export.</S.HelpText>
34
+ <S.ChecksWrapper>
35
+ <CheckGroup options={options} value={state} onChange={handleChange} multipleSelection={true} />
36
+ </S.ChecksWrapper>
37
+ <S.ExportWrapper>
38
+ <Button className="button" type="button" buttonStyle="line" onClick={handleClick}>
39
+ Export Data
40
+ </Button>
41
+ </S.ExportWrapper>
42
+ </S.MenuWrapper>
43
+ </FloatingMenu>
44
+ </S.Wrapper>
45
+ );
46
+ };
47
+
48
+ export interface IExportButtonProps {
49
+ onClick: (formats: (string | number)[]) => void;
50
+ }
51
+
52
+ export default ExportButton;
@@ -0,0 +1,36 @@
1
+ import styled from "styled-components";
2
+
3
+ const Wrapper = styled.div`
4
+ position: relative;
5
+ `;
6
+
7
+ const ButtonWrapper = styled.div`
8
+ button {
9
+ margin-left: 0 !important;
10
+ margin-right: ${(p) => p.theme.spacing.s} !important;
11
+ }
12
+ `;
13
+
14
+ const MenuWrapper = styled.div`
15
+ padding: ${(p) => `${p.theme.spacing.xs} ${p.theme.spacing.s}`};
16
+ `;
17
+
18
+ const HelpText = styled.div`
19
+ ${(p) => p.theme.textStyle.uiXS};
20
+ color: ${(p) => p.theme.colors.textHighEmphasis};
21
+ `;
22
+
23
+ const ChecksWrapper = styled.div`
24
+ margin-top: ${(p) => p.theme.spacing.xs};
25
+ `;
26
+
27
+ const ExportWrapper = styled.div`
28
+ margin-top: ${(p) => p.theme.spacing.xs};
29
+ button {
30
+ margin-left: 0 !important;
31
+ margin-right: 0 !important;
32
+ width: 100%;
33
+ }
34
+ `;
35
+
36
+ export { Wrapper, ChecksWrapper, MenuWrapper, HelpText, ButtonWrapper, ExportWrapper };
@@ -16,6 +16,7 @@ import {
16
16
  ErrorCenter,
17
17
  SearchField,
18
18
  Modal,
19
+ ExportButton,
19
20
  } from "@ax/components";
20
21
 
21
22
  import { ActionMenu, ActionSimpleMenu, DownArrowButton } from "./atoms";
@@ -50,6 +51,7 @@ const AppBar = (props: IProps): JSX.Element => {
50
51
  hasAnimation,
51
52
  searchValue,
52
53
  isDirty,
54
+ exportAction,
53
55
  } = props;
54
56
 
55
57
  const publishedTooltip: any = {
@@ -280,6 +282,7 @@ const AppBar = (props: IProps): JSX.Element => {
280
282
  <S.Separator />
281
283
  </>
282
284
  )}
285
+ {exportAction && <ExportButton onClick={exportAction} />}
283
286
  {rightLineButton && (
284
287
  <Button
285
288
  className="button"
@@ -344,6 +347,7 @@ export interface IAppBarProps {
344
347
  hasAnimation?: boolean;
345
348
  searchValue?: string;
346
349
  isDirty?: boolean;
350
+ exportAction?(formats: (number | string)[]): void;
347
351
  }
348
352
 
349
353
  type IProps = IAppBarProps & RouteComponentProps;
@@ -56,6 +56,7 @@ export interface IWrapperProps {
56
56
  hasAnimation?: boolean;
57
57
  searchValue?: string;
58
58
  isDirty?: boolean;
59
+ exportAction?(formats: (number | string)[]): void;
59
60
  }
60
61
 
61
62
  export default MainWrapper;
@@ -70,6 +70,7 @@ import EmptyState from "./EmptyState";
70
70
  import ErrorCenter from "./ErrorCenter";
71
71
  import ErrorPage from "./ErrorPage";
72
72
  import ErrorToast from "./ErrorToast";
73
+ import ExportButton from "./ExportButton";
73
74
  import FieldContainer from "./FieldContainer";
74
75
  import FieldsBehavior from "./FieldsBehavior";
75
76
  import FileGallery from "./FileGallery";
@@ -182,6 +183,7 @@ export {
182
183
  ErrorCenter,
183
184
  ErrorPage,
184
185
  ErrorToast,
186
+ ExportButton,
185
187
  FieldContainer,
186
188
  FieldsBehavior,
187
189
  FileGallery,
@@ -54,11 +54,12 @@ import {
54
54
  ICategoryGroupParams,
55
55
  IRootState,
56
56
  IOrderCategoryParams,
57
+ IExportDataParams,
57
58
  } from "@ax/types";
58
59
  import { structuredData } from "@ax/api";
59
60
  import { setTotalItems } from "@ax/containers/Sites/actions";
60
61
  import { appActions } from "@ax/containers/App";
61
- import { deepClone, handleRequest, isEmptyArray } from "@ax/helpers";
62
+ import { dateToString, deepClone, handleRequest, isEmptyArray } from "@ax/helpers";
62
63
  import { findMandatoryStructuredDataErrors } from "@ax/forms";
63
64
 
64
65
  const { setIsLoading, setIsSaving } = appActions;
@@ -761,6 +762,46 @@ function updateCurrentSearch(query: string): (dispatch: Dispatch) => Promise<voi
761
762
  };
762
763
  }
763
764
 
765
+ function exportDataContent(
766
+ structuredDataID: string,
767
+ data: IExportDataParams
768
+ ): (dispatch: Dispatch, getState: any) => Promise<void> {
769
+ return async (dispatch, getState) => {
770
+ try {
771
+ const {
772
+ sites: { currentSiteInfo },
773
+ }: IRootState = getState();
774
+
775
+ const siteID = currentSiteInfo ? currentSiteInfo.id : "global";
776
+ const date = new Date();
777
+ const dateString = dateToString(date, "yyyy-MM-dd");
778
+ const fileName =
779
+ data.format.length === 1
780
+ ? `${structuredDataID}-${dateString}.${data.format[0]}`
781
+ : `${structuredDataID}-${dateString}.zip`;
782
+
783
+ const responseActions = {
784
+ handleSuccess: (response: any) => {
785
+ const url = window.URL.createObjectURL(new Blob([response]));
786
+ const a = document.createElement("a");
787
+ a.href = url;
788
+ a.download = fileName;
789
+ document.body.appendChild(a);
790
+ a.click();
791
+ window.URL.revokeObjectURL(url);
792
+ },
793
+ handleError: (response: any) => appActions.handleError(response)(dispatch),
794
+ };
795
+
796
+ const callback = async () => structuredData.exportDataContent(structuredDataID, siteID, data);
797
+
798
+ await handleRequest(callback, responseActions, [])(dispatch);
799
+ } catch (e) {
800
+ console.log(e);
801
+ }
802
+ };
803
+ }
804
+
764
805
  export {
765
806
  setIsActive,
766
807
  setCategories,
@@ -799,4 +840,5 @@ export {
799
840
  deleteCategoryGroup,
800
841
  orderCategory,
801
842
  updateCurrentSearch,
843
+ exportDataContent,
802
844
  };
@@ -27,6 +27,7 @@ const BulkHeader = (props: IProps): JSX.Element => {
27
27
  isGlobalPages,
28
28
  siteID,
29
29
  maxColumns,
30
+ exportAction,
30
31
  } = props;
31
32
 
32
33
  const isAllowedToDeletePage = usePermission("content.deletePages");
@@ -62,6 +63,7 @@ const BulkHeader = (props: IProps): JSX.Element => {
62
63
  actions={bulkActions}
63
64
  selectItems={selectItems}
64
65
  totalItems={totalItems}
66
+ exportAction={exportAction}
65
67
  />
66
68
  ) : (
67
69
  <TableHeader
@@ -106,6 +108,7 @@ interface IProps {
106
108
  maxColumns: { value: number; text: string };
107
109
  isGlobalPages: boolean;
108
110
  siteID: number;
111
+ exportAction?(formats: (number | string)[]): void;
109
112
  }
110
113
 
111
114
  export default BulkHeader;
@@ -22,6 +22,7 @@ import {
22
22
  IQueryValue,
23
23
  IStructuredData,
24
24
  ISchemaField,
25
+ IExportDataParams,
25
26
  } from "@ax/types";
26
27
  import {
27
28
  MainWrapper,
@@ -134,6 +135,7 @@ const Content = (props: IProps): JSX.Element => {
134
135
  error,
135
136
  currentSearch,
136
137
  updateCurrentSearch,
138
+ exportDataContent,
137
139
  } = props;
138
140
 
139
141
  if (!currentSiteInfo) {
@@ -166,6 +168,7 @@ const Content = (props: IProps): JSX.Element => {
166
168
  const isStructuredData = filter !== "unique-pages" && !checkFromPage;
167
169
  const isGlobalPages = filter !== "unique-pages" && checkFromPage;
168
170
  const isDataEditable = !isStructuredData || (currentStructuredData && currentStructuredData.editable);
171
+ const isDataExportable = currentStructuredData?.exportable || false;
169
172
 
170
173
  const pagesIds = currentSitePages && currentSitePages.map((page: any) => page.id);
171
174
  const dataIds = currentDataContent && currentDataContent.map((data: any) => data.id);
@@ -545,6 +548,15 @@ const Content = (props: IProps): JSX.Element => {
545
548
  setFiltersSelection(filterPointer, filtersSelected);
546
549
  };
547
550
 
551
+ const exportContent = isDataExportable
552
+ ? async (formats: (number | string)[]) => {
553
+ if (currentStructuredData && formats.length) {
554
+ const ids = selectedItems.all.length ? selectedItems.all : undefined;
555
+ await exportDataContent(currentStructuredData?.id, { format: formats as string[], ids });
556
+ }
557
+ }
558
+ : undefined;
559
+
548
560
  const Header = (
549
561
  <BulkHeader
550
562
  showBulk={areItemsSelected(contentIds)}
@@ -568,6 +580,7 @@ const Content = (props: IProps): JSX.Element => {
568
580
  isGlobalPages={isGlobalPages}
569
581
  siteID={currentSiteInfo.id}
570
582
  maxColumns={maxColumns}
583
+ exportAction={exportContent}
571
584
  />
572
585
  );
573
586
 
@@ -845,6 +858,7 @@ const Content = (props: IProps): JSX.Element => {
845
858
  searchAction={updateCurrentSearch}
846
859
  errors={errors}
847
860
  searchValue={currentSearch}
861
+ exportAction={exportContent}
848
862
  >
849
863
  <S.ContentListWrapper>
850
864
  <ContentFilters
@@ -1008,6 +1022,7 @@ interface IDispatchProps {
1008
1022
  getDefaults(): Promise<void>;
1009
1023
  getAvailableSiteDataPacks(queryParams: string | null, loading?: boolean): Promise<void>;
1010
1024
  updateCurrentSearch(query: string): Promise<void>;
1025
+ exportDataContent(structuredDataID: string, data: IExportDataParams): Promise<void>;
1011
1026
  }
1012
1027
 
1013
1028
  const mapDispatchToProps = {
@@ -1048,6 +1063,7 @@ const mapDispatchToProps = {
1048
1063
  getDefaults: navigationActions.getDefaults,
1049
1064
  getAvailableSiteDataPacks: dataPacksActions.getAvailableSiteDataPacks,
1050
1065
  updateCurrentSearch: sitesActions.updateCurrentSearch,
1066
+ exportDataContent: structuredDataActions.exportDataContent,
1051
1067
  };
1052
1068
 
1053
1069
  interface IPagesProps {
@@ -32,6 +32,7 @@ const BulkHeader = (props: IProps): JSX.Element => {
32
32
  columns,
33
33
  setColumns,
34
34
  maxColumns,
35
+ exportAction,
35
36
  } = props;
36
37
 
37
38
  const isAllowedToPublishPages = usePermission("global.globalData.publishUnpublishAllGlobalData");
@@ -67,6 +68,7 @@ const BulkHeader = (props: IProps): JSX.Element => {
67
68
  actions={bulkActions}
68
69
  selectItems={selectItems}
69
70
  totalItems={totalItems}
71
+ exportAction={exportAction}
70
72
  />
71
73
  ) : (
72
74
  <TableHeader
@@ -109,6 +111,7 @@ interface IProps {
109
111
  columns: IColumn[];
110
112
  setColumns: (columns: IColumn[]) => void;
111
113
  maxColumns: { value: number; text: string };
114
+ exportAction?(formats: (number | string)[]): void;
112
115
  }
113
116
 
114
117
  export default BulkHeader;
@@ -5,20 +5,20 @@ import { NavLink } from "react-router-dom";
5
5
  import { IStructuredData } from "@ax/types";
6
6
  import { MenuGroup, MenuItem, SubNav } from "@ax/components";
7
7
  import { pageEditorActions } from "@ax/containers/PageEditor";
8
- import { structuredDataActions } from "@ax/containers/StructuredData";
9
8
 
10
9
  import { getFilters } from "./utils";
11
10
 
12
11
  import * as S from "./style";
13
12
 
14
13
  const ContentFilters = (props: IProps): JSX.Element => {
15
- const { setFilter, current, dynamicValues, onClick, addNew, isAllowedToCreate } = props;
14
+ const { current, dynamicValues, onClick, addNew, isAllowedToCreate } = props;
16
15
 
17
16
  const filters = getFilters(dynamicValues);
18
17
 
19
18
  const handleClick = (value: string) => {
20
- onClick(value);
21
- setFilter(value);
19
+ if (value !== current) {
20
+ onClick(value);
21
+ }
22
22
  };
23
23
 
24
24
  return (
@@ -55,7 +55,6 @@ const ContentFilters = (props: IProps): JSX.Element => {
55
55
 
56
56
  interface IProps {
57
57
  current: string | undefined;
58
- setFilter(filter: string | null): void;
59
58
  addTemplate(template: string): void;
60
59
  dynamicValues: IStructuredData[];
61
60
  onClick(dataID: string): void;
@@ -65,7 +64,6 @@ interface IProps {
65
64
 
66
65
  const mapDispatchToProps = {
67
66
  addTemplate: pageEditorActions.addTemplate,
68
- setFilter: structuredDataActions.setFilter,
69
67
  };
70
68
 
71
69
  export default connect(null, mapDispatchToProps)(ContentFilters);
@@ -21,16 +21,15 @@ const useFilterQuery = (
21
21
  currentStructuredData: IStructuredData | null,
22
22
  values: Record<string, IStructuredDataQueryValues> | null
23
23
  ): IUseFilterQuery => {
24
-
25
24
  const structuredDataType = currentStructuredData ? currentStructuredData.id : "all";
26
25
  const initialQueryValues: IStructuredDataQueryValues = {
27
- types: [{value: "all", label: "All"}],
28
- translated: [{value: "all", label: "All"}],
29
- liveStatus: [{value: "all", label: "All"}],
26
+ types: [{ value: "all", label: "All" }],
27
+ translated: [{ value: "all", label: "All" }],
28
+ liveStatus: [{ value: "all", label: "All" }],
30
29
  order: [],
31
- filterSites: [{value: "all", label: "All"}],
32
- categories: [{value: "all", label: "All"}],
33
- related: [{value: "all", label: "All"}],
30
+ filterSites: [{ value: "all", label: "All" }],
31
+ categories: [{ value: "all", label: "All" }],
32
+ related: [{ value: "all", label: "All" }],
34
33
  };
35
34
 
36
35
  const getFilterQuery = (filterValues: IStructuredDataQueryValues): string => {
@@ -38,9 +37,10 @@ const useFilterQuery = (
38
37
  let filterQuery = "";
39
38
 
40
39
  const currentQuery = (pointer: string, values: IQueryValue[]): string => {
41
- const stringValues = Array.isArray(values) && values.length
42
- ? values.map((value) => (value.value !== "all" ? value.value : "")).join(",")
43
- : "";
40
+ const stringValues =
41
+ Array.isArray(values) && values.length
42
+ ? values.map((value) => (value.value !== "all" ? value.value : "")).join(",")
43
+ : "";
44
44
 
45
45
  return !stringValues.length
46
46
  ? filterQuery
@@ -86,7 +86,7 @@ const useFilterQuery = (
86
86
  types: pointer === "types" ? filter : types,
87
87
  translated: pointer === "translated" ? filter : translated,
88
88
  liveStatus: pointer === "liveStatus" ? filter : liveStatus,
89
- order: pointer === "order" ? [{value: `${filter[0].value}-${orderMethod}`, label: filter[0].label}] : order,
89
+ order: pointer === "order" ? [{ value: `${filter[0].value}-${orderMethod}`, label: filter[0].label }] : order,
90
90
  filterSites: pointer === "filterSites" ? filter : filterSites,
91
91
  categories: pointer === "categories" ? filter : categories,
92
92
  related: pointer === "related" ? filter : related,
@@ -19,6 +19,7 @@ import {
19
19
  IStructuredDataQueryValues,
20
20
  IQueryValue,
21
21
  ISchemaField,
22
+ IExportDataParams,
22
23
  } from "@ax/types";
23
24
  import {
24
25
  ISetCurrentPageIDAction,
@@ -107,6 +108,7 @@ const StructuredDataList = (props: IProps): JSX.Element => {
107
108
  currentSearch,
108
109
  updateCurrentSearch,
109
110
  resetCurrentData,
111
+ exportDataContent,
110
112
  } = props;
111
113
 
112
114
  const itemsPerPage = 50;
@@ -153,6 +155,7 @@ const StructuredDataList = (props: IProps): JSX.Element => {
153
155
  const isDataTranslatable = currentStructuredData && currentStructuredData.translate;
154
156
  const isAllPages = filter === "all-pages";
155
157
  const isStructuredDataFromPage = !!currentStructuredData?.fromPage || isAllPages;
158
+ const isDataExportable = currentStructuredData?.exportable || false;
156
159
  const dataIds = isStructuredDataFromPage
157
160
  ? currentSitePages.map((page: IPage) => page.id)
158
161
  : currentDataContent.map((data: IStructuredDataContent) => data.id);
@@ -165,8 +168,9 @@ const StructuredDataList = (props: IProps): JSX.Element => {
165
168
  ? currentStructuredData.schema.fields.filter((field: ISchemaField) => field.showList)
166
169
  : [];
167
170
 
171
+ const type = currentStructuredData ? currentStructuredData.id : "all";
168
172
  const columns = getColumns(categoryColumns, isStructuredDataFromPage, isAllPages, maxColumns.value);
169
- const [columnsState, setColumnsState] = useState<Record<string, IColumn[]>>({ all: columns });
173
+ const [columnsState, setColumnsState] = useState<Record<string, IColumn[]>>({ all: [], [type]: columns });
170
174
 
171
175
  const {
172
176
  resetBulkSelection,
@@ -236,28 +240,21 @@ const StructuredDataList = (props: IProps): JSX.Element => {
236
240
  }, []);
237
241
 
238
242
  useEffect(() => {
239
- const columns = getColumns(categoryColumns, isStructuredDataFromPage, isAllPages, maxColumns.value);
240
-
241
- const isGlobalData = structuredData.global.some((data) => data.id === currentStructuredData?.id);
242
- const type = currentStructuredData && isGlobalData ? currentStructuredData.id : "all";
243
+ const type = currentStructuredData ? currentStructuredData.id : "all";
243
244
  setStructuredDataType(type);
244
245
 
245
- if (filter === "all-pages" || !isStructuredDataFromPage) {
246
- setColumnsState({ all: columns });
247
- }
248
-
249
- if (filter !== "all-pages" && currentStructuredData) {
246
+ if (!columnsState[type] || type === "all") {
247
+ const columns = getColumns(categoryColumns, isStructuredDataFromPage, isAllPages, maxColumns.value);
250
248
  setColumnsState((state) => ({
251
249
  ...state,
252
- [currentStructuredData.id]: columns,
250
+ [type]: columns,
253
251
  }));
254
252
  }
255
253
  // eslint-disable-next-line react-hooks/exhaustive-deps
256
- }, [currentStructuredData]);
254
+ }, [filter]);
257
255
 
258
256
  useEffect(() => {
259
- const isGlobalData = structuredData.global.some((data) => data.id === currentStructuredData?.id);
260
- const type = currentStructuredData && isGlobalData ? currentStructuredData.id : "all";
257
+ const type = currentStructuredData ? currentStructuredData.id : "all";
261
258
  const updatedColumns = updateColumns(columnsState[type], maxColumns.value);
262
259
  setColumnsState((state) => ({
263
260
  ...state,
@@ -332,12 +329,13 @@ const StructuredDataList = (props: IProps): JSX.Element => {
332
329
  };
333
330
 
334
331
  const handleMenuClick = async (dataID: string) => {
335
- if (filter === "all-pages" || !isStructuredDataFromPage) {
332
+ if (dataID === "all-pages" || !isStructuredDataFromPage) {
336
333
  filterItems("filterSites", [{ value: "all", label: "All" }]);
337
334
  }
338
- setPage(firstPage);
335
+ setFilter(dataID);
339
336
  setSelectedStructuredData(dataID, scope);
340
337
  unselectAllItems();
338
+ setPage(firstPage);
341
339
  };
342
340
 
343
341
  const createNewData = () => {
@@ -455,6 +453,15 @@ const StructuredDataList = (props: IProps): JSX.Element => {
455
453
  setFiltersSelection(filterPointer, filtersSelected);
456
454
  };
457
455
 
456
+ const exportContent = isDataExportable
457
+ ? async (formats: (number | string)[]) => {
458
+ if (currentStructuredData && formats.length) {
459
+ const ids = selectedItems.all.length ? selectedItems.all : undefined;
460
+ await exportDataContent(currentStructuredData?.id, { format: formats as string[], ids });
461
+ }
462
+ }
463
+ : undefined;
464
+
458
465
  const currentDataColumnsState = currentStructuredData ? columnsState[structuredDataType] || [] : columnsState["all"];
459
466
 
460
467
  const TableHeader = (
@@ -479,6 +486,7 @@ const StructuredDataList = (props: IProps): JSX.Element => {
479
486
  columns={currentDataColumnsState}
480
487
  setColumns={changeColumnsState}
481
488
  maxColumns={maxColumns}
489
+ exportAction={exportContent}
482
490
  />
483
491
  );
484
492
 
@@ -610,6 +618,7 @@ const StructuredDataList = (props: IProps): JSX.Element => {
610
618
  languageActions={languageProps.languageActions}
611
619
  searchAction={updateCurrentSearch}
612
620
  searchValue={currentSearch}
621
+ exportAction={exportContent}
613
622
  >
614
623
  <S.StructuredDataWrapper ref={wrapperRef}>
615
624
  <ContentFilters
@@ -737,6 +746,7 @@ const mapDispatchToProps = {
737
746
  checkUserSession: appActions.checkUserSession,
738
747
  updateCurrentSearch: structuredDataActions.updateCurrentSearch,
739
748
  resetCurrentData: structuredDataActions.resetCurrentData,
749
+ exportDataContent: structuredDataActions.exportDataContent,
740
750
  };
741
751
 
742
752
  interface IDispatchProps {
@@ -765,6 +775,7 @@ interface IDispatchProps {
765
775
  checkUserSession(): Promise<void>;
766
776
  updateCurrentSearch(query: string): Promise<void>;
767
777
  resetCurrentData(): Promise<void>;
778
+ exportDataContent(structuredDataID: string, data: IExportDataParams): Promise<void>;
768
779
  }
769
780
 
770
781
  interface ICategoriesProps {
@@ -451,6 +451,7 @@ export interface IStructuredData {
451
451
  structuredData?: string;
452
452
  editable: boolean;
453
453
  dataPacks: string[];
454
+ exportable?: boolean;
454
455
  }
455
456
 
456
457
  export interface IDataLanguage {
@@ -1084,6 +1085,11 @@ export interface ITemplateOption {
1084
1085
  isData?: boolean;
1085
1086
  }
1086
1087
 
1088
+ export interface IExportDataParams {
1089
+ ids?: number[];
1090
+ format: string[];
1091
+ }
1092
+
1087
1093
  export type Field =
1088
1094
  | "AsyncCheckGroup"
1089
1095
  | "AsyncSelect"