@griddo/ax 10.6.5 → 10.6.7
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 +2 -2
- package/src/api/structuredData.tsx +21 -1
- package/src/components/BulkSelectionOptions/index.tsx +4 -2
- package/src/components/ExportButton/index.tsx +52 -0
- package/src/components/ExportButton/style.tsx +36 -0
- package/src/components/MainWrapper/AppBar/index.tsx +4 -0
- package/src/components/MainWrapper/index.tsx +1 -0
- package/src/components/index.tsx +2 -0
- package/src/containers/StructuredData/actions.tsx +43 -1
- package/src/modules/Content/BulkHeader/index.tsx +3 -0
- package/src/modules/Content/index.tsx +16 -0
- package/src/modules/StructuredData/StructuredDataList/BulkHeader/index.tsx +3 -0
- package/src/modules/StructuredData/StructuredDataList/ContentFilters/index.tsx +4 -6
- package/src/modules/StructuredData/StructuredDataList/hooks.tsx +11 -11
- package/src/modules/StructuredData/StructuredDataList/index.tsx +27 -16
- package/src/types/index.tsx +6 -0
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.
|
|
4
|
+
"version": "10.6.7",
|
|
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": "
|
|
236
|
+
"gitHead": "7518a5fa486026aeeceee57d87fac1841e9e35a6"
|
|
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;
|
package/src/components/index.tsx
CHANGED
|
@@ -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 {
|
|
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
|
-
|
|
21
|
-
|
|
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 =
|
|
42
|
-
|
|
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
|
|
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 (
|
|
246
|
-
|
|
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
|
-
[
|
|
250
|
+
[type]: columns,
|
|
253
251
|
}));
|
|
254
252
|
}
|
|
255
253
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
256
|
-
}, [
|
|
254
|
+
}, [filter]);
|
|
257
255
|
|
|
258
256
|
useEffect(() => {
|
|
259
|
-
const
|
|
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 (
|
|
332
|
+
if (dataID === "all-pages" || !isStructuredDataFromPage) {
|
|
336
333
|
filterItems("filterSites", [{ value: "all", label: "All" }]);
|
|
337
334
|
}
|
|
338
|
-
|
|
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 {
|
package/src/types/index.tsx
CHANGED
|
@@ -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"
|