@griddo/ax 1.72.11 → 1.73.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.
- package/package.json +2 -2
- package/scripts/griddo-sync-schemas.js +1 -1
- package/src/__tests__/components/ErrorCenter/ErrorCenter.test.tsx +186 -0
- package/src/__tests__/components/Flag/Flag.test.tsx +60 -0
- package/src/__tests__/components/FloatingMenu/FloatingMenu.test.tsx +712 -0
- package/src/__tests__/components/FloatingPanel/FloatingPanel.test.tsx +149 -0
- package/src/__tests__/components/GuardModal/GuardModal.test.tsx +31 -0
- package/src/__tests__/components/Icon/Icon.test.tsx +76 -0
- package/src/__tests__/components/IconAction/IconAction.test.tsx +91 -0
- package/src/__tests__/components/Notification/Notification.test.tsx +206 -0
- package/src/__tests__/components/Notification/SubNotification/Subnotification.test.tsx +46 -0
- package/src/__tests__/components/ReorderArrows/ReorderArrows.test.tsx +96 -0
- package/src/__tests__/components/ResizePanel/ResizePanel.test.tsx +200 -0
- package/src/__tests__/components/SearchField/SearchField.test.tsx +375 -0
- package/src/api/analytics.tsx +4 -4
- package/src/components/ActionMenu/style.tsx +1 -0
- package/src/components/ConfigPanel/Form/ConnectedField/NavConnectedField/index.tsx +1 -1
- package/src/components/ConfigPanel/Form/ConnectedField/PageConnectedField/Field/index.tsx +2 -1
- package/src/components/ConfigPanel/Form/index.tsx +22 -1
- package/src/components/ConfigPanel/Form/style.tsx +19 -0
- package/src/components/ConfigPanel/GlobalPageForm/index.tsx +22 -3
- package/src/components/ConfigPanel/GlobalPageForm/style.tsx +18 -2
- package/src/components/ConfigPanel/NavigationForm/Field/index.tsx +25 -13
- package/src/components/ConfigPanel/index.tsx +8 -0
- package/src/components/ErrorCenter/index.tsx +8 -4
- package/src/components/Fields/DateField/DatePickerInput/index.tsx +30 -8
- package/src/components/Fields/DateField/index.tsx +8 -2
- package/src/components/Fields/Select/index.tsx +1 -0
- package/src/components/Flag/index.tsx +13 -11
- package/src/components/FloatingMenu/index.tsx +23 -7
- package/src/components/FloatingMenu/style.tsx +1 -0
- package/src/components/FloatingPanel/index.tsx +9 -3
- package/src/components/GuardModal/index.tsx +3 -3
- package/src/components/Icon/index.tsx +2 -1
- package/src/components/IconAction/index.tsx +3 -3
- package/src/components/MainWrapper/AppBar/index.tsx +3 -1
- package/src/components/MainWrapper/AppBar/style.tsx +3 -0
- package/src/components/MenuItem/index.tsx +1 -1
- package/src/components/Modal/index.tsx +1 -1
- package/src/components/Notification/SubNotification/index.tsx +33 -0
- package/src/components/Notification/SubNotification/style.tsx +49 -0
- package/src/components/Notification/index.tsx +31 -17
- package/src/components/Notification/style.tsx +33 -8
- package/src/components/ReorderArrows/index.tsx +3 -3
- package/src/components/ResizePanel/ResizeHandle/index.tsx +29 -38
- package/src/components/ResizePanel/index.tsx +13 -15
- package/src/components/SearchField/index.tsx +9 -8
- package/src/containers/Analytics/actions.tsx +14 -4
- package/src/containers/App/actions.tsx +18 -6
- package/src/containers/App/reducer.tsx +1 -0
- package/src/containers/Domains/actions.tsx +8 -1
- package/src/containers/Navigation/Defaults/actions.tsx +16 -2
- package/src/containers/PageEditor/actions.tsx +82 -6
- package/src/containers/PageEditor/utils.tsx +28 -10
- package/src/containers/Redirects/actions.tsx +16 -2
- package/src/containers/Sites/actions.tsx +80 -3
- package/src/containers/StructuredData/actions.tsx +24 -3
- package/src/containers/Users/actions.tsx +8 -1
- package/src/forms/errors.tsx +1 -0
- package/src/forms/fields.tsx +6 -3
- package/src/forms/validators.tsx +14 -4
- package/src/guards/error/index.tsx +17 -21
- package/src/helpers/dates.tsx +2 -0
- package/src/helpers/index.tsx +2 -0
- package/src/hooks/modals.tsx +4 -4
- package/src/modules/Content/OptionTable/index.tsx +20 -7
- package/src/modules/Content/index.tsx +4 -7
- package/src/modules/Content/utils.tsx +18 -13
- package/src/modules/FramePreview/index.tsx +39 -12
- package/src/modules/GlobalEditor/index.tsx +17 -20
- package/src/modules/Navigation/Menus/List/Table/index.tsx +2 -2
- package/src/modules/PageEditor/Editor/index.tsx +13 -0
- package/src/modules/PageEditor/index.tsx +17 -20
- package/src/modules/Redirects/RedirectItem/index.tsx +17 -3
- package/src/modules/Settings/ContentTypes/DataPacks/Item/index.tsx +1 -1
- package/src/modules/StructuredData/Form/index.tsx +10 -13
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import React, { useReducer, useEffect, useLayoutEffect } from "react";
|
|
2
2
|
import { connect } from "react-redux";
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { IRootState, IStructuredData } from "@ax/types";
|
|
5
|
+
import { getThumbnailProps } from "@ax/helpers";
|
|
6
6
|
import { MenuItem, RadioGroup } from "@ax/components";
|
|
7
|
+
import { structuredDataActions } from "@ax/containers/StructuredData";
|
|
7
8
|
import { SecondaryActionButton, MainActionButton } from "./../atoms";
|
|
8
9
|
|
|
9
10
|
import { reducer, IOptionTableStore, setColumnValues, setShowThumbnail, setSelectedType, setOption } from "./store";
|
|
@@ -21,7 +22,9 @@ const OptionTable = (props: IOptionTableProps): JSX.Element => {
|
|
|
21
22
|
theme,
|
|
22
23
|
mainAction,
|
|
23
24
|
secondaryAction,
|
|
25
|
+
structuredData,
|
|
24
26
|
} = props;
|
|
27
|
+
|
|
25
28
|
const filterOptions = (value: string, objKey: string) => values.filter((item: any) => item[objKey] === value);
|
|
26
29
|
const filterOptionsByDataPack = (value: string) => {
|
|
27
30
|
return values.filter((item: any) => {
|
|
@@ -89,13 +92,18 @@ const OptionTable = (props: IOptionTableProps): JSX.Element => {
|
|
|
89
92
|
const { value } = item;
|
|
90
93
|
setType(value);
|
|
91
94
|
filteredOptionsByDataPack = filterOptionsByDataPack(value);
|
|
95
|
+
|
|
92
96
|
filteredOptionsByDataPack.forEach((option: any) => {
|
|
93
|
-
const {
|
|
94
|
-
|
|
95
|
-
|
|
97
|
+
const { name } = option;
|
|
98
|
+
|
|
99
|
+
const currentGlobalStructuredData = structuredData.global.find((data: any) =>
|
|
100
|
+
data.schema.templates?.includes(name)
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
if (currentGlobalStructuredData) {
|
|
96
104
|
filteredOptionsByDataPack = filteredOptionsByDataPack.map((option: any) => {
|
|
97
105
|
if (option.mode !== "detail") return option;
|
|
98
|
-
const title = `Get ${
|
|
106
|
+
const title = `Get ${currentGlobalStructuredData.title} from Global`;
|
|
99
107
|
return { ...option, title };
|
|
100
108
|
});
|
|
101
109
|
const globalOptionIdx = filteredOptionsByDataPack.findIndex((option: any) => option.mode === "detail");
|
|
@@ -165,10 +173,15 @@ interface IOptionTableProps {
|
|
|
165
173
|
theme: string;
|
|
166
174
|
mainAction: IAction;
|
|
167
175
|
secondaryAction: IAction;
|
|
176
|
+
structuredData: { global: IStructuredData[]; site: IStructuredData[] };
|
|
168
177
|
}
|
|
169
178
|
|
|
179
|
+
const mapStateToProps = (state: IRootState) => ({
|
|
180
|
+
structuredData: state.structuredData.structuredData,
|
|
181
|
+
});
|
|
182
|
+
|
|
170
183
|
const mapDispatchToProps = {
|
|
171
184
|
setIsStructuredData: structuredDataActions.setIsActive,
|
|
172
185
|
};
|
|
173
186
|
|
|
174
|
-
export default connect(
|
|
187
|
+
export default connect(mapStateToProps, mapDispatchToProps)(OptionTable);
|
|
@@ -99,6 +99,7 @@ const Content = (props: IProps): JSX.Element => {
|
|
|
99
99
|
skipReviewOnPublish,
|
|
100
100
|
setContentFilters,
|
|
101
101
|
contentFilters,
|
|
102
|
+
deleteAndRemoveFromSiteBulk,
|
|
102
103
|
} = props;
|
|
103
104
|
|
|
104
105
|
const itemsPerPage = 50;
|
|
@@ -349,13 +350,7 @@ const Content = (props: IProps): JSX.Element => {
|
|
|
349
350
|
.filter((page: IPage) => pageIds.includes(page.id) && page.origin !== "GLOBAL")
|
|
350
351
|
.map((page: IPage) => page.id);
|
|
351
352
|
|
|
352
|
-
|
|
353
|
-
if (filteredPageIds.length > 0) {
|
|
354
|
-
deleted = await deleteBulk(filteredPageIds);
|
|
355
|
-
}
|
|
356
|
-
if (globalPageIds.length > 0) {
|
|
357
|
-
deleted = await removePageFromSite(globalPageIds, false);
|
|
358
|
-
}
|
|
353
|
+
const deleted = await deleteAndRemoveFromSiteBulk(filteredPageIds, globalPageIds);
|
|
359
354
|
|
|
360
355
|
if (deleted) {
|
|
361
356
|
setDeletedItem(pageIds);
|
|
@@ -826,6 +821,7 @@ interface IDispatchProps {
|
|
|
826
821
|
resetCurrentSiteErrorPages: () => Promise<void>;
|
|
827
822
|
getSitesByLang(language: number): Promise<void>;
|
|
828
823
|
setContentFilters(contentFilters: Record<string, string> | null): void;
|
|
824
|
+
deleteAndRemoveFromSiteBulk(pageIds: number[], globalPageIds: number[]): Promise<boolean>;
|
|
829
825
|
}
|
|
830
826
|
|
|
831
827
|
const mapDispatchToProps = {
|
|
@@ -859,6 +855,7 @@ const mapDispatchToProps = {
|
|
|
859
855
|
resetCurrentSiteErrorPages: sitesActions.resetCurrentSiteErrorPages,
|
|
860
856
|
getSitesByLang: sitesActions.getSitesByLang,
|
|
861
857
|
setContentFilters: sitesActions.setContentFilters,
|
|
858
|
+
deleteAndRemoveFromSiteBulk: sitesActions.deleteAndRemoveFromSiteBulk,
|
|
862
859
|
};
|
|
863
860
|
|
|
864
861
|
interface IPagesProps {
|
|
@@ -15,14 +15,17 @@ const getTemplatesFilters = (activatedDataPacks: any) => {
|
|
|
15
15
|
if (isActivated) {
|
|
16
16
|
!dataPacks
|
|
17
17
|
? filters.push({ ...type })
|
|
18
|
-
: dataPacks.map((
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
: dataPacks.map((dataPack: string) => {
|
|
19
|
+
const currentDataPack = activatedDataPacks.find(
|
|
20
|
+
(activatedDataPack: any) => dataPack === activatedDataPack.id
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
return filters.push({
|
|
24
|
+
label: currentDataPack.title,
|
|
25
|
+
value: currentDataPack.id,
|
|
23
26
|
mode: type.mode,
|
|
24
|
-
})
|
|
25
|
-
);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
26
29
|
}
|
|
27
30
|
});
|
|
28
31
|
|
|
@@ -75,13 +78,15 @@ const getOptionFilters = (options: any, activatedDataPacks: any) => {
|
|
|
75
78
|
const templateFilters = getTemplatesFilters(activatedDataPacks);
|
|
76
79
|
|
|
77
80
|
const mappedOptions = pureOptions.flatMap((option: any) =>
|
|
78
|
-
option.dataPacks.map((dataPack: string) =>
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
81
|
+
option.dataPacks.map((dataPack: string) => {
|
|
82
|
+
const currentDataPack = activatedDataPacks.find((activatedDataPack: any) => dataPack === activatedDataPack.id);
|
|
83
|
+
return {
|
|
84
|
+
label: currentDataPack.title,
|
|
85
|
+
value: currentDataPack.id,
|
|
86
|
+
isData: true,
|
|
87
|
+
};
|
|
88
|
+
})
|
|
83
89
|
);
|
|
84
|
-
|
|
85
90
|
const filters = [...templateFilters, ...mappedOptions];
|
|
86
91
|
const uniqueFilters = [...new Map(filters.map((item: any) => [item.value, item])).values()];
|
|
87
92
|
const sortedUniqueFilters = uniqueFilters.sort((a, b) => a.label.localeCompare(b.label));
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useCallback, useEffect
|
|
1
|
+
import React, { useCallback, useEffect } from "react";
|
|
2
2
|
import { connect } from "react-redux";
|
|
3
3
|
|
|
4
4
|
import { getDefaultTheme } from "@ax/helpers";
|
|
@@ -11,31 +11,56 @@ import { useURLSearchParam } from "@ax/hooks";
|
|
|
11
11
|
import * as S from "./style";
|
|
12
12
|
|
|
13
13
|
const FramePreview = (props: IProps) => {
|
|
14
|
-
const {
|
|
15
|
-
|
|
14
|
+
const {
|
|
15
|
+
content,
|
|
16
|
+
socials,
|
|
17
|
+
cloudinaryName,
|
|
18
|
+
isLoading,
|
|
19
|
+
currentSiteInfo,
|
|
20
|
+
siteLangs,
|
|
21
|
+
globalLangs,
|
|
22
|
+
setSelectedContent,
|
|
23
|
+
setEditorContent,
|
|
24
|
+
} = props;
|
|
16
25
|
|
|
17
|
-
const [state, setState] = useState(content);
|
|
18
26
|
const isPreview = useURLSearchParam("preview");
|
|
19
27
|
const isDisabled = useURLSearchParam("disabled");
|
|
20
28
|
|
|
21
|
-
const onMessageReceivedFromOutside = useCallback(
|
|
29
|
+
const onMessageReceivedFromOutside = useCallback(
|
|
30
|
+
(ev: MessageEvent<{ type: string; message: Record<string, unknown> }>) => {
|
|
31
|
+
if (typeof ev.data !== "object") return;
|
|
32
|
+
if (!ev.data.type) return;
|
|
33
|
+
if (ev.data.type !== "content-update") return;
|
|
34
|
+
if (!ev.data.message) return;
|
|
35
|
+
setEditorContent(ev.data.message);
|
|
36
|
+
},
|
|
37
|
+
[]
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
window.addEventListener("message", onMessageReceivedFromOutside);
|
|
42
|
+
return () => window.removeEventListener("message", onMessageReceivedFromOutside);
|
|
43
|
+
}, [onMessageReceivedFromOutside]);
|
|
44
|
+
|
|
45
|
+
const onMessageReceivedFromPanel = useCallback((ev: MessageEvent<{ type: string; message: string }>) => {
|
|
22
46
|
if (typeof ev.data !== "object") return;
|
|
23
47
|
if (!ev.data.type) return;
|
|
24
|
-
if (ev.data.type !== "content
|
|
48
|
+
if (ev.data.type !== "selected-content") return;
|
|
25
49
|
if (!ev.data.message) return;
|
|
26
|
-
|
|
50
|
+
setSelectedContent(parseInt(ev.data.message));
|
|
51
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
27
52
|
}, []);
|
|
28
53
|
|
|
29
54
|
useEffect(() => {
|
|
30
|
-
window.addEventListener("message",
|
|
31
|
-
return () => window.removeEventListener("message",
|
|
32
|
-
}, [
|
|
55
|
+
window.addEventListener("message", onMessageReceivedFromPanel);
|
|
56
|
+
return () => window.removeEventListener("message", onMessageReceivedFromPanel);
|
|
57
|
+
}, [onMessageReceivedFromPanel]);
|
|
33
58
|
|
|
34
59
|
const {
|
|
35
60
|
editorContent: { canonicalSite, language, pageLanguages },
|
|
36
61
|
header,
|
|
37
62
|
footer,
|
|
38
|
-
} =
|
|
63
|
+
} = content;
|
|
39
64
|
|
|
40
65
|
document.body.classList.add("preview");
|
|
41
66
|
|
|
@@ -81,7 +106,7 @@ const FramePreview = (props: IProps) => {
|
|
|
81
106
|
selectEditorID={selectEditorID}
|
|
82
107
|
siteID={siteID}
|
|
83
108
|
isPage={true}
|
|
84
|
-
content={
|
|
109
|
+
content={content.editorContent}
|
|
85
110
|
header={currentSiteInfo && header}
|
|
86
111
|
footer={currentSiteInfo && footer}
|
|
87
112
|
languageID={language}
|
|
@@ -100,6 +125,7 @@ interface IProps {
|
|
|
100
125
|
globalLangs: ILanguage[];
|
|
101
126
|
isLoading: boolean;
|
|
102
127
|
setSelectedContent(editorID: number): void;
|
|
128
|
+
setEditorContent(editorContent: Record<string, unknown>): void;
|
|
103
129
|
}
|
|
104
130
|
|
|
105
131
|
const mapStateToProps = (state: IRootState) => ({
|
|
@@ -114,6 +140,7 @@ const mapStateToProps = (state: IRootState) => ({
|
|
|
114
140
|
|
|
115
141
|
const mapDispatchToProps = {
|
|
116
142
|
setSelectedContent: pageEditorActions.setSelectedContent,
|
|
143
|
+
setEditorContent: pageEditorActions.setEditorContent,
|
|
117
144
|
};
|
|
118
145
|
|
|
119
146
|
export default connect(mapStateToProps, mapDispatchToProps)(FramePreview);
|
|
@@ -33,7 +33,6 @@ const GlobalEditor = (props: IProps) => {
|
|
|
33
33
|
errors,
|
|
34
34
|
setSelectedContent,
|
|
35
35
|
setTab,
|
|
36
|
-
validated,
|
|
37
36
|
pageEditor: { editorContent },
|
|
38
37
|
sitePageID,
|
|
39
38
|
setHistoryPush,
|
|
@@ -60,6 +59,10 @@ const GlobalEditor = (props: IProps) => {
|
|
|
60
59
|
const isLivePageChanged = editorContent.editorContent && editorContent.editorContent.liveChanged;
|
|
61
60
|
const structuredData = editorContent.editorContent ? editorContent.editorContent.structuredData : "";
|
|
62
61
|
|
|
62
|
+
const errorNotificationText =
|
|
63
|
+
"There are some errors on the page so you can not publish yet. Please review them in the error panel.";
|
|
64
|
+
const validatedNotificationText = "Everything seems ok, you can publish the page.";
|
|
65
|
+
|
|
63
66
|
const theme = getDefaultTheme();
|
|
64
67
|
|
|
65
68
|
useEffect(() => {
|
|
@@ -141,6 +144,8 @@ const GlobalEditor = (props: IProps) => {
|
|
|
141
144
|
resetDirty();
|
|
142
145
|
}
|
|
143
146
|
});
|
|
147
|
+
} else {
|
|
148
|
+
setNotification({ text: errorNotificationText, type: "error" });
|
|
144
149
|
}
|
|
145
150
|
};
|
|
146
151
|
|
|
@@ -159,6 +164,8 @@ const GlobalEditor = (props: IProps) => {
|
|
|
159
164
|
resetDirty();
|
|
160
165
|
}
|
|
161
166
|
});
|
|
167
|
+
} else {
|
|
168
|
+
setNotification({ text: errorNotificationText, type: "error" });
|
|
162
169
|
}
|
|
163
170
|
};
|
|
164
171
|
|
|
@@ -174,9 +181,14 @@ const GlobalEditor = (props: IProps) => {
|
|
|
174
181
|
updatePageStatus([pageID], pageStatus.OFFLINE);
|
|
175
182
|
};
|
|
176
183
|
|
|
177
|
-
const reviewPage = () => {
|
|
184
|
+
const reviewPage = async () => {
|
|
178
185
|
const { validatePage } = props;
|
|
179
|
-
validatePage(false);
|
|
186
|
+
const validated = await validatePage(false);
|
|
187
|
+
if (validated) {
|
|
188
|
+
setNotification({ text: validatedNotificationText, type: "success" });
|
|
189
|
+
} else {
|
|
190
|
+
setNotification({ text: errorNotificationText, type: "error" });
|
|
191
|
+
}
|
|
180
192
|
};
|
|
181
193
|
|
|
182
194
|
const handlePublishDraft = async () => {
|
|
@@ -187,6 +199,8 @@ const GlobalEditor = (props: IProps) => {
|
|
|
187
199
|
if (validated) {
|
|
188
200
|
const isSaved = await savePage(false, null, true);
|
|
189
201
|
if (isSaved) resetDirty();
|
|
202
|
+
} else {
|
|
203
|
+
setNotification({ text: errorNotificationText, type: "error" });
|
|
190
204
|
}
|
|
191
205
|
};
|
|
192
206
|
|
|
@@ -377,11 +391,6 @@ const GlobalEditor = (props: IProps) => {
|
|
|
377
391
|
}
|
|
378
392
|
};
|
|
379
393
|
|
|
380
|
-
const errorNotificationText =
|
|
381
|
-
"There are some errors on the page so you can not publish yet. Please review them in the error panel.";
|
|
382
|
-
|
|
383
|
-
const validatedNotificationText = "Everything seems ok, you can publish the page.";
|
|
384
|
-
|
|
385
394
|
const globalNotificationText = "You’ re working on the Global Page. Make sure you want to make changes to this page.";
|
|
386
395
|
|
|
387
396
|
const modifiedNotificationText =
|
|
@@ -433,16 +442,6 @@ const GlobalEditor = (props: IProps) => {
|
|
|
433
442
|
pageStatusActions={pageStatusActions}
|
|
434
443
|
tabs={tabsPreview}
|
|
435
444
|
>
|
|
436
|
-
{errors.length > 0 && (
|
|
437
|
-
<S.NotificationWrapper>
|
|
438
|
-
<Notification type="error" text={errorNotificationText} />
|
|
439
|
-
</S.NotificationWrapper>
|
|
440
|
-
)}
|
|
441
|
-
{validated && (
|
|
442
|
-
<S.NotificationWrapper>
|
|
443
|
-
<Notification type="success" text={validatedNotificationText} />
|
|
444
|
-
</S.NotificationWrapper>
|
|
445
|
-
)}
|
|
446
445
|
{isLivePageChanged && (
|
|
447
446
|
<S.NotificationWrapper>
|
|
448
447
|
<Notification type="warning" text={modifiedNotificationText} />
|
|
@@ -534,7 +533,6 @@ const mapStateToProps = (state: IRootState): IPageEditorStateProps => ({
|
|
|
534
533
|
pageLanguages: state.pageEditor.currentPageLanguages,
|
|
535
534
|
pageEditor: state.pageEditor,
|
|
536
535
|
errors: state.pageEditor.errors,
|
|
537
|
-
validated: state.pageEditor.validated,
|
|
538
536
|
sitePageID: state.pageEditor.sitePageID,
|
|
539
537
|
savedSiteInfo: state.sites.savedSiteInfo,
|
|
540
538
|
userEditing: state.pageEditor.userEditing,
|
|
@@ -555,7 +553,6 @@ interface IPageEditorStateProps {
|
|
|
555
553
|
pageLanguages: any[];
|
|
556
554
|
pageEditor: any;
|
|
557
555
|
errors: IErrorItem[];
|
|
558
|
-
validated: boolean;
|
|
559
556
|
sitePageID: number | null;
|
|
560
557
|
savedSiteInfo: any;
|
|
561
558
|
userEditing: IUserEditing | null;
|
|
@@ -33,12 +33,12 @@ const ItemList = (props: IItemList): JSX.Element => {
|
|
|
33
33
|
}, [menu]);
|
|
34
34
|
|
|
35
35
|
const getIcon = (item: TreeItem, onExpand: (itemId: ItemId) => void, onCollapse: (itemId: ItemId) => void) => {
|
|
36
|
-
const handleCollapse = (e: MouseEvent) => {
|
|
36
|
+
const handleCollapse = (e: React.MouseEvent<HTMLButtonElement>) => {
|
|
37
37
|
e.stopPropagation();
|
|
38
38
|
onCollapse(item.id);
|
|
39
39
|
};
|
|
40
40
|
|
|
41
|
-
const handleExpand = (e: MouseEvent) => {
|
|
41
|
+
const handleExpand = (e: React.MouseEvent<HTMLButtonElement>) => {
|
|
42
42
|
e.stopPropagation();
|
|
43
43
|
onExpand(item.id);
|
|
44
44
|
};
|
|
@@ -40,8 +40,14 @@ const Editor = (props: IProps) => {
|
|
|
40
40
|
copyModule,
|
|
41
41
|
pasteModule,
|
|
42
42
|
setNotification,
|
|
43
|
+
restorePageNavigation,
|
|
44
|
+
content,
|
|
43
45
|
} = props;
|
|
44
46
|
|
|
47
|
+
const {
|
|
48
|
+
editorContent: { header, footer },
|
|
49
|
+
} = content;
|
|
50
|
+
|
|
45
51
|
const actions = {
|
|
46
52
|
deleteModuleAction: deleteModule,
|
|
47
53
|
addComponentAction: addComponent,
|
|
@@ -55,6 +61,7 @@ const Editor = (props: IProps) => {
|
|
|
55
61
|
copyModuleAction: copyModule,
|
|
56
62
|
pasteModuleAction: pasteModule,
|
|
57
63
|
setNotificationAction: setNotification,
|
|
64
|
+
restorePageNavigationAction: restorePageNavigation,
|
|
58
65
|
};
|
|
59
66
|
|
|
60
67
|
return (
|
|
@@ -82,6 +89,8 @@ const Editor = (props: IProps) => {
|
|
|
82
89
|
userEditing={userEditing}
|
|
83
90
|
theme={site.theme}
|
|
84
91
|
lastElementAddedId={lastElementAddedId}
|
|
92
|
+
header={header}
|
|
93
|
+
footer={footer}
|
|
85
94
|
/>
|
|
86
95
|
}
|
|
87
96
|
/>
|
|
@@ -99,6 +108,7 @@ interface IEditorStateProps {
|
|
|
99
108
|
userEditing: IUserEditing | null;
|
|
100
109
|
site: ISite;
|
|
101
110
|
lastElementAddedId: null | number;
|
|
111
|
+
content: any;
|
|
102
112
|
}
|
|
103
113
|
|
|
104
114
|
interface IPageBrowserDispatchProps {
|
|
@@ -117,6 +127,7 @@ interface IPageBrowserDispatchProps {
|
|
|
117
127
|
copyModule(editorID: number): boolean;
|
|
118
128
|
pasteModule(editorID: number, key: string): Promise<{ error?: INotification }>;
|
|
119
129
|
setNotification: (notification: INotification) => void;
|
|
130
|
+
restorePageNavigation: (key: string) => void;
|
|
120
131
|
isTemplateActivated: boolean;
|
|
121
132
|
isGlobal: boolean;
|
|
122
133
|
isEditable: boolean;
|
|
@@ -137,6 +148,7 @@ const mapStateToProps = (state: IRootState): IEditorStateProps => ({
|
|
|
137
148
|
userEditing: state.pageEditor.userEditing,
|
|
138
149
|
site: state.sites.currentSiteInfo,
|
|
139
150
|
lastElementAddedId: state.pageEditor.lastElementAddedId,
|
|
151
|
+
content: state.pageEditor.editorContent,
|
|
140
152
|
});
|
|
141
153
|
|
|
142
154
|
const mapDispatchToProps = {
|
|
@@ -154,6 +166,7 @@ const mapDispatchToProps = {
|
|
|
154
166
|
saveCurrentSiteInfo: sitesActions.saveCurrentSiteInfo,
|
|
155
167
|
copyModule: pageEditorActions.copyModule,
|
|
156
168
|
pasteModule: pageEditorActions.pasteModule,
|
|
169
|
+
restorePageNavigation: pageEditorActions.restorePageNavigation,
|
|
157
170
|
};
|
|
158
171
|
|
|
159
172
|
export default connect(mapStateToProps, mapDispatchToProps)(Editor);
|
|
@@ -40,7 +40,6 @@ const PageEditor = (props: IProps) => {
|
|
|
40
40
|
errors,
|
|
41
41
|
setSelectedContent,
|
|
42
42
|
setTab,
|
|
43
|
-
validated,
|
|
44
43
|
pageEditor: { editorContent, schema },
|
|
45
44
|
userEditing,
|
|
46
45
|
isNewTranslation,
|
|
@@ -67,6 +66,10 @@ const PageEditor = (props: IProps) => {
|
|
|
67
66
|
const isTranslated = pageLanguages.length > 1;
|
|
68
67
|
const structuredData = editorContent.editorContent ? editorContent.editorContent.structuredData : "";
|
|
69
68
|
|
|
69
|
+
const errorNotificationText =
|
|
70
|
+
"There are some errors on the page so you can not publish yet. Please review them in the error panel.";
|
|
71
|
+
const validatedNotificationText = "Everything seems ok, you can publish the page.";
|
|
72
|
+
|
|
70
73
|
useEffect(() => {
|
|
71
74
|
const { pageID, getPage, setTab, sendPagePing } = props;
|
|
72
75
|
const defaultTab = "content";
|
|
@@ -145,6 +148,8 @@ const PageEditor = (props: IProps) => {
|
|
|
145
148
|
resetDirty();
|
|
146
149
|
}
|
|
147
150
|
});
|
|
151
|
+
} else {
|
|
152
|
+
setNotification({ text: errorNotificationText, type: "error" });
|
|
148
153
|
}
|
|
149
154
|
};
|
|
150
155
|
|
|
@@ -163,6 +168,8 @@ const PageEditor = (props: IProps) => {
|
|
|
163
168
|
resetDirty();
|
|
164
169
|
}
|
|
165
170
|
});
|
|
171
|
+
} else {
|
|
172
|
+
setNotification({ text: errorNotificationText, type: "error" });
|
|
166
173
|
}
|
|
167
174
|
};
|
|
168
175
|
|
|
@@ -178,9 +185,14 @@ const PageEditor = (props: IProps) => {
|
|
|
178
185
|
updatePageStatus([pageID], pageStatus.OFFLINE);
|
|
179
186
|
};
|
|
180
187
|
|
|
181
|
-
const reviewPage = () => {
|
|
188
|
+
const reviewPage = async () => {
|
|
182
189
|
const { validatePage } = props;
|
|
183
|
-
validatePage(false);
|
|
190
|
+
const validated = await validatePage(false);
|
|
191
|
+
if (validated) {
|
|
192
|
+
setNotification({ text: validatedNotificationText, type: "success" });
|
|
193
|
+
} else {
|
|
194
|
+
setNotification({ text: errorNotificationText, type: "error" });
|
|
195
|
+
}
|
|
184
196
|
};
|
|
185
197
|
|
|
186
198
|
const handlePublishDraft = async () => {
|
|
@@ -191,6 +203,8 @@ const PageEditor = (props: IProps) => {
|
|
|
191
203
|
if (validated) {
|
|
192
204
|
const isSaved = await savePage(false, null, true);
|
|
193
205
|
if (isSaved) resetDirty();
|
|
206
|
+
} else {
|
|
207
|
+
setNotification({ text: errorNotificationText, type: "error" });
|
|
194
208
|
}
|
|
195
209
|
};
|
|
196
210
|
|
|
@@ -426,11 +440,6 @@ const PageEditor = (props: IProps) => {
|
|
|
426
440
|
}
|
|
427
441
|
};
|
|
428
442
|
|
|
429
|
-
const errorNotificationText =
|
|
430
|
-
"There are some errors on the page so you can not publish yet. Please review them in the error panel.";
|
|
431
|
-
|
|
432
|
-
const validatedNotificationText = "Everything seems ok, you can publish the page.";
|
|
433
|
-
|
|
434
443
|
const modifiedNotificationText =
|
|
435
444
|
"You made some changes to the Live version that aren't implemented on this Draft. Check it out before you continue working.";
|
|
436
445
|
|
|
@@ -496,16 +505,6 @@ const PageEditor = (props: IProps) => {
|
|
|
496
505
|
/>
|
|
497
506
|
</S.NotificationWrapper>
|
|
498
507
|
)}
|
|
499
|
-
{errors.length > 0 && (
|
|
500
|
-
<S.NotificationWrapper>
|
|
501
|
-
<Notification type="error" text={errorNotificationText} />
|
|
502
|
-
</S.NotificationWrapper>
|
|
503
|
-
)}
|
|
504
|
-
{validated && (
|
|
505
|
-
<S.NotificationWrapper>
|
|
506
|
-
<Notification type="success" text={validatedNotificationText} />
|
|
507
|
-
</S.NotificationWrapper>
|
|
508
|
-
)}
|
|
509
508
|
{isLivePageChanged && (
|
|
510
509
|
<S.NotificationWrapper>
|
|
511
510
|
<Notification type="warning" text={modifiedNotificationText} />
|
|
@@ -598,7 +597,6 @@ const mapStateToProps = (state: IRootState): IPageEditorStateProps => ({
|
|
|
598
597
|
activatedTemplates: state.dataPacks.templates,
|
|
599
598
|
activatedModules: state.dataPacks.modules,
|
|
600
599
|
errors: state.pageEditor.errors,
|
|
601
|
-
validated: state.pageEditor.validated,
|
|
602
600
|
userEditing: state.pageEditor.userEditing,
|
|
603
601
|
currentUserID: state.users.currentUser.id,
|
|
604
602
|
isNewTranslation: state.pageEditor.isNewTranslation,
|
|
@@ -620,7 +618,6 @@ interface IPageEditorStateProps {
|
|
|
620
618
|
activatedTemplates: any[];
|
|
621
619
|
activatedModules: string[];
|
|
622
620
|
errors: IErrorItem[];
|
|
623
|
-
validated: boolean;
|
|
624
621
|
userEditing: IUserEditing | null;
|
|
625
622
|
currentUserID: number | null;
|
|
626
623
|
isNewTranslation: boolean;
|
|
@@ -62,10 +62,24 @@ const RedirectItem = (props: IRedirectItemProps): JSX.Element => {
|
|
|
62
62
|
};
|
|
63
63
|
|
|
64
64
|
const secondaryDeleteModalAction = { title: "Cancel", onClick: toggleModalDelete };
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
const target =
|
|
66
|
+
redirect.site?.siteUrl === "/"
|
|
67
|
+
? `(${redirect.domain || ""})`
|
|
68
|
+
: `(${redirect.domain || ""}|${redirect.site?.siteUrl || ""})`;
|
|
67
69
|
const regex = new RegExp(target, "g");
|
|
68
70
|
|
|
71
|
+
const isUrlAndDomainEqual = () => {
|
|
72
|
+
const urlWithSlash = `${redirect.to?.url}/`;
|
|
73
|
+
const domainWithSlash = `${redirect.domain}/`;
|
|
74
|
+
|
|
75
|
+
return (
|
|
76
|
+
urlWithSlash === redirect.domain ||
|
|
77
|
+
urlWithSlash === domainWithSlash ||
|
|
78
|
+
domainWithSlash === redirect.to?.url ||
|
|
79
|
+
redirect.domain === redirect.to?.url
|
|
80
|
+
);
|
|
81
|
+
};
|
|
82
|
+
|
|
69
83
|
return (
|
|
70
84
|
<>
|
|
71
85
|
<S.ItemRow role="rowgroup" selected={isSelected}>
|
|
@@ -83,7 +97,7 @@ const RedirectItem = (props: IRedirectItemProps): JSX.Element => {
|
|
|
83
97
|
{redirect.from.replace(regex, "")}
|
|
84
98
|
</S.UrlCell>
|
|
85
99
|
<S.UrlCell role="cell" onClick={handleClick}>
|
|
86
|
-
{redirect.to?.url?.replace(regex, "") || "Deleted page"}
|
|
100
|
+
{isUrlAndDomainEqual() ? "/" : redirect.to?.url?.replace(regex, "") || "Deleted page"}
|
|
87
101
|
</S.UrlCell>
|
|
88
102
|
<S.DateCell role="cell" onClick={handleClick}>
|
|
89
103
|
{redirect.date && format(new Date(redirect.date), "dd MMM yyyy")}
|
|
@@ -68,7 +68,7 @@ const Item = (props: IProps): JSX.Element => {
|
|
|
68
68
|
</Modal>
|
|
69
69
|
);
|
|
70
70
|
|
|
71
|
-
const deleteAction = (event: React.MouseEvent<
|
|
71
|
+
const deleteAction = (event: React.MouseEvent<HTMLButtonElement>) => {
|
|
72
72
|
event.preventDefault();
|
|
73
73
|
event.stopPropagation();
|
|
74
74
|
const force = false;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, { useEffect, useState } from "react";
|
|
2
2
|
import { connect } from "react-redux";
|
|
3
3
|
|
|
4
|
-
import { IDataPack, IErrorItem, IRootState, ISite } from "@ax/types";
|
|
4
|
+
import { IDataPack, IErrorItem, INotification, IRootState, ISite } 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, getDefaultTheme } from "@ax/helpers";
|
|
@@ -44,6 +44,7 @@ const Form = (props: IProps) => {
|
|
|
44
44
|
} = props;
|
|
45
45
|
|
|
46
46
|
const [isNewStructuredData, setIsNewStructuredData] = useState(!currentStructuredDataId);
|
|
47
|
+
const [notification, setNotification] = useState<INotification | null>(null);
|
|
47
48
|
const { isDirty, resetDirty, setIsDirty } = useIsDirty(form);
|
|
48
49
|
|
|
49
50
|
const { fields } = schema;
|
|
@@ -257,11 +258,6 @@ const Form = (props: IProps) => {
|
|
|
257
258
|
languageActions: isDataTranslatable ? languageActions : null,
|
|
258
259
|
};
|
|
259
260
|
|
|
260
|
-
const errorNotificationText =
|
|
261
|
-
"There are some errors on the page so you can not publish yet. Please review them in the error panel.";
|
|
262
|
-
|
|
263
|
-
const validatedNotificationText = "Everything seems ok, you can publish the page.";
|
|
264
|
-
|
|
265
261
|
return isLoading ? (
|
|
266
262
|
<Loading />
|
|
267
263
|
) : (
|
|
@@ -293,14 +289,15 @@ const Form = (props: IProps) => {
|
|
|
293
289
|
/>
|
|
294
290
|
</S.NotificationWrapper>
|
|
295
291
|
)}
|
|
296
|
-
{
|
|
292
|
+
{notification && (
|
|
297
293
|
<S.NotificationWrapper>
|
|
298
|
-
<Notification
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
294
|
+
<Notification
|
|
295
|
+
type={notification.type}
|
|
296
|
+
text={notification.text}
|
|
297
|
+
btnText={notification.btnText}
|
|
298
|
+
onClick={notification.onClick}
|
|
299
|
+
resetError={() => setNotification(null)}
|
|
300
|
+
/>
|
|
304
301
|
</S.NotificationWrapper>
|
|
305
302
|
)}
|
|
306
303
|
<ErrorToast size="l" />
|