@griddo/ax 1.68.7 → 1.69.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/config/webpack.config.js +24 -0
- package/package.json +6 -2
- package/src/__mocks__/axios/ReferenceField.ts +471 -0
- package/src/{__tests__/components/Fields/UrlField → __mocks__}/mockedAxios.ts +0 -0
- package/src/__mocks__/reducers/structuredData.tsx +10 -0
- package/src/__mocks__/store/ReferenceField.ts +1671 -0
- package/src/__tests__/components/Fields/AnalyticsField/AnalyticsField.test.tsx +20 -28
- package/src/__tests__/components/Fields/CheckGroup/CheckGroup.test.tsx +16 -28
- package/src/__tests__/components/Fields/MultiCheckSelectGroup/MultiCheckSelectGroup.test.tsx +120 -0
- package/src/__tests__/components/Fields/ReferenceField/ReferenceField.test.tsx +532 -0
- package/src/__tests__/components/Fields/TextField/TextField.test.tsx +0 -1
- package/src/__tests__/components/Fields/UrlField/UrlField.test.tsx +14 -13
- package/src/__tests__/components/Fields/Wysiwyg/Wysiwyg.test.tsx +121 -0
- package/src/components/Fields/ComponentArray/MixableComponentArray/PasteModuleButton/index.tsx +4 -3
- package/src/components/Fields/ComponentArray/MixableComponentArray/index.tsx +69 -34
- package/src/components/Fields/ComponentArray/SameComponentArray/index.tsx +59 -26
- package/src/components/Fields/ComponentContainer/atoms.tsx +2 -8
- package/src/components/Fields/ComponentContainer/index.tsx +21 -21
- package/src/components/Fields/ComponentContainer/style.tsx +49 -28
- package/src/components/Fields/MultiCheckSelectGroup/index.tsx +2 -2
- package/src/components/Fields/MultiCheckSelectGroup/style.tsx +4 -4
- package/src/components/Fields/ReferenceField/AutoPanel/AutoItem/index.tsx +1 -1
- package/src/components/Fields/ReferenceField/AutoPanel/index.tsx +2 -4
- package/src/components/Fields/ReferenceField/AutoPanel/style.tsx +3 -0
- package/src/components/Fields/ReferenceField/Context/index.tsx +3 -3
- package/src/components/Fields/ReferenceField/ItemList/Item/index.tsx +15 -24
- package/src/components/Fields/ReferenceField/ItemList/Item/style.tsx +22 -15
- package/src/components/Fields/ReferenceField/ItemList/index.tsx +42 -11
- package/src/components/Fields/ReferenceField/ManualPanel/Item/index.tsx +1 -1
- package/src/components/Fields/ReferenceField/index.tsx +5 -6
- package/src/components/Fields/Wysiwyg/index.tsx +4 -4
- package/src/components/Gallery/GalleryPanel/DetailPanel/index.tsx +12 -4
- package/src/components/Gallery/GalleryPanel/index.tsx +10 -2
- package/src/components/Gallery/index.tsx +5 -1
- package/src/components/MainWrapper/AppBar/index.tsx +1 -1
- package/src/containers/App/reducer.tsx +1 -0
- package/src/containers/Gallery/actions.tsx +11 -5
- package/src/containers/Navigation/Defaults/actions.tsx +2 -2
- package/src/containers/PageEditor/actions.tsx +18 -7
- package/src/forms/elements.tsx +5 -6
- package/src/helpers/arrays.tsx +1 -2
- package/src/modules/Content/PageItem/index.tsx +13 -2
- package/src/modules/Content/index.tsx +18 -1
- package/src/modules/GlobalEditor/Editor/index.tsx +2 -2
- package/src/modules/GlobalEditor/index.tsx +9 -7
- package/src/modules/Navigation/Defaults/DefaultsEditor/Editor/index.tsx +1 -1
- package/src/modules/PageEditor/Editor/index.tsx +2 -2
- package/src/modules/PageEditor/index.tsx +8 -6
- package/src/modules/StructuredData/Form/index.tsx +7 -4
- package/src/modules/StructuredData/StructuredDataList/GlobalPageItem/index.tsx +25 -3
- package/src/modules/StructuredData/StructuredDataList/index.tsx +4 -0
- package/src/__mocks__/reducers/analyticsState.tsx +0 -14
- package/src/__mocks__/reducers/app.tsx +0 -10
- package/src/__mocks__/reducers/pageEditor.tsx +0 -30
- package/src/__mocks__/reducers/sites.tsx +0 -10
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
+
import { DraggableProvided } from "react-beautiful-dnd";
|
|
3
|
+
|
|
2
4
|
import { IDataSource, IStructuredDataContent } from "@ax/types";
|
|
3
5
|
import { getFormattedDateWithTimezone } from "@ax/helpers";
|
|
4
6
|
|
|
5
|
-
import { FloatingMenu, Icon, IconAction
|
|
7
|
+
import { FloatingMenu, Icon, IconAction } from "@ax/components";
|
|
6
8
|
|
|
7
9
|
import * as S from "./style";
|
|
8
10
|
|
|
9
11
|
const Item = (props: IProps) => {
|
|
10
|
-
const { item, handleDelete,
|
|
12
|
+
const { item, handleDelete, listLength, source, innerRef, provided } = props;
|
|
11
13
|
|
|
12
14
|
const removeItem = () => {
|
|
13
15
|
handleDelete(item);
|
|
@@ -20,22 +22,12 @@ const Item = (props: IProps) => {
|
|
|
20
22
|
);
|
|
21
23
|
|
|
22
24
|
const actionMenuItem = (item: any) => (
|
|
23
|
-
<S.ActionItem key={item.icon} onClick={item.action}>
|
|
25
|
+
<S.ActionItem key={item.icon} onClick={item.action} data-testid="action-menu-item">
|
|
24
26
|
<Icon name={item.icon} />
|
|
25
27
|
<S.ActionText>{item.label}</S.ActionText>
|
|
26
28
|
</S.ActionItem>
|
|
27
29
|
);
|
|
28
30
|
|
|
29
|
-
const moveModule = (e: any, isPush: boolean) => {
|
|
30
|
-
e.preventDefault();
|
|
31
|
-
e.stopPropagation();
|
|
32
|
-
handleReorder(item, isPush);
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
const handleUpClick = (e: any) => moveModule(e, false);
|
|
36
|
-
|
|
37
|
-
const handleDownClick = (e: any) => moveModule(e, true);
|
|
38
|
-
|
|
39
31
|
const editMenu = {
|
|
40
32
|
options: [
|
|
41
33
|
{
|
|
@@ -53,19 +45,18 @@ const Item = (props: IProps) => {
|
|
|
53
45
|
);
|
|
54
46
|
|
|
55
47
|
return (
|
|
56
|
-
<S.Item>
|
|
48
|
+
<S.Item ref={innerRef} data-testid="reference-field-item" {...provided?.draggableProps}>
|
|
49
|
+
{listLength > 1 && (
|
|
50
|
+
<S.HandleWrapper {...provided?.dragHandleProps}>
|
|
51
|
+
<S.IconHandleWrapper>
|
|
52
|
+
<Icon name="drag" size="16" />
|
|
53
|
+
</S.IconHandleWrapper>
|
|
54
|
+
</S.HandleWrapper>
|
|
55
|
+
)}
|
|
57
56
|
<S.TextWrapper>
|
|
58
57
|
<S.Header>
|
|
59
58
|
<S.Type>{source?.title.toUpperCase()}</S.Type>
|
|
60
59
|
{item.modified && <S.Date>{getFormattedDateWithTimezone(item.modified, "d MMM Y")}</S.Date>}
|
|
61
|
-
<S.ReorderArrowsWrapper>
|
|
62
|
-
<ReorderArrows
|
|
63
|
-
handleDownClick={handleDownClick}
|
|
64
|
-
handleUpClick={handleUpClick}
|
|
65
|
-
listLength={listLength}
|
|
66
|
-
index={index}
|
|
67
|
-
/>
|
|
68
|
-
</S.ReorderArrowsWrapper>
|
|
69
60
|
</S.Header>
|
|
70
61
|
<S.Title>{item.content.title}</S.Title>
|
|
71
62
|
</S.TextWrapper>
|
|
@@ -76,11 +67,11 @@ const Item = (props: IProps) => {
|
|
|
76
67
|
|
|
77
68
|
interface IProps {
|
|
78
69
|
item: IStructuredDataContent;
|
|
79
|
-
index: number;
|
|
80
70
|
listLength: number;
|
|
81
71
|
source: IDataSource;
|
|
82
72
|
handleDelete(item: IStructuredDataContent): void;
|
|
83
|
-
|
|
73
|
+
innerRef: any;
|
|
74
|
+
provided: DraggableProvided;
|
|
84
75
|
}
|
|
85
76
|
|
|
86
77
|
export default Item;
|
|
@@ -20,10 +20,11 @@ const IconActionWrapper = styled.div`
|
|
|
20
20
|
const Item = styled.li`
|
|
21
21
|
position: relative;
|
|
22
22
|
display: flex;
|
|
23
|
+
align-items: stretch;
|
|
23
24
|
background-color: ${(p) => p.theme.color.uiBarBackground};
|
|
24
25
|
border: ${(p) => `1px solid ${p.theme.color.uiLine}`};
|
|
25
26
|
border-radius: ${(p) => p.theme.radii.s};
|
|
26
|
-
padding: ${(p) => p.theme.spacing.s};
|
|
27
|
+
padding: ${(p) => `${p.theme.spacing.s} ${p.theme.spacing.s} ${p.theme.spacing.s} ${p.theme.spacing.xs}`};
|
|
27
28
|
margin-bottom: ${(p) => p.theme.spacing.xxs};
|
|
28
29
|
cursor: pointer;
|
|
29
30
|
&:hover {
|
|
@@ -49,7 +50,7 @@ const Header = styled.div`
|
|
|
49
50
|
display: flex;
|
|
50
51
|
justify-content: space-between;
|
|
51
52
|
align-items: center;
|
|
52
|
-
padding-right: ${p => p.theme.spacing.l};
|
|
53
|
+
padding-right: ${(p) => p.theme.spacing.l};
|
|
53
54
|
margin-bottom: ${(p) => p.theme.spacing.xxs};
|
|
54
55
|
`;
|
|
55
56
|
|
|
@@ -66,7 +67,6 @@ const Type = styled.div`
|
|
|
66
67
|
const Title = styled.div`
|
|
67
68
|
${(p) => p.theme.textStyle.fieldContent};
|
|
68
69
|
color: ${(p) => p.theme.color.textHighEmphasis};
|
|
69
|
-
max-width: 75%;
|
|
70
70
|
`;
|
|
71
71
|
|
|
72
72
|
const ActionMenu = styled.ul`
|
|
@@ -104,19 +104,25 @@ const ActionItem = styled.li`
|
|
|
104
104
|
const ButtonsWrapper = styled.span`
|
|
105
105
|
display: flex;
|
|
106
106
|
position: absolute;
|
|
107
|
-
bottom: ${p => p.theme.spacing.xs};
|
|
108
|
-
right: ${p => p.theme.spacing.xs};
|
|
107
|
+
bottom: ${(p) => p.theme.spacing.xs};
|
|
108
|
+
right: ${(p) => p.theme.spacing.xs};
|
|
109
109
|
`;
|
|
110
110
|
|
|
111
|
-
const
|
|
112
|
-
position: absolute;
|
|
113
|
-
right: 0;
|
|
114
|
-
bottom: -${p => p.theme.spacing.xxs};
|
|
115
|
-
white-space: nowrap;
|
|
111
|
+
const HandleWrapper = styled.div`
|
|
116
112
|
display: flex;
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
113
|
+
align-items: center;
|
|
114
|
+
padding-right: ${(p) => p.theme.spacing.xxs};
|
|
115
|
+
`;
|
|
116
|
+
|
|
117
|
+
const IconHandleWrapper = styled.div`
|
|
118
|
+
width: ${(p) => p.theme.spacing.s};
|
|
119
|
+
height: ${(p) => p.theme.spacing.s};
|
|
120
|
+
svg {
|
|
121
|
+
path {
|
|
122
|
+
fill: ${(p) => p.theme.color.textLowEmphasis};
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
`;
|
|
120
126
|
|
|
121
127
|
export {
|
|
122
128
|
IconActionWrapper,
|
|
@@ -130,5 +136,6 @@ export {
|
|
|
130
136
|
ActionText,
|
|
131
137
|
ActionItem,
|
|
132
138
|
ButtonsWrapper,
|
|
133
|
-
|
|
134
|
-
|
|
139
|
+
HandleWrapper,
|
|
140
|
+
IconHandleWrapper,
|
|
141
|
+
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React, { useEffect } from "react";
|
|
2
2
|
import { connect } from "react-redux";
|
|
3
|
+
import { DragDropContext, Droppable, Draggable, DropResult } from "react-beautiful-dnd";
|
|
3
4
|
|
|
4
5
|
import { structuredData } from "@ax/api";
|
|
5
6
|
import { IDataSource, IRootState, IStructuredDataContent } from "@ax/types";
|
|
@@ -58,23 +59,53 @@ const ItemList = (props: IProps) => {
|
|
|
58
59
|
}
|
|
59
60
|
};
|
|
60
61
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
62
|
+
const onDragEnd = (result: DropResult) => {
|
|
63
|
+
if (!result.destination) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (result.destination.index === result.source.index) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const item = selectedItems.find((elem: IStructuredDataContent) => elem.id === parseInt(result.draggableId));
|
|
72
|
+
setReorderElements(item, result.destination.index);
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const ComponentList = React.memo(function ComponentList({ components }: any) {
|
|
76
|
+
return components.map((item: IStructuredDataContent, index: number) => {
|
|
77
|
+
const source = sourceTitles.find((el: IDataSource) => el.id === item.structuredData);
|
|
78
|
+
return (
|
|
79
|
+
<Draggable draggableId={`${item.id}`} index={index} key={item.id}>
|
|
80
|
+
{(provided) => (
|
|
67
81
|
<Item
|
|
68
|
-
key={index}
|
|
69
82
|
item={item}
|
|
70
83
|
handleDelete={handleDelete}
|
|
71
|
-
handleReorder={setReorderElements}
|
|
72
|
-
index={index}
|
|
73
84
|
listLength={selectedItems.length}
|
|
74
85
|
source={source}
|
|
86
|
+
innerRef={provided.innerRef}
|
|
87
|
+
provided={provided}
|
|
75
88
|
/>
|
|
76
|
-
)
|
|
77
|
-
|
|
89
|
+
)}
|
|
90
|
+
</Draggable>
|
|
91
|
+
);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
return (
|
|
96
|
+
<S.ItemList>
|
|
97
|
+
{selectedItems && (
|
|
98
|
+
<DragDropContext onDragEnd={onDragEnd}>
|
|
99
|
+
<Droppable droppableId="referenceList">
|
|
100
|
+
{(provided) => (
|
|
101
|
+
<div ref={provided.innerRef} {...provided.droppableProps}>
|
|
102
|
+
<ComponentList components={selectedItems} />
|
|
103
|
+
{provided.placeholder}
|
|
104
|
+
</div>
|
|
105
|
+
)}
|
|
106
|
+
</Droppable>
|
|
107
|
+
</DragDropContext>
|
|
108
|
+
)}
|
|
78
109
|
</S.ItemList>
|
|
79
110
|
);
|
|
80
111
|
};
|
|
@@ -15,7 +15,7 @@ const Item = (props: IProps) => {
|
|
|
15
15
|
};
|
|
16
16
|
|
|
17
17
|
return (
|
|
18
|
-
<S.Item onClick={handleItemClick}>
|
|
18
|
+
<S.Item onClick={handleItemClick} data-testid="manual-panel-item">
|
|
19
19
|
<CheckField name="check" value={item.id} checked={isChecked} disabled={disabled} />
|
|
20
20
|
<S.TextWrapper>
|
|
21
21
|
<S.Header>
|
|
@@ -13,13 +13,13 @@ import { useReference, ReferenceProvider } from "./Context";
|
|
|
13
13
|
|
|
14
14
|
import * as S from "./style";
|
|
15
15
|
|
|
16
|
-
const ReferenceFieldWithProvider = (props:
|
|
16
|
+
const ReferenceFieldWithProvider = (props: IReferenceFieldProps) => (
|
|
17
17
|
<ReferenceProvider modes={props.selectionType}>
|
|
18
18
|
<ReferenceField {...props} />
|
|
19
19
|
</ReferenceProvider>
|
|
20
20
|
);
|
|
21
21
|
|
|
22
|
-
const ReferenceField = (props:
|
|
22
|
+
const ReferenceField = (props: IReferenceFieldProps) => {
|
|
23
23
|
const {
|
|
24
24
|
source,
|
|
25
25
|
value,
|
|
@@ -139,9 +139,8 @@ const ReferenceField = (props: IProps) => {
|
|
|
139
139
|
const directionLabel = state.orderDirection === "ASC" ? "(ascendent)" : "(descendent)";
|
|
140
140
|
return `${orderLabel} ${directionLabel}`;
|
|
141
141
|
};
|
|
142
|
-
|
|
143
142
|
const autoData = (
|
|
144
|
-
<S.DataWrapper>
|
|
143
|
+
<S.DataWrapper data-testid="auto-data-wrapper">
|
|
145
144
|
<S.SourcesWrapper>
|
|
146
145
|
{value &&
|
|
147
146
|
value.source &&
|
|
@@ -182,7 +181,7 @@ const ReferenceField = (props: IProps) => {
|
|
|
182
181
|
const Asterisk = () => (mandatory ? <S.Asterisk>*</S.Asterisk> : null);
|
|
183
182
|
|
|
184
183
|
return (
|
|
185
|
-
<S.Wrapper>
|
|
184
|
+
<S.Wrapper data-testid="reference-field-wrapper">
|
|
186
185
|
<S.Label>
|
|
187
186
|
Elements
|
|
188
187
|
<Asterisk />
|
|
@@ -218,7 +217,7 @@ const ReferenceField = (props: IProps) => {
|
|
|
218
217
|
);
|
|
219
218
|
};
|
|
220
219
|
|
|
221
|
-
interface
|
|
220
|
+
export interface IReferenceFieldProps {
|
|
222
221
|
source: string[];
|
|
223
222
|
value: any;
|
|
224
223
|
onChange: (value: any) => void;
|
|
@@ -9,7 +9,7 @@ import { wysiwygConfig, buttons, buttonsFull } from "./config";
|
|
|
9
9
|
import "./vendors";
|
|
10
10
|
import * as S from "./style";
|
|
11
11
|
|
|
12
|
-
const Wysiwyg = (props:
|
|
12
|
+
const Wysiwyg = (props: IWysiwygProps): JSX.Element => {
|
|
13
13
|
const {
|
|
14
14
|
value,
|
|
15
15
|
error,
|
|
@@ -64,13 +64,13 @@ const Wysiwyg = (props: IProps): JSX.Element => {
|
|
|
64
64
|
const config = { ...wysiwygConfig, ...dynamicConfig };
|
|
65
65
|
|
|
66
66
|
return (
|
|
67
|
-
<S.EditorWrapper error={error} disabled={disabled}>
|
|
67
|
+
<S.EditorWrapper error={error} disabled={disabled} data-testid="wysiwyg-wrapper">
|
|
68
68
|
<FroalaEditor tag="textarea" model={value} config={config} onModelChange={handleChange} />
|
|
69
69
|
</S.EditorWrapper>
|
|
70
70
|
);
|
|
71
71
|
};
|
|
72
72
|
|
|
73
|
-
interface
|
|
73
|
+
interface IProps {
|
|
74
74
|
name: string;
|
|
75
75
|
value: string;
|
|
76
76
|
title: string;
|
|
@@ -97,6 +97,6 @@ const mapDispatchToProps = {
|
|
|
97
97
|
uploadImage: galleryActions.uploadImage,
|
|
98
98
|
};
|
|
99
99
|
|
|
100
|
-
type
|
|
100
|
+
export type IWysiwygProps = IProps & IDispatchProps;
|
|
101
101
|
|
|
102
102
|
export default connect(mapStateToProps, mapDispatchToProps)(Wysiwyg);
|
|
@@ -145,10 +145,18 @@ const GalleryDetailPanel = (props: IProps) => {
|
|
|
145
145
|
<IconAction icon="OpenOutside" size="m" onClick={handleOpenUrl} />
|
|
146
146
|
</S.ImageWrapper>
|
|
147
147
|
<S.ImageName>{imageSelected.name}</S.ImageName>
|
|
148
|
-
<S.Date
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
<S.
|
|
148
|
+
<S.Date>
|
|
149
|
+
<strong>Uploaded:</strong> {getFormattedDateWithTimezone(imageSelected.published, "d MMM Y")}
|
|
150
|
+
</S.Date>
|
|
151
|
+
<S.Type>
|
|
152
|
+
<strong>Type:</strong> {getFileExtension(imageSelected.name)}
|
|
153
|
+
</S.Type>
|
|
154
|
+
<S.ImageSize>
|
|
155
|
+
<strong>Size:</strong> {formatBytes(imageSelected.size)}
|
|
156
|
+
</S.ImageSize>
|
|
157
|
+
<S.ImageDimensions>
|
|
158
|
+
<strong>Resolution:</strong> {dimensions}
|
|
159
|
+
</S.ImageDimensions>
|
|
152
160
|
</S.ImageInfoWrapper>
|
|
153
161
|
<S.FormWrapper>
|
|
154
162
|
<FieldsBehavior
|
|
@@ -7,8 +7,16 @@ import DetailPanel from "./DetailPanel";
|
|
|
7
7
|
import * as S from "./style";
|
|
8
8
|
|
|
9
9
|
const GalleryPanel = (props: IGalleryPanelProps) => {
|
|
10
|
-
const {
|
|
11
|
-
|
|
10
|
+
const {
|
|
11
|
+
isImageSelected,
|
|
12
|
+
imageSelected,
|
|
13
|
+
validFormats,
|
|
14
|
+
setImage,
|
|
15
|
+
isGlobalTab,
|
|
16
|
+
site,
|
|
17
|
+
selectedTab,
|
|
18
|
+
refreshImages,
|
|
19
|
+
} = props;
|
|
12
20
|
const allowUpload = !isGlobalTab || !selectedTab;
|
|
13
21
|
|
|
14
22
|
return (
|
|
@@ -56,6 +56,10 @@ const Gallery = (props: IProps): JSX.Element => {
|
|
|
56
56
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
57
57
|
}, [galleryScope]);
|
|
58
58
|
|
|
59
|
+
useEffect(() => {
|
|
60
|
+
setImageSelectedData(data);
|
|
61
|
+
}, [data]);
|
|
62
|
+
|
|
59
63
|
useEffect(() => {
|
|
60
64
|
const handleScroll = () => {
|
|
61
65
|
const loadMore =
|
|
@@ -172,7 +176,7 @@ const Gallery = (props: IProps): JSX.Element => {
|
|
|
172
176
|
<S.GridItem key={item.name + index} orientation={item.orientation}>
|
|
173
177
|
<S.ImageWrapper
|
|
174
178
|
onClick={handleClick(item)}
|
|
175
|
-
selected={isSelected
|
|
179
|
+
selected={isSelected}
|
|
176
180
|
orientation={item.orientation}
|
|
177
181
|
>
|
|
178
182
|
<img src={item.thumb} alt={item.alt} />
|
|
@@ -208,7 +208,7 @@ const AppBar = (props: IProps): JSX.Element => {
|
|
|
208
208
|
<S.Separator />
|
|
209
209
|
</>
|
|
210
210
|
)}
|
|
211
|
-
{errors && errors.length > 0 && (
|
|
211
|
+
{isFromEditor && errors && errors.length > 0 && (
|
|
212
212
|
<>
|
|
213
213
|
<S.IconStatusWrapper>
|
|
214
214
|
<FloatingMenu Button={ErrorCenterBtn} isInAppBar={true} position="left" offset={-20}>
|
|
@@ -67,8 +67,8 @@ function getSiteImages(props: IGetSiteImages): (dispatch: Dispatch, getState: ()
|
|
|
67
67
|
setData({
|
|
68
68
|
items: images,
|
|
69
69
|
page,
|
|
70
|
-
isImageSelected:
|
|
71
|
-
imageSelected:
|
|
70
|
+
isImageSelected: data.isImageSelected,
|
|
71
|
+
imageSelected: data.imageSelected,
|
|
72
72
|
isFinished: result.data.items.length < items,
|
|
73
73
|
})
|
|
74
74
|
);
|
|
@@ -86,7 +86,7 @@ function selectImage(item: IImage): (dispatch: Dispatch, getState: () => IRootSt
|
|
|
86
86
|
const {
|
|
87
87
|
gallery: { data },
|
|
88
88
|
} = getState();
|
|
89
|
-
if (data
|
|
89
|
+
if (data?.imageSelected?.id === item.id) {
|
|
90
90
|
dispatch(setData({ ...data, imageSelected: null, isImageSelected: false }));
|
|
91
91
|
} else {
|
|
92
92
|
dispatch(setData({ ...data, imageSelected: item, isImageSelected: true }));
|
|
@@ -147,10 +147,16 @@ function updateImage(
|
|
|
147
147
|
}
|
|
148
148
|
|
|
149
149
|
function deleteImage(imageID: number): (dispatch: Dispatch, getState: () => IRootState) => Promise<boolean> {
|
|
150
|
-
return async (dispatch) => {
|
|
150
|
+
return async (dispatch, getState) => {
|
|
151
151
|
try {
|
|
152
|
+
const {
|
|
153
|
+
gallery: { data },
|
|
154
|
+
} = getState();
|
|
152
155
|
const responseActions = {
|
|
153
|
-
handleSuccess: () =>
|
|
156
|
+
handleSuccess: () => {
|
|
157
|
+
dispatch(setData({ ...data, isImageSelected: false, imageSelected: null }));
|
|
158
|
+
return true;
|
|
159
|
+
},
|
|
154
160
|
handleError: (response: any) => {
|
|
155
161
|
appActions.handleError(response)(dispatch);
|
|
156
162
|
return false;
|
|
@@ -573,7 +573,7 @@ function duplicateModule(editorID: number, key?: string): (dispatch: Dispatch, g
|
|
|
573
573
|
function moveModule(
|
|
574
574
|
elementID: number,
|
|
575
575
|
content: any,
|
|
576
|
-
|
|
576
|
+
newIndex: number,
|
|
577
577
|
key: string
|
|
578
578
|
): (dispatch: Dispatch, getState: any) => void {
|
|
579
579
|
return async (dispatch, getState) => {
|
|
@@ -584,7 +584,7 @@ function moveModule(
|
|
|
584
584
|
|
|
585
585
|
const contentElements = [...selectedContent[key]];
|
|
586
586
|
const { element: selectedModule } = findByEditorID(editorContent, selectedContent.editorID);
|
|
587
|
-
selectedModule[key] = moveElement(elementID, contentElements,
|
|
587
|
+
selectedModule[key] = moveElement(elementID, contentElements, newIndex);
|
|
588
588
|
|
|
589
589
|
generateContent(editorContent, dispatch, getState);
|
|
590
590
|
} catch {
|
|
@@ -525,6 +525,9 @@ function updatePageStatus(
|
|
|
525
525
|
try {
|
|
526
526
|
dispatch(setIsSaving(true));
|
|
527
527
|
const {
|
|
528
|
+
app: {
|
|
529
|
+
globalSettings: { skipReviewOnPublish },
|
|
530
|
+
},
|
|
528
531
|
pageEditor: {
|
|
529
532
|
editorContent: { header, footer },
|
|
530
533
|
},
|
|
@@ -532,7 +535,7 @@ function updatePageStatus(
|
|
|
532
535
|
} = getState();
|
|
533
536
|
|
|
534
537
|
const pagesWithErrors: number[] = [];
|
|
535
|
-
if (status === pageStatus.UPLOAD_PENDING && updatedFromList) {
|
|
538
|
+
if (status === pageStatus.UPLOAD_PENDING && updatedFromList && !skipReviewOnPublish && ids.length > 1) {
|
|
536
539
|
const getPagesParams = {
|
|
537
540
|
siteID: currentSiteInfo?.id,
|
|
538
541
|
filterPages: ids,
|
|
@@ -829,7 +832,10 @@ function copyModule(editorID: number): (dispatch: Dispatch, getState: any) => bo
|
|
|
829
832
|
};
|
|
830
833
|
}
|
|
831
834
|
|
|
832
|
-
function pasteModule(
|
|
835
|
+
function pasteModule(
|
|
836
|
+
editorID: number,
|
|
837
|
+
key: string
|
|
838
|
+
): (dispatch: Dispatch, getState: any) => Promise<{ error?: INotification }> {
|
|
833
839
|
return async (dispatch, getState) => {
|
|
834
840
|
const {
|
|
835
841
|
pageEditor: { moduleCopy },
|
|
@@ -873,7 +879,7 @@ function pasteModule(editorID: number): (dispatch: Dispatch, getState: any) => P
|
|
|
873
879
|
}
|
|
874
880
|
}
|
|
875
881
|
|
|
876
|
-
const itemsArr = originalElement
|
|
882
|
+
const itemsArr = originalElement[key];
|
|
877
883
|
itemsArr.push(validatedModuleCopy);
|
|
878
884
|
|
|
879
885
|
const updatedPageContent = {
|
|
@@ -884,7 +890,7 @@ function pasteModule(editorID: number): (dispatch: Dispatch, getState: any) => P
|
|
|
884
890
|
|
|
885
891
|
const { sections: generatedSections } = getStateValues(getState);
|
|
886
892
|
const { element: generatedElement } = findByEditorID(generatedSections, editorID);
|
|
887
|
-
const pastedEditorID = generatedElement
|
|
893
|
+
const pastedEditorID = generatedElement[key][itemsArr.length - 1].editorID;
|
|
888
894
|
|
|
889
895
|
localStorage.setItem("selectedID", `${pastedEditorID}`);
|
|
890
896
|
return { error };
|
|
@@ -1059,7 +1065,7 @@ function resetPageEditor(): (dispatch: Dispatch) => Promise<void> {
|
|
|
1059
1065
|
function moveElement(
|
|
1060
1066
|
elementID: number,
|
|
1061
1067
|
content: any,
|
|
1062
|
-
|
|
1068
|
+
newIndex: number,
|
|
1063
1069
|
key: string
|
|
1064
1070
|
): (dispatch: Dispatch, getState: any) => void {
|
|
1065
1071
|
return async (dispatch, getState) => {
|
|
@@ -1069,7 +1075,7 @@ function moveElement(
|
|
|
1069
1075
|
elementID,
|
|
1070
1076
|
content,
|
|
1071
1077
|
selectedContent,
|
|
1072
|
-
|
|
1078
|
+
newIndex,
|
|
1073
1079
|
page: editorContent.editorContent,
|
|
1074
1080
|
key,
|
|
1075
1081
|
});
|
|
@@ -1106,6 +1112,8 @@ function validatePage(publish?: boolean): (dispatch: Dispatch, getState: any) =>
|
|
|
1106
1112
|
return async (dispatch, getState) => {
|
|
1107
1113
|
try {
|
|
1108
1114
|
const { editorContent } = getStateValues(getState);
|
|
1115
|
+
const { component } = editorContent;
|
|
1116
|
+
const isGlobalPage = component === "GlobalPage";
|
|
1109
1117
|
const content = deepClone(editorContent);
|
|
1110
1118
|
|
|
1111
1119
|
const {
|
|
@@ -1133,7 +1141,10 @@ function validatePage(publish?: boolean): (dispatch: Dispatch, getState: any) =>
|
|
|
1133
1141
|
const fieldErrors = findFieldsErrors(content);
|
|
1134
1142
|
|
|
1135
1143
|
errors = [...errors, ...fieldErrors];
|
|
1136
|
-
|
|
1144
|
+
let packagesActivationErrors;
|
|
1145
|
+
if (!isGlobalPage) {
|
|
1146
|
+
packagesActivationErrors = findPackagesActivationErrors(pageEditor, modules, templates);
|
|
1147
|
+
}
|
|
1137
1148
|
errors = packagesActivationErrors ? [...errors, packagesActivationErrors] : errors;
|
|
1138
1149
|
|
|
1139
1150
|
let warnings: IErrorItem[] = [];
|
package/src/forms/elements.tsx
CHANGED
|
@@ -150,11 +150,10 @@ const updateByEditorID = (content: any, editorID: number, contentKey: string, va
|
|
|
150
150
|
return content;
|
|
151
151
|
};
|
|
152
152
|
|
|
153
|
-
const moveElement = (elementID: number, arr: any[],
|
|
153
|
+
const moveElement = (elementID: number, arr: any[], newIndex: number, idKey = "editorID") => {
|
|
154
154
|
const arrCopy = [...arr];
|
|
155
155
|
if (arrCopy.length <= 1) return arrCopy;
|
|
156
156
|
const elementIndex = arrCopy.findIndex((el: any) => el[idKey] === elementID);
|
|
157
|
-
const newIndex = isPush ? elementIndex + 1 : elementIndex - 1;
|
|
158
157
|
const element = { ...arrCopy[elementIndex] };
|
|
159
158
|
arrCopy.splice(elementIndex, 1);
|
|
160
159
|
arrCopy.splice(newIndex, 0, element);
|
|
@@ -163,12 +162,12 @@ const moveElement = (elementID: number, arr: any[], isPush: boolean, idKey = "ed
|
|
|
163
162
|
};
|
|
164
163
|
|
|
165
164
|
const moveModule = (params: IMoveElementParams) => {
|
|
166
|
-
const { elementID, content, selectedContent,
|
|
165
|
+
const { elementID, content, selectedContent, newIndex, page, key } = params;
|
|
167
166
|
const isPage = ["Page", "GlobalPage"].includes(selectedContent.component);
|
|
168
167
|
let newContent;
|
|
169
168
|
if (isPage) {
|
|
170
169
|
const { modules } = content;
|
|
171
|
-
const newModules = moveElement(elementID, modules,
|
|
170
|
+
const newModules = moveElement(elementID, modules, newIndex);
|
|
172
171
|
const { template } = selectedContent;
|
|
173
172
|
const selectedSection = Object.keys(template).find(
|
|
174
173
|
(key: string) => template[key] && template[key].editorID === content.editorID
|
|
@@ -189,7 +188,7 @@ const moveModule = (params: IMoveElementParams) => {
|
|
|
189
188
|
const contentElements = content[key];
|
|
190
189
|
const { template } = page;
|
|
191
190
|
const { element: selectedModule } = findByEditorID(page, selectedContent.editorID);
|
|
192
|
-
selectedModule[key] = moveElement(elementID, contentElements,
|
|
191
|
+
selectedModule[key] = moveElement(elementID, contentElements, newIndex);
|
|
193
192
|
|
|
194
193
|
newContent = {
|
|
195
194
|
...page,
|
|
@@ -216,7 +215,7 @@ function replaceElements(elements: any, elemType: string): any {
|
|
|
216
215
|
interface IMoveElementParams {
|
|
217
216
|
elementID: number;
|
|
218
217
|
content: any;
|
|
219
|
-
|
|
218
|
+
newIndex: number;
|
|
220
219
|
selectedContent: any;
|
|
221
220
|
page: any;
|
|
222
221
|
key: string;
|
package/src/helpers/arrays.tsx
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
const isEmptyArray = (arr: any[]) => arr && arr.length === 0;
|
|
2
2
|
|
|
3
|
-
const moveArrayElement = (element: unknown, arr: unknown[],
|
|
3
|
+
const moveArrayElement = (element: unknown, arr: unknown[], newIndex: number): Array<unknown> => {
|
|
4
4
|
const arrCopy = [...arr];
|
|
5
5
|
if (arrCopy.length <= 1) return arrCopy;
|
|
6
6
|
const elementIndex = arrCopy.findIndex((el: unknown) => el === element);
|
|
7
|
-
const newIndex = isPush ? elementIndex + 1 : elementIndex - 1;
|
|
8
7
|
const el = arrCopy[elementIndex];
|
|
9
8
|
arrCopy.splice(elementIndex, 1);
|
|
10
9
|
arrCopy.splice(newIndex, 0, el);
|
|
@@ -37,6 +37,7 @@ const PageItem = (props: IPageItemProps): JSX.Element => {
|
|
|
37
37
|
addCategoryColors,
|
|
38
38
|
dataPacks,
|
|
39
39
|
sites,
|
|
40
|
+
skipReview,
|
|
40
41
|
} = props;
|
|
41
42
|
const { isSelected, siteLanguages, page, lang, isDuplicable } = item;
|
|
42
43
|
const {
|
|
@@ -49,6 +50,8 @@ const PageItem = (props: IPageItemProps): JSX.Element => {
|
|
|
49
50
|
setCurrentPageID,
|
|
50
51
|
languageActions,
|
|
51
52
|
duplicatePage,
|
|
53
|
+
validatePage,
|
|
54
|
+
getPage,
|
|
52
55
|
removePageFromSite,
|
|
53
56
|
deleteBulk,
|
|
54
57
|
getDataPack,
|
|
@@ -181,8 +184,13 @@ const PageItem = (props: IPageItemProps): JSX.Element => {
|
|
|
181
184
|
};
|
|
182
185
|
|
|
183
186
|
const publishPage = async () => {
|
|
184
|
-
await
|
|
185
|
-
await
|
|
187
|
+
await getPage(page.id);
|
|
188
|
+
const isValidated = skipReview ? true : await validatePage(true);
|
|
189
|
+
|
|
190
|
+
if (isValidated) {
|
|
191
|
+
await updatePageStatus([page.id], pageStatus.UPLOAD_PENDING, true);
|
|
192
|
+
await getSiteContent();
|
|
193
|
+
}
|
|
186
194
|
};
|
|
187
195
|
|
|
188
196
|
const unpublishPage = async () => {
|
|
@@ -630,6 +638,8 @@ interface IPageItemProps {
|
|
|
630
638
|
setTemplateInstanceError(error: any): void;
|
|
631
639
|
getDataPack: (id: string) => Promise<void>;
|
|
632
640
|
toggleCopiedToast(): void;
|
|
641
|
+
getPage(pageID?: number, global?: boolean): Promise<void>;
|
|
642
|
+
validatePage(publish?: boolean, browserRef?: any, currentPage?: IPage): Promise<boolean>;
|
|
633
643
|
};
|
|
634
644
|
activatedTemplates: any[];
|
|
635
645
|
toggleToast(): void;
|
|
@@ -640,6 +650,7 @@ interface IPageItemProps {
|
|
|
640
650
|
addCategoryColors(cats: string[]): void;
|
|
641
651
|
dataPacks: IDataPack[];
|
|
642
652
|
sites: ISite[];
|
|
653
|
+
skipReview?: boolean;
|
|
643
654
|
}
|
|
644
655
|
|
|
645
656
|
export default memo(PageItem);
|