@griddo/ax 1.66.13 → 1.67.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/package.json +2 -2
- package/src/__tests__/components/Fields/ConditionalField/ConditionalField.test.tsx +95 -0
- package/src/api/pages.tsx +15 -3
- package/src/api/redirects.tsx +4 -2
- package/src/api/sites.tsx +12 -4
- package/src/components/Browser/index.tsx +9 -22
- package/src/components/Browser/style.tsx +1 -6
- package/src/components/ErrorCenter/index.tsx +8 -5
- package/src/components/ErrorCenter/style.tsx +21 -8
- package/src/components/Fields/ComponentArray/MixableComponentArray/AddItemButton/index.tsx +3 -3
- package/src/components/Fields/ComponentArray/MixableComponentArray/index.tsx +60 -25
- package/src/components/Fields/ComponentContainer/index.tsx +21 -7
- package/src/components/Fields/ConditionalField/index.tsx +1 -1
- package/src/components/Fields/LinkField/index.tsx +111 -0
- package/src/components/Fields/ReferenceField/ItemList/index.tsx +4 -0
- package/src/components/Fields/ReferenceField/ManualPanel/index.tsx +12 -2
- package/src/components/Fields/ReferenceField/index.tsx +24 -12
- package/src/components/Fields/ReferenceField/style.tsx +12 -1
- package/src/components/Fields/UrlField/index.tsx +13 -1
- package/src/components/Fields/VisualUniqueSelection/utils.tsx +1 -6
- package/src/components/Fields/index.tsx +2 -0
- package/src/components/FieldsBehavior/index.tsx +14 -1
- package/src/components/Icon/components/Copy.js +14 -0
- package/src/components/Icon/components/Copy2.js +14 -0
- package/src/components/Icon/components/Duplicate.js +3 -5
- package/src/components/Icon/components/Page.js +12 -0
- package/src/components/Icon/svgs/Copy.svg +3 -0
- package/src/components/Icon/svgs/Copy2.svg +3 -0
- package/src/components/Icon/svgs/Duplicate.svg +1 -1
- package/src/components/Icon/svgs/page.svg +3 -0
- package/src/components/MainWrapper/AppBar/index.tsx +21 -10
- package/src/components/MainWrapper/AppBar/style.tsx +11 -3
- package/src/components/MainWrapper/index.tsx +2 -0
- package/src/components/Notification/index.tsx +1 -3
- package/src/components/SearchField/index.tsx +37 -4
- package/src/components/SearchField/style.tsx +23 -10
- package/src/components/index.tsx +2 -0
- package/src/containers/Navigation/Defaults/actions.tsx +2 -0
- package/src/containers/PageEditor/actions.tsx +92 -17
- package/src/containers/PageEditor/utils.tsx +2 -1
- package/src/containers/Sites/actions.tsx +53 -24
- package/src/containers/Sites/constants.tsx +2 -0
- package/src/containers/Sites/interfaces.tsx +12 -5
- package/src/containers/Sites/reducer.tsx +8 -0
- package/src/containers/StructuredData/actions.tsx +5 -8
- package/src/forms/index.tsx +9 -1
- package/src/forms/validators.tsx +119 -12
- package/src/helpers/index.tsx +2 -0
- package/src/helpers/objects.tsx +10 -2
- package/src/modules/Categories/CategoriesList/CategoryItem/index.tsx +3 -1
- package/src/modules/Categories/CategoriesList/CategoryPanel/index.tsx +15 -9
- package/src/modules/Categories/CategoriesList/index.tsx +2 -1
- package/src/modules/Content/PageItem/index.tsx +52 -2
- package/src/modules/Content/atoms.tsx +41 -3
- package/src/modules/Content/index.tsx +44 -2
- package/src/modules/Content/style.tsx +8 -1
- package/src/modules/FramePreview/index.tsx +85 -0
- package/src/modules/FramePreview/style.tsx +18 -0
- package/src/modules/GlobalEditor/Editor/index.tsx +3 -1
- package/src/modules/GlobalEditor/PageBrowser/index.tsx +3 -0
- package/src/modules/GlobalEditor/index.tsx +22 -6
- package/src/modules/PageEditor/Editor/index.tsx +5 -1
- package/src/modules/PageEditor/PageBrowser/index.tsx +4 -5
- package/src/modules/PageEditor/index.tsx +27 -9
- package/src/modules/Redirects/index.tsx +40 -10
- package/src/modules/Settings/Globals/index.tsx +1 -1
- package/src/modules/Sites/index.tsx +2 -2
- package/src/modules/StructuredData/StructuredDataList/GlobalPageItem/index.tsx +1 -1
- package/src/modules/StructuredData/StructuredDataList/index.tsx +19 -2
- package/src/modules/Users/Profile/index.tsx +3 -3
- package/src/routes/multisite.tsx +12 -4
- package/src/routes/site.tsx +1 -1
- package/src/types/index.tsx +13 -4
- package/tsconfig.paths.json +2 -1
|
@@ -35,4 +35,11 @@ const ModalContent = styled.div`
|
|
|
35
35
|
}
|
|
36
36
|
`;
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
const SelectWrapper = styled.div`
|
|
39
|
+
& .react-select__control,
|
|
40
|
+
.react-select__menu {
|
|
41
|
+
min-width: 100%;
|
|
42
|
+
}
|
|
43
|
+
`;
|
|
44
|
+
|
|
45
|
+
export { ContentListWrapper, TableWrapper, PaginationWrapper, EmptyWrapper, ModalContent, SelectWrapper };
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { connect } from "react-redux";
|
|
3
|
+
|
|
4
|
+
import * as components from "components";
|
|
5
|
+
import { SiteProvider } from "components";
|
|
6
|
+
import { Preview } from "@griddo/core";
|
|
7
|
+
import { getDefaultTheme } from "@ax/helpers";
|
|
8
|
+
import { Loading } from "@ax/components";
|
|
9
|
+
import { ILanguage, IRootState, ISocialState } from "@ax/types";
|
|
10
|
+
|
|
11
|
+
import * as S from "./style";
|
|
12
|
+
|
|
13
|
+
const FramePreview = (props: IProps) => {
|
|
14
|
+
const { content, socials, selectedEditorID, cloudinaryName, isLoading, currentSiteInfo, siteLangs, globalLangs } =
|
|
15
|
+
props;
|
|
16
|
+
|
|
17
|
+
const {
|
|
18
|
+
editorContent: { canonicalSite, language, pageLanguages },
|
|
19
|
+
header,
|
|
20
|
+
footer,
|
|
21
|
+
} = content;
|
|
22
|
+
|
|
23
|
+
document.body.classList.add("preview");
|
|
24
|
+
|
|
25
|
+
const API_URL = process.env.REACT_APP_API_ENDPOINT;
|
|
26
|
+
const PUBLIC_API_URL = process.env.REACT_APP_PUBLIC_API_ENDPOINT;
|
|
27
|
+
|
|
28
|
+
const globalTheme = getDefaultTheme();
|
|
29
|
+
const theme = currentSiteInfo ? currentSiteInfo.theme : globalTheme;
|
|
30
|
+
const langs = currentSiteInfo ? siteLangs : globalLangs;
|
|
31
|
+
const siteID = currentSiteInfo ? currentSiteInfo.id : canonicalSite;
|
|
32
|
+
|
|
33
|
+
if (isLoading) return <Loading />;
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<SiteProvider
|
|
37
|
+
cloudinaryCloudName={cloudinaryName}
|
|
38
|
+
theme={theme}
|
|
39
|
+
socials={socials}
|
|
40
|
+
siteLangs={langs}
|
|
41
|
+
selectEditorID={selectedEditorID}
|
|
42
|
+
renderer="editor"
|
|
43
|
+
apiUrl={API_URL}
|
|
44
|
+
publicApiUrl={PUBLIC_API_URL}
|
|
45
|
+
siteId={siteID}
|
|
46
|
+
>
|
|
47
|
+
<S.Wrapper ref={(ref: any) => ((window as any).browserRef = ref)}>
|
|
48
|
+
<Preview
|
|
49
|
+
isPage={true}
|
|
50
|
+
apiUrl={API_URL}
|
|
51
|
+
library={components}
|
|
52
|
+
content={content.editorContent}
|
|
53
|
+
header={currentSiteInfo && header}
|
|
54
|
+
footer={currentSiteInfo && footer}
|
|
55
|
+
languageId={language}
|
|
56
|
+
pageLanguages={pageLanguages}
|
|
57
|
+
/>
|
|
58
|
+
</S.Wrapper>
|
|
59
|
+
</SiteProvider>
|
|
60
|
+
);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
interface IProps {
|
|
64
|
+
content: any;
|
|
65
|
+
selectedEditorID: number;
|
|
66
|
+
socials: ISocialState;
|
|
67
|
+
cloudinaryName: string | null;
|
|
68
|
+
currentSiteInfo: any;
|
|
69
|
+
siteLangs: ILanguage[];
|
|
70
|
+
globalLangs: ILanguage[];
|
|
71
|
+
isLoading: boolean;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const mapStateToProps = (state: IRootState) => ({
|
|
75
|
+
content: { ...state.pageEditor.editorContent },
|
|
76
|
+
selectedEditorID: state.pageEditor.selectedEditorID as number,
|
|
77
|
+
socials: state.social,
|
|
78
|
+
cloudinaryName: state.app.globalSettings.cloudinaryName,
|
|
79
|
+
currentSiteInfo: state.sites.currentSiteInfo,
|
|
80
|
+
siteLangs: state.sites.currentSiteLanguages,
|
|
81
|
+
globalLangs: state.app.globalLangs,
|
|
82
|
+
isLoading: state.app.isLoading,
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
export default connect(mapStateToProps)(FramePreview);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import styled from "styled-components";
|
|
2
|
+
|
|
3
|
+
const Wrapper = styled.div`
|
|
4
|
+
overflow: auto;
|
|
5
|
+
scroll-behavior: smooth;
|
|
6
|
+
height: 100%;
|
|
7
|
+
position: relative;
|
|
8
|
+
|
|
9
|
+
.headroom {
|
|
10
|
+
position: relative !important;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
body.preview:not(&) {
|
|
14
|
+
min-width: 0 !important;
|
|
15
|
+
}
|
|
16
|
+
`;
|
|
17
|
+
|
|
18
|
+
export { Wrapper };
|
|
@@ -29,6 +29,7 @@ const Editor = (props: IProps) => {
|
|
|
29
29
|
copyModule,
|
|
30
30
|
pasteModule,
|
|
31
31
|
theme,
|
|
32
|
+
browserRef,
|
|
32
33
|
setNotification,
|
|
33
34
|
} = props;
|
|
34
35
|
|
|
@@ -47,7 +48,7 @@ const Editor = (props: IProps) => {
|
|
|
47
48
|
|
|
48
49
|
return (
|
|
49
50
|
<ResizePanel
|
|
50
|
-
leftPanel={<PageBrowser isReadOnly={isReadOnly} theme={theme} />}
|
|
51
|
+
leftPanel={<PageBrowser isReadOnly={isReadOnly} theme={theme} browserRef={browserRef} />}
|
|
51
52
|
rightPanel={
|
|
52
53
|
<ConfigPanel
|
|
53
54
|
schema={schema}
|
|
@@ -99,6 +100,7 @@ interface IPageBrowserDispatchProps {
|
|
|
99
100
|
isEditable: boolean;
|
|
100
101
|
isReadOnly: boolean;
|
|
101
102
|
theme: string;
|
|
103
|
+
browserRef: any;
|
|
102
104
|
}
|
|
103
105
|
|
|
104
106
|
type IProps = IEditorStateProps & IPageBrowserDispatchProps;
|
|
@@ -18,6 +18,7 @@ const PageBrowser = (props: IProps) => {
|
|
|
18
18
|
theme,
|
|
19
19
|
isReadOnly,
|
|
20
20
|
isPreview,
|
|
21
|
+
browserRef,
|
|
21
22
|
} = props;
|
|
22
23
|
|
|
23
24
|
const slugWithSlash = slug ? (slug.startsWith("/") ? slug : `/${slug}`) : "";
|
|
@@ -38,6 +39,7 @@ const PageBrowser = (props: IProps) => {
|
|
|
38
39
|
disabled={isReadOnly}
|
|
39
40
|
siteID={canonicalSite}
|
|
40
41
|
isPreview={isPreview}
|
|
42
|
+
browserRef={browserRef}
|
|
41
43
|
/>
|
|
42
44
|
);
|
|
43
45
|
};
|
|
@@ -60,6 +62,7 @@ interface IPageBrowserDispatchProps {
|
|
|
60
62
|
theme: string;
|
|
61
63
|
isReadOnly: boolean;
|
|
62
64
|
isPreview?: boolean;
|
|
65
|
+
browserRef?: any;
|
|
63
66
|
}
|
|
64
67
|
|
|
65
68
|
type IProps = IEditorStateProps & IPageBrowserDispatchProps;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useEffect, useState } from "react";
|
|
1
|
+
import React, { useEffect, useState, useRef } from "react";
|
|
2
2
|
import { connect } from "react-redux";
|
|
3
3
|
import { RouteComponentProps } from "react-router-dom";
|
|
4
4
|
|
|
@@ -42,6 +42,7 @@ const GlobalEditor = (props: IProps) => {
|
|
|
42
42
|
savedSiteInfo,
|
|
43
43
|
userEditing,
|
|
44
44
|
isNewTranslation,
|
|
45
|
+
currentSiteErrorPages,
|
|
45
46
|
} = props;
|
|
46
47
|
|
|
47
48
|
const { isOpen, toggleModal } = useModal();
|
|
@@ -50,6 +51,8 @@ const GlobalEditor = (props: IProps) => {
|
|
|
50
51
|
const [selectedTab, setSelectedTab] = useState("edit");
|
|
51
52
|
const [notification, setNotification] = useState<INotification | null>(null);
|
|
52
53
|
const { isDirty, setIsDirty, resetDirty } = useIsDirty(editorContent.editorContent, isNewTranslation);
|
|
54
|
+
const [errorPagesChecked, setErrorPagesChecked] = useState(false);
|
|
55
|
+
const browserRef = useRef<HTMLDivElement>(null);
|
|
53
56
|
|
|
54
57
|
const isPublished = props.pageStatus === pageStatus.PUBLISHED || props.pageStatus === pageStatus.UPLOAD_PENDING;
|
|
55
58
|
const isDraft = props.pageStatus === pageStatus.MODIFIED;
|
|
@@ -98,6 +101,16 @@ const GlobalEditor = (props: IProps) => {
|
|
|
98
101
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
99
102
|
}, [userEditing]);
|
|
100
103
|
|
|
104
|
+
useEffect(() => {
|
|
105
|
+
if (!errorPagesChecked && !isLoading && editorContent.editorContent) {
|
|
106
|
+
const pageId = editorContent.editorContent.id;
|
|
107
|
+
const hasErrors = currentSiteErrorPages.some((errorPageId) => pageId === errorPageId);
|
|
108
|
+
hasErrors && reviewPage();
|
|
109
|
+
setErrorPagesChecked(true);
|
|
110
|
+
}
|
|
111
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
112
|
+
}, [editorContent]);
|
|
113
|
+
|
|
101
114
|
const setRoute = (path: string) => props.setHistoryPush(path, true);
|
|
102
115
|
|
|
103
116
|
const removePage = async () => {
|
|
@@ -114,7 +127,7 @@ const GlobalEditor = (props: IProps) => {
|
|
|
114
127
|
const publishPage = async () => {
|
|
115
128
|
const { updatePageStatus, savePage, pageID, validatePage } = props;
|
|
116
129
|
|
|
117
|
-
const validated = await validatePage(true);
|
|
130
|
+
const validated = await validatePage(true, browserRef);
|
|
118
131
|
|
|
119
132
|
if (validated) {
|
|
120
133
|
const publishPage = {
|
|
@@ -134,7 +147,7 @@ const GlobalEditor = (props: IProps) => {
|
|
|
134
147
|
const publishChanges = async () => {
|
|
135
148
|
const { savePage, validatePage } = props;
|
|
136
149
|
|
|
137
|
-
const validated = await validatePage(true);
|
|
150
|
+
const validated = await validatePage(true, browserRef);
|
|
138
151
|
|
|
139
152
|
if (validated) {
|
|
140
153
|
const publishPage = {
|
|
@@ -163,13 +176,13 @@ const GlobalEditor = (props: IProps) => {
|
|
|
163
176
|
|
|
164
177
|
const reviewPage = () => {
|
|
165
178
|
const { validatePage } = props;
|
|
166
|
-
validatePage();
|
|
179
|
+
validatePage(undefined, browserRef);
|
|
167
180
|
};
|
|
168
181
|
|
|
169
182
|
const handlePublishDraft = async () => {
|
|
170
183
|
const { savePage, validatePage } = props;
|
|
171
184
|
|
|
172
|
-
const validated = await validatePage(true);
|
|
185
|
+
const validated = await validatePage(true, browserRef);
|
|
173
186
|
|
|
174
187
|
if (validated) {
|
|
175
188
|
const isSaved = await savePage(false, null, true);
|
|
@@ -462,6 +475,7 @@ const GlobalEditor = (props: IProps) => {
|
|
|
462
475
|
isEditable={isEditable}
|
|
463
476
|
isReadOnly={isReadOnly}
|
|
464
477
|
theme={theme}
|
|
478
|
+
browserRef={browserRef}
|
|
465
479
|
setNotification={setNotification}
|
|
466
480
|
/>
|
|
467
481
|
</S.Content>
|
|
@@ -524,6 +538,7 @@ const mapStateToProps = (state: IRootState): IPageEditorStateProps => ({
|
|
|
524
538
|
userEditing: state.pageEditor.userEditing,
|
|
525
539
|
currentUserID: state.users.currentUser.id,
|
|
526
540
|
isNewTranslation: state.pageEditor.isNewTranslation,
|
|
541
|
+
currentSiteErrorPages: state.sites.currentSiteErrorPages,
|
|
527
542
|
});
|
|
528
543
|
|
|
529
544
|
interface IPageEditorStateProps {
|
|
@@ -543,6 +558,7 @@ interface IPageEditorStateProps {
|
|
|
543
558
|
userEditing: IUserEditing | null;
|
|
544
559
|
currentUserID: number | null;
|
|
545
560
|
isNewTranslation: boolean;
|
|
561
|
+
currentSiteErrorPages: number[];
|
|
546
562
|
}
|
|
547
563
|
|
|
548
564
|
const mapDispatchToProps = {
|
|
@@ -567,7 +583,7 @@ interface IPageEditorDispatchProps {
|
|
|
567
583
|
getPage(pageID?: number, global?: boolean): Promise<void>;
|
|
568
584
|
savePage(createDraft: boolean, publishPage?: any, publishDraft?: boolean): Promise<boolean>;
|
|
569
585
|
deletePage(params?: ISavePageParams): Promise<boolean>;
|
|
570
|
-
validatePage(publish?: boolean): Promise<boolean>;
|
|
586
|
+
validatePage(publish?: boolean, browserRef?: any): Promise<boolean>;
|
|
571
587
|
updatePageStatus(id: number[], status: string): Promise<boolean>;
|
|
572
588
|
setHistoryPush(path: string, isEditor: boolean): void;
|
|
573
589
|
setLanguage?(lang: { locale: string; id: number | null }): void;
|
|
@@ -35,6 +35,7 @@ const Editor = (props: IProps) => {
|
|
|
35
35
|
isReadOnly,
|
|
36
36
|
userEditing,
|
|
37
37
|
site,
|
|
38
|
+
browserRef,
|
|
38
39
|
lastElementAddedId,
|
|
39
40
|
copyModule,
|
|
40
41
|
pasteModule,
|
|
@@ -58,7 +59,9 @@ const Editor = (props: IProps) => {
|
|
|
58
59
|
|
|
59
60
|
return (
|
|
60
61
|
<ResizePanel
|
|
61
|
-
leftPanel={
|
|
62
|
+
leftPanel={
|
|
63
|
+
<PageBrowser isTemplateActivated={isTemplateActivated} isReadOnly={isReadOnly} browserRef={browserRef} />
|
|
64
|
+
}
|
|
62
65
|
rightPanel={
|
|
63
66
|
<ConfigPanel
|
|
64
67
|
schema={schema}
|
|
@@ -119,6 +122,7 @@ interface IPageBrowserDispatchProps {
|
|
|
119
122
|
isEditable: boolean;
|
|
120
123
|
pageTitle: string;
|
|
121
124
|
isReadOnly: boolean;
|
|
125
|
+
browserRef: any;
|
|
122
126
|
}
|
|
123
127
|
|
|
124
128
|
type IProps = IEditorStateProps & IPageBrowserDispatchProps;
|
|
@@ -3,7 +3,7 @@ import { connect } from "react-redux";
|
|
|
3
3
|
import { pageEditorActions } from "@ax/containers/PageEditor";
|
|
4
4
|
|
|
5
5
|
import { Browser } from "@ax/components";
|
|
6
|
-
import {
|
|
6
|
+
import { ILanguage, IRootState, ISocialState } from "@ax/types";
|
|
7
7
|
|
|
8
8
|
const PageBrowser = (props: IProps) => {
|
|
9
9
|
const {
|
|
@@ -21,6 +21,7 @@ const PageBrowser = (props: IProps) => {
|
|
|
21
21
|
isTemplateActivated,
|
|
22
22
|
isReadOnly,
|
|
23
23
|
isPreview,
|
|
24
|
+
browserRef,
|
|
24
25
|
} = props;
|
|
25
26
|
|
|
26
27
|
const slugWithSlash = slug ? (slug.startsWith("/") ? slug : `/${slug}`) : "";
|
|
@@ -44,6 +45,7 @@ const PageBrowser = (props: IProps) => {
|
|
|
44
45
|
disabled={disabled}
|
|
45
46
|
siteID={siteID}
|
|
46
47
|
isPreview={isPreview}
|
|
48
|
+
browserRef={browserRef}
|
|
47
49
|
/>
|
|
48
50
|
);
|
|
49
51
|
};
|
|
@@ -56,8 +58,6 @@ interface IEditorStateProps {
|
|
|
56
58
|
socials: ISocialState;
|
|
57
59
|
cloudinaryName: string | null;
|
|
58
60
|
siteLangs: ILanguage[];
|
|
59
|
-
schema: ISchema | Record<string, unknown>;
|
|
60
|
-
breadcrumb: IBreadcrumbItem[];
|
|
61
61
|
selectedParent: any;
|
|
62
62
|
activatedModules: string[];
|
|
63
63
|
}
|
|
@@ -67,6 +67,7 @@ interface IPageBrowserDispatchProps {
|
|
|
67
67
|
isTemplateActivated: boolean;
|
|
68
68
|
isReadOnly: boolean;
|
|
69
69
|
isPreview?: boolean;
|
|
70
|
+
browserRef?: any;
|
|
70
71
|
}
|
|
71
72
|
|
|
72
73
|
type IProps = IEditorStateProps & IPageBrowserDispatchProps;
|
|
@@ -78,8 +79,6 @@ const mapStateToProps = (state: IRootState): IEditorStateProps => ({
|
|
|
78
79
|
socials: state.social,
|
|
79
80
|
cloudinaryName: state.app.globalSettings.cloudinaryName,
|
|
80
81
|
siteLangs: state.sites.currentSiteLanguages,
|
|
81
|
-
schema: state.pageEditor.schema,
|
|
82
|
-
breadcrumb: state.pageEditor.breadcrumb,
|
|
83
82
|
selectedParent: state.pageEditor.selectedParent,
|
|
84
83
|
activatedModules: state.dataPacks.modules,
|
|
85
84
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useEffect, useState } from "react";
|
|
1
|
+
import React, { useEffect, useState, useRef } from "react";
|
|
2
2
|
import { connect } from "react-redux";
|
|
3
3
|
import { RouteComponentProps } from "react-router-dom";
|
|
4
4
|
|
|
@@ -44,6 +44,7 @@ const PageEditor = (props: IProps) => {
|
|
|
44
44
|
pageEditor: { editorContent, schema },
|
|
45
45
|
userEditing,
|
|
46
46
|
isNewTranslation,
|
|
47
|
+
currentSiteErrorPages,
|
|
47
48
|
} = props;
|
|
48
49
|
|
|
49
50
|
const [deleteAllVersions, setDeleteAllVersions] = useState(false);
|
|
@@ -54,6 +55,8 @@ const PageEditor = (props: IProps) => {
|
|
|
54
55
|
const { isOpen, toggleModal } = useModal();
|
|
55
56
|
const { isOpen: isUnpublishOpen, toggleModal: toggleUnpublishModal } = useModal();
|
|
56
57
|
const { isOpen: isDeleteOpen, toggleModal: toggleDeleteModal } = useModal();
|
|
58
|
+
const [errorPagesChecked, setErrorPagesChecked] = useState(false);
|
|
59
|
+
const browserRef = useRef<HTMLDivElement>(null);
|
|
57
60
|
|
|
58
61
|
const isGlobal = editorContent.editorContent && editorContent.editorContent.origin === "GLOBAL";
|
|
59
62
|
const isEditable = editorContent.editorContent && editorContent.editorContent.editable;
|
|
@@ -101,6 +104,16 @@ const PageEditor = (props: IProps) => {
|
|
|
101
104
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
102
105
|
}, [lang]);
|
|
103
106
|
|
|
107
|
+
useEffect(() => {
|
|
108
|
+
if (!errorPagesChecked && !isLoading && editorContent.editorContent) {
|
|
109
|
+
const pageId = editorContent.editorContent.id;
|
|
110
|
+
const hasErrors = currentSiteErrorPages.some((errorPageId) => pageId === errorPageId);
|
|
111
|
+
hasErrors && reviewPage();
|
|
112
|
+
setErrorPagesChecked(true);
|
|
113
|
+
}
|
|
114
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
115
|
+
}, [editorContent]);
|
|
116
|
+
|
|
104
117
|
const setRoute = (path: string) => props.setHistoryPush(path, true);
|
|
105
118
|
|
|
106
119
|
const removePage = async () => {
|
|
@@ -118,7 +131,7 @@ const PageEditor = (props: IProps) => {
|
|
|
118
131
|
const publishPage = async () => {
|
|
119
132
|
const { updatePageStatus, savePage, pageID, validatePage } = props;
|
|
120
133
|
|
|
121
|
-
const validated = await validatePage(true);
|
|
134
|
+
const validated = await validatePage(true, browserRef);
|
|
122
135
|
|
|
123
136
|
if (validated) {
|
|
124
137
|
const publishPage = {
|
|
@@ -138,7 +151,7 @@ const PageEditor = (props: IProps) => {
|
|
|
138
151
|
const publishChanges = async () => {
|
|
139
152
|
const { savePage, validatePage } = props;
|
|
140
153
|
|
|
141
|
-
const validated = await validatePage(true);
|
|
154
|
+
const validated = await validatePage(true, browserRef);
|
|
142
155
|
|
|
143
156
|
if (validated) {
|
|
144
157
|
const publishPage = {
|
|
@@ -167,13 +180,13 @@ const PageEditor = (props: IProps) => {
|
|
|
167
180
|
|
|
168
181
|
const reviewPage = () => {
|
|
169
182
|
const { validatePage } = props;
|
|
170
|
-
validatePage();
|
|
183
|
+
validatePage(undefined, browserRef);
|
|
171
184
|
};
|
|
172
185
|
|
|
173
186
|
const handlePublishDraft = async () => {
|
|
174
187
|
const { savePage, validatePage } = props;
|
|
175
188
|
|
|
176
|
-
const validated = await validatePage(true);
|
|
189
|
+
const validated = await validatePage(true, browserRef);
|
|
177
190
|
|
|
178
191
|
if (validated) {
|
|
179
192
|
const isSaved = await savePage(false, null, true);
|
|
@@ -295,10 +308,12 @@ const PageEditor = (props: IProps) => {
|
|
|
295
308
|
|
|
296
309
|
const goToPages = (path: string) => setRoute(path);
|
|
297
310
|
|
|
298
|
-
const goToError = (editorID: number, tab: string, template: boolean) => {
|
|
311
|
+
const goToError = (editorID: number | null, tab: string, template: boolean) => {
|
|
299
312
|
const realEditorID = template ? 0 : editorID;
|
|
300
|
-
|
|
301
|
-
|
|
313
|
+
if (realEditorID !== null) {
|
|
314
|
+
setSelectedContent(realEditorID);
|
|
315
|
+
setTab(tab);
|
|
316
|
+
}
|
|
302
317
|
};
|
|
303
318
|
|
|
304
319
|
const modalText = (
|
|
@@ -506,6 +521,7 @@ const PageEditor = (props: IProps) => {
|
|
|
506
521
|
isEditable={isEditable}
|
|
507
522
|
pageTitle={pageName}
|
|
508
523
|
isReadOnly={isReadOnly}
|
|
524
|
+
browserRef={browserRef}
|
|
509
525
|
setNotification={setNotification}
|
|
510
526
|
/>
|
|
511
527
|
</S.Content>
|
|
@@ -576,6 +592,7 @@ const mapStateToProps = (state: IRootState): IPageEditorStateProps => ({
|
|
|
576
592
|
userEditing: state.pageEditor.userEditing,
|
|
577
593
|
currentUserID: state.users.currentUser.id,
|
|
578
594
|
isNewTranslation: state.pageEditor.isNewTranslation,
|
|
595
|
+
currentSiteErrorPages: state.sites.currentSiteErrorPages,
|
|
579
596
|
});
|
|
580
597
|
|
|
581
598
|
interface IPageEditorStateProps {
|
|
@@ -596,6 +613,7 @@ interface IPageEditorStateProps {
|
|
|
596
613
|
userEditing: IUserEditing | null;
|
|
597
614
|
currentUserID: number | null;
|
|
598
615
|
isNewTranslation: boolean;
|
|
616
|
+
currentSiteErrorPages: number[];
|
|
599
617
|
}
|
|
600
618
|
|
|
601
619
|
const mapDispatchToProps = {
|
|
@@ -622,7 +640,7 @@ interface IPageEditorDispatchProps {
|
|
|
622
640
|
getPage(pageID?: number): Promise<void>;
|
|
623
641
|
savePage(createDraft: boolean, publishPage?: any, publishDraft?: boolean): Promise<boolean>;
|
|
624
642
|
deletePage(params?: ISavePageParams): Promise<boolean>;
|
|
625
|
-
validatePage(publish?: boolean): Promise<boolean>;
|
|
643
|
+
validatePage(publish?: boolean, browserRef?: any): Promise<boolean>;
|
|
626
644
|
updatePageStatus(id: number[], status: string): Promise<boolean>;
|
|
627
645
|
setHistoryPush(path: string, isEditor: boolean): void;
|
|
628
646
|
setLanguage?(lang: { locale: string; id: number | null }): void;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, { useCallback, useEffect, useRef, useState } from "react";
|
|
2
2
|
import { connect } from "react-redux";
|
|
3
3
|
|
|
4
|
-
import { INavItem, IRedirect, IRootState } from "@ax/types";
|
|
4
|
+
import { IEmptyStateProps, INavItem, IRedirect, IRootState } from "@ax/types";
|
|
5
5
|
import { appActions } from "@ax/containers/App";
|
|
6
6
|
import { redirectsActions } from "@ax/containers/Redirects";
|
|
7
7
|
import { MainWrapper, ErrorToast, Nav, TableList, EmptyState, Toast } from "@ax/components";
|
|
@@ -30,6 +30,7 @@ const Redirects = (props: IProps): JSX.Element => {
|
|
|
30
30
|
importRedirects,
|
|
31
31
|
imports,
|
|
32
32
|
totalImports,
|
|
33
|
+
isLoading,
|
|
33
34
|
} = props;
|
|
34
35
|
|
|
35
36
|
const itemsPerPage = 50;
|
|
@@ -50,6 +51,10 @@ const Redirects = (props: IProps): JSX.Element => {
|
|
|
50
51
|
const { isOpen: isOpenCheckImport, toggleModal: toggleCheckImportModal } = useModal();
|
|
51
52
|
const [importData, setImportData] = useState<{ from: string; to: string }[]>([]);
|
|
52
53
|
const [isUploading, setIsUploading] = useState(false);
|
|
54
|
+
const [searchQuery, setSearchQuery] = useState<string>("");
|
|
55
|
+
const [searchFilter, setSearchFilter] = useState<string>("");
|
|
56
|
+
const [isEmpty, setIsEmpty] = useState(false);
|
|
57
|
+
const [emptyStateProps, setEmptyStateProps] = useState<IEmptyStateProps>({});
|
|
53
58
|
|
|
54
59
|
const initState = {
|
|
55
60
|
from: "",
|
|
@@ -62,17 +67,18 @@ const Redirects = (props: IProps): JSX.Element => {
|
|
|
62
67
|
const [formValues, setFormValues] = useState<IRedirect>(initState);
|
|
63
68
|
|
|
64
69
|
const redIds = redirects && redirects.map((red: any) => red.id);
|
|
65
|
-
const isEmpty = redirects && redirects.length === 0;
|
|
66
70
|
|
|
67
71
|
const getParams = useCallback(() => {
|
|
68
72
|
const params = {
|
|
69
73
|
page,
|
|
70
74
|
itemsPerPage,
|
|
71
75
|
pagination: true,
|
|
76
|
+
query: searchQuery.trim(),
|
|
77
|
+
filterBy: searchFilter === "filterby" || searchQuery.trim() === "" ? "" : searchFilter,
|
|
72
78
|
};
|
|
73
79
|
|
|
74
80
|
return params;
|
|
75
|
-
}, [page]);
|
|
81
|
+
}, [page, searchQuery, searchFilter]);
|
|
76
82
|
|
|
77
83
|
useEffect(() => {
|
|
78
84
|
const params = getParams();
|
|
@@ -81,7 +87,26 @@ const Redirects = (props: IProps): JSX.Element => {
|
|
|
81
87
|
tableRef.current.scrollTo(0, 0);
|
|
82
88
|
}
|
|
83
89
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
84
|
-
}, [page, currentFilterQuery]);
|
|
90
|
+
}, [page, currentFilterQuery, searchQuery, searchFilter]);
|
|
91
|
+
|
|
92
|
+
useEffect(() => {
|
|
93
|
+
if (!isLoading) {
|
|
94
|
+
const emptyState: IEmptyStateProps = {};
|
|
95
|
+
const isSearching = searchQuery.length > 0;
|
|
96
|
+
if (isSearching) {
|
|
97
|
+
emptyState.icon = "search";
|
|
98
|
+
emptyState.title = "Oh! No Results Found";
|
|
99
|
+
emptyState.message = "We couldn’t find what you are looking for. Please, try another search.";
|
|
100
|
+
} else {
|
|
101
|
+
emptyState.message = "To have a redirects on your site, create as many redirects as you want.";
|
|
102
|
+
emptyState.button = "Create New redirect";
|
|
103
|
+
emptyState.action = handleModal;
|
|
104
|
+
}
|
|
105
|
+
setIsEmpty(!redirects.length);
|
|
106
|
+
setEmptyStateProps(emptyState);
|
|
107
|
+
}
|
|
108
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
109
|
+
}, [isLoading]);
|
|
85
110
|
|
|
86
111
|
const {
|
|
87
112
|
resetBulkSelection,
|
|
@@ -176,12 +201,6 @@ const Redirects = (props: IProps): JSX.Element => {
|
|
|
176
201
|
toggleOverwriteModal();
|
|
177
202
|
};
|
|
178
203
|
|
|
179
|
-
const emptyStateProps = {
|
|
180
|
-
message: "To have a redirects on your site, create as many redirects as you want.",
|
|
181
|
-
button: "Create New redirect",
|
|
182
|
-
action: handleModal,
|
|
183
|
-
};
|
|
184
|
-
|
|
185
204
|
const pagination = {
|
|
186
205
|
setPage,
|
|
187
206
|
itemsPerPage,
|
|
@@ -236,6 +255,12 @@ const Redirects = (props: IProps): JSX.Element => {
|
|
|
236
255
|
|
|
237
256
|
const secondaryImportModalAction = { title: "Cancel", onClick: toggleCheckImportModal };
|
|
238
257
|
|
|
258
|
+
const searchFilters = [
|
|
259
|
+
{ value: "filterby", label: "Filter by" },
|
|
260
|
+
{ value: "from", label: "Old URL" },
|
|
261
|
+
{ value: "to", label: "New URL" },
|
|
262
|
+
];
|
|
263
|
+
|
|
239
264
|
return (
|
|
240
265
|
<>
|
|
241
266
|
<MainWrapper
|
|
@@ -243,6 +268,9 @@ const Redirects = (props: IProps): JSX.Element => {
|
|
|
243
268
|
title="SEO Settings"
|
|
244
269
|
rightButton={rightButtonProps}
|
|
245
270
|
rightLineButton={rightLineButtonProps}
|
|
271
|
+
searchAction={setSearchQuery}
|
|
272
|
+
filterSearchAction={setSearchFilter}
|
|
273
|
+
searchFilters={searchFilters}
|
|
246
274
|
>
|
|
247
275
|
<S.Wrapper>
|
|
248
276
|
<Nav current={currentNavItem} items={navItems} onClick={handleMenuClick} />
|
|
@@ -341,6 +369,7 @@ const mapStateToProps = (state: IRootState) => ({
|
|
|
341
369
|
currentSiteID: state.sites.currentSiteInfo && state.sites.currentSiteInfo.id,
|
|
342
370
|
totalImports: state.redirects.totalImports,
|
|
343
371
|
imports: state.redirects.imports,
|
|
372
|
+
isLoading: state.app.isLoading,
|
|
344
373
|
});
|
|
345
374
|
|
|
346
375
|
const mapDispatchToProps = {
|
|
@@ -357,6 +386,7 @@ interface IRedirectsProps {
|
|
|
357
386
|
totalItems: number;
|
|
358
387
|
currentSiteID: number | null;
|
|
359
388
|
totalImports: number;
|
|
389
|
+
isLoading: boolean;
|
|
360
390
|
imports: null | {
|
|
361
391
|
error: IRedirect[];
|
|
362
392
|
existing: IRedirect[];
|
|
@@ -87,7 +87,7 @@ const Globals = (props: IProps): JSX.Element => {
|
|
|
87
87
|
text="The design of the navigation modules has changed. Please, check the previously created."
|
|
88
88
|
btnText="Go to check"
|
|
89
89
|
onClick={goToNavigationModules}
|
|
90
|
-
|
|
90
|
+
resetError={closeNavigationNotification}
|
|
91
91
|
/>
|
|
92
92
|
)}
|
|
93
93
|
<S.FormWrapper>
|
|
@@ -28,7 +28,7 @@ const Sites = (props: IProps): JSX.Element => {
|
|
|
28
28
|
const fetchInitialData = async () => {
|
|
29
29
|
setCurrentSiteInfo(null);
|
|
30
30
|
await getStructuredData(token);
|
|
31
|
-
await getSites(
|
|
31
|
+
await getSites();
|
|
32
32
|
await getAllDataPacks();
|
|
33
33
|
await getUser("me");
|
|
34
34
|
|
|
@@ -68,7 +68,7 @@ interface IStateProps {
|
|
|
68
68
|
|
|
69
69
|
interface IDispatchProps {
|
|
70
70
|
setCurrentSiteInfo(currentSiteInfo: any): void;
|
|
71
|
-
getSites(
|
|
71
|
+
getSites(): Promise<void>;
|
|
72
72
|
getStructuredData(token: string, siteId?: number): Promise<void>;
|
|
73
73
|
setLanguage(lang: { locale: string; id: number | null }): void;
|
|
74
74
|
getAllDataPacks: () => Promise<void>;
|
|
@@ -405,7 +405,7 @@ interface IGlobalPageItemProps {
|
|
|
405
405
|
isAllPages?: boolean;
|
|
406
406
|
globalPage: IPage;
|
|
407
407
|
updatePageStatus(ids: number[], status: string, updatedFromList: boolean): Promise<boolean>;
|
|
408
|
-
duplicatePage(pageID: number, data: { title: string; slug: string }): Promise<
|
|
408
|
+
duplicatePage(pageID: number, data: { title: string; slug: string }, siteID?: number): Promise<boolean>;
|
|
409
409
|
setHistoryPush(path: string, isEditor: boolean): void;
|
|
410
410
|
deletePage(params?: ISavePageParams, currentLanguage?: string): Promise<boolean>;
|
|
411
411
|
getGlobalPages(): void;
|