@griddo/ax 11.7.10 → 11.7.12-rc.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/DateField/DateField.test.tsx +1 -3
- package/src/__tests__/components/FloatingMenu/FloatingMenu.test.tsx +8 -8
- package/src/__tests__/components/TableFilters/LiveFilter/LiveFilter.test.tsx +41 -6
- package/src/components/Fields/DateField/index.tsx +0 -6
- package/src/components/Fields/IntegrationsField/SideModal/index.tsx +1 -1
- package/src/components/Fields/MultiCheckSelect/index.tsx +14 -2
- package/src/components/Fields/ReferenceField/index.tsx +0 -1
- package/src/components/Fields/Wysiwyg/style.tsx +6 -0
- package/src/components/FloatingMenu/index.tsx +17 -16
- package/src/components/MainWrapper/AppBar/atoms.tsx +2 -2
- package/src/components/MainWrapper/AppBar/index.tsx +6 -2
- package/src/components/TableFilters/LiveFilter/index.tsx +3 -4
- package/src/containers/Navigation/Defaults/actions.tsx +7 -2
- package/src/containers/StructuredData/actions.tsx +1 -0
- package/src/hooks/modals.tsx +1 -1
- package/src/modules/App/Routing/NavMenu/index.tsx +31 -6
- package/src/modules/Content/BulkHeader/TableHeader/index.tsx +5 -1
- package/src/modules/Forms/FormEditor/Editor/SideModal/SideModalOption/index.tsx +1 -1
- package/src/modules/Forms/FormEditor/Editor/SideModal/SideModalOption/style.tsx +6 -3
- package/src/modules/GlobalEditor/index.tsx +5 -4
- package/src/modules/PageEditor/index.tsx +6 -4
- package/src/modules/Sites/SitesList/ListView/BulkHeader/TableHeader/index.tsx +1 -1
- package/src/modules/Sites/SitesList/hooks.tsx +4 -1
- package/src/modules/StructuredData/Form/index.tsx +1 -1
- package/src/modules/StructuredData/StructuredDataList/BulkHeader/TableHeader/index.tsx +5 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@griddo/ax",
|
|
3
3
|
"description": "Griddo Author Experience",
|
|
4
|
-
"version": "11.7.
|
|
4
|
+
"version": "11.7.12-rc.0",
|
|
5
5
|
"authors": [
|
|
6
6
|
"Álvaro Sánchez' <alvaro.sanches@secuoyas.com>",
|
|
7
7
|
"Diego M. Béjar <diego.bejar@secuoyas.com>",
|
|
@@ -223,5 +223,5 @@
|
|
|
223
223
|
"publishConfig": {
|
|
224
224
|
"access": "public"
|
|
225
225
|
},
|
|
226
|
-
"gitHead": "
|
|
226
|
+
"gitHead": "c7e40c899abb683a6c53cbe36f1bd19135c9670e"
|
|
227
227
|
}
|
|
@@ -63,7 +63,6 @@ describe("DateField component rendering", () => {
|
|
|
63
63
|
defaultProps.value = "01/01/2022 - 10/01/2022";
|
|
64
64
|
defaultProps.mandatory = false;
|
|
65
65
|
const onChangeMock = defaultProps.onChange as jest.MockedFunction<(value: any) => void>;
|
|
66
|
-
const handleValidationMock = defaultProps.handleValidation as jest.MockedFunction<(value: string) => void>;
|
|
67
66
|
|
|
68
67
|
render(
|
|
69
68
|
<ThemeProvider theme={parseTheme(globalTheme)}>
|
|
@@ -72,7 +71,6 @@ describe("DateField component rendering", () => {
|
|
|
72
71
|
);
|
|
73
72
|
|
|
74
73
|
expect(screen.getByTestId("dateWrapper")).toBeTruthy();
|
|
75
|
-
expect(
|
|
76
|
-
expect(handleValidationMock).toBeCalled();
|
|
74
|
+
expect(screen.getByDisplayValue("01/01/2022 - 10/01/2022")).toBeTruthy();
|
|
77
75
|
});
|
|
78
76
|
});
|
|
@@ -30,7 +30,7 @@ describe("FloatingMenu component rendering", () => {
|
|
|
30
30
|
);
|
|
31
31
|
|
|
32
32
|
const defaultProps: IFloatingProps = {
|
|
33
|
-
children:
|
|
33
|
+
children: <div>hola</div>,
|
|
34
34
|
Button: buttonContent,
|
|
35
35
|
isInAppBar: true,
|
|
36
36
|
position: "left",
|
|
@@ -58,7 +58,7 @@ describe("FloatingMenu component rendering", () => {
|
|
|
58
58
|
);
|
|
59
59
|
|
|
60
60
|
const defaultProps: IFloatingProps = {
|
|
61
|
-
children:
|
|
61
|
+
children: <div>hola</div>,
|
|
62
62
|
Button: buttonContent,
|
|
63
63
|
isInAppBar: true,
|
|
64
64
|
isCheckGroup: true,
|
|
@@ -138,7 +138,7 @@ describe("FloatingMenu component rendering", () => {
|
|
|
138
138
|
);
|
|
139
139
|
|
|
140
140
|
const defaultProps: IFloatingProps = {
|
|
141
|
-
children:
|
|
141
|
+
children: <div>hola</div>,
|
|
142
142
|
Button: buttonContent,
|
|
143
143
|
isInAppBar: true,
|
|
144
144
|
isCheckGroup: true,
|
|
@@ -228,7 +228,7 @@ describe("FloatingMenu component rendering", () => {
|
|
|
228
228
|
const buttonContent = () => <input type="checkbox" data-testid="menu-children" />;
|
|
229
229
|
|
|
230
230
|
const defaultProps: IFloatingProps = {
|
|
231
|
-
children:
|
|
231
|
+
children: <div>hola</div>,
|
|
232
232
|
Button: buttonContent,
|
|
233
233
|
isInAppBar: true,
|
|
234
234
|
isCheckGroup: true,
|
|
@@ -343,7 +343,7 @@ describe("FloatingMenu component rendering", () => {
|
|
|
343
343
|
const buttonContent = () => <span data-testid="menu-children">texto</span>;
|
|
344
344
|
|
|
345
345
|
const defaultProps: IFloatingProps = {
|
|
346
|
-
children:
|
|
346
|
+
children: <div>hola</div>,
|
|
347
347
|
Button: buttonContent,
|
|
348
348
|
isInAppBar: true,
|
|
349
349
|
isCheckGroup: false,
|
|
@@ -458,7 +458,7 @@ describe("FloatingMenu component rendering", () => {
|
|
|
458
458
|
const buttonContent = () => <span data-testid="menu-children">texto</span>;
|
|
459
459
|
|
|
460
460
|
const defaultProps: IFloatingProps = {
|
|
461
|
-
children:
|
|
461
|
+
children: <div>hola</div>,
|
|
462
462
|
Button: buttonContent,
|
|
463
463
|
isInAppBar: true,
|
|
464
464
|
isCheckGroup: false,
|
|
@@ -574,7 +574,7 @@ describe("FloatingMenu component rendering", () => {
|
|
|
574
574
|
const buttonContent = () => <span data-testid="menu-children">texto</span>;
|
|
575
575
|
|
|
576
576
|
const defaultProps: IFloatingProps = {
|
|
577
|
-
children:
|
|
577
|
+
children: <div>hola</div>,
|
|
578
578
|
Button: buttonContent,
|
|
579
579
|
isInAppBar: true,
|
|
580
580
|
isCheckGroup: false,
|
|
@@ -644,7 +644,7 @@ describe("FloatingMenu component rendering", () => {
|
|
|
644
644
|
const buttonContent = () => <span data-testid="menu-children">texto</span>;
|
|
645
645
|
|
|
646
646
|
const defaultProps: IFloatingProps = {
|
|
647
|
-
children:
|
|
647
|
+
children: <div>hola</div>,
|
|
648
648
|
Button: buttonContent,
|
|
649
649
|
isInAppBar: true,
|
|
650
650
|
isCheckGroup: false,
|
|
@@ -17,7 +17,6 @@ const defaultProps = mock<ILiveFilterProps>();
|
|
|
17
17
|
|
|
18
18
|
describe("LiveFilter component rendering", () => {
|
|
19
19
|
it("should render live filter", async () => {
|
|
20
|
-
defaultProps.hasBasicStatus = false;
|
|
21
20
|
defaultProps.value = [{ value: "all", label: "All" }];
|
|
22
21
|
const filterItems = jest.fn() as CalledWithMock<void, [pointer: string, filter: IQueryValue[]]>;
|
|
23
22
|
|
|
@@ -53,7 +52,6 @@ describe("LiveFilter component rendering", () => {
|
|
|
53
52
|
});
|
|
54
53
|
|
|
55
54
|
it("should render the component with no options", async () => {
|
|
56
|
-
defaultProps.hasBasicStatus = false;
|
|
57
55
|
defaultProps.value = [{ value: "all", label: "All" }];
|
|
58
56
|
const filterItems = jest.fn() as CalledWithMock<void, [pointer: string, filter: IQueryValue[]]>;
|
|
59
57
|
|
|
@@ -91,7 +89,6 @@ describe("LiveFilter component rendering", () => {
|
|
|
91
89
|
|
|
92
90
|
describe("LiveFilter events", () => {
|
|
93
91
|
it("should render check group on click", async () => {
|
|
94
|
-
defaultProps.hasBasicStatus = false;
|
|
95
92
|
defaultProps.value = [{ value: "all", label: "All" }];
|
|
96
93
|
const filterItemsMock = jest.fn() as CalledWithMock<void, [pointer: string, filter: IQueryValue[]]>;
|
|
97
94
|
|
|
@@ -132,7 +129,6 @@ describe("LiveFilter events", () => {
|
|
|
132
129
|
});
|
|
133
130
|
|
|
134
131
|
it("should check option on click", async () => {
|
|
135
|
-
defaultProps.hasBasicStatus = false;
|
|
136
132
|
defaultProps.value = [{ value: "all", label: "All" }];
|
|
137
133
|
const filterItemsMock = jest.fn() as CalledWithMock<void, [pointer: string, filter: IQueryValue[]]>;
|
|
138
134
|
|
|
@@ -176,7 +172,6 @@ describe("LiveFilter events", () => {
|
|
|
176
172
|
});
|
|
177
173
|
|
|
178
174
|
it("should uncheck selected option on click and select 'All' option", async () => {
|
|
179
|
-
defaultProps.hasBasicStatus = false;
|
|
180
175
|
defaultProps.value = [{ value: "all", label: "All" }];
|
|
181
176
|
const filterItemsMock = jest.fn() as CalledWithMock<void, [pointer: string, filter: IQueryValue[]]>;
|
|
182
177
|
|
|
@@ -225,7 +220,6 @@ describe("LiveFilter events", () => {
|
|
|
225
220
|
});
|
|
226
221
|
|
|
227
222
|
it("should call filterItems action on change", async () => {
|
|
228
|
-
defaultProps.hasBasicStatus = false;
|
|
229
223
|
defaultProps.value = [{ value: "all", label: "All" }];
|
|
230
224
|
const filterItemsMock = jest.fn() as CalledWithMock<void, [pointer: string, filter: IQueryValue[]]>;
|
|
231
225
|
|
|
@@ -264,4 +258,45 @@ describe("LiveFilter events", () => {
|
|
|
264
258
|
expect(filterItemsMock).toHaveBeenCalledTimes(1);
|
|
265
259
|
expect(filterItemsMock).toBeCalledWith("liveStatus", [{ label: "Offline", value: "offline" }]);
|
|
266
260
|
});
|
|
261
|
+
|
|
262
|
+
it("should render live filter with filter options", async () => {
|
|
263
|
+
defaultProps.value = [{ value: "all", label: "All" }];
|
|
264
|
+
const filterItems = jest.fn() as CalledWithMock<void, [pointer: string, filter: IQueryValue[]]>;
|
|
265
|
+
defaultProps.filterOptions = ["offline", "active", "scheduled"];
|
|
266
|
+
defaultProps.filterItems = filterItems;
|
|
267
|
+
const data = {
|
|
268
|
+
data: [
|
|
269
|
+
{ id: 1, title: "Offline", status: "offline" },
|
|
270
|
+
{ id: 2, title: "Publication pending", status: "upload-pending" },
|
|
271
|
+
{ id: 3, title: "Live", status: "active" },
|
|
272
|
+
{ id: 4, title: "Offline pending", status: "offline-pending" },
|
|
273
|
+
{ id: 5, title: "Live & modified", status: "modified" },
|
|
274
|
+
{ id: 6, title: "Publication scheduled", status: "scheduled" },
|
|
275
|
+
],
|
|
276
|
+
status: 200,
|
|
277
|
+
statusText: "Ok",
|
|
278
|
+
headers: {},
|
|
279
|
+
config: {},
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
mockedAxios.mockResolvedValue(data);
|
|
283
|
+
|
|
284
|
+
await act(async () => {
|
|
285
|
+
render(
|
|
286
|
+
<ThemeProvider theme={parseTheme(globalTheme)}>
|
|
287
|
+
<LiveFilter {...defaultProps} />
|
|
288
|
+
</ThemeProvider>
|
|
289
|
+
);
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
const liveFilterButton = screen.getByTestId("floating-menu-button");
|
|
293
|
+
expect(liveFilterButton).toBeTruthy();
|
|
294
|
+
fireEvent.click(liveFilterButton);
|
|
295
|
+
const floatingMenu = screen.getByTestId("floating-menu");
|
|
296
|
+
expect(floatingMenu).toBeTruthy();
|
|
297
|
+
const checkGroupFieldGroup = screen.getByTestId("check-group-field-group");
|
|
298
|
+
expect(checkGroupFieldGroup).toBeTruthy();
|
|
299
|
+
const checkFieldLabels = screen.getAllByTestId("check-field-label");
|
|
300
|
+
expect(checkFieldLabels).toHaveLength(4);
|
|
301
|
+
});
|
|
267
302
|
});
|
|
@@ -61,12 +61,6 @@ const DateField = (props: IDateFieldProps): JSX.Element => {
|
|
|
61
61
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
62
62
|
}, [editorID]);
|
|
63
63
|
|
|
64
|
-
useEffect(() => {
|
|
65
|
-
const { start, end } = initialDate;
|
|
66
|
-
handleOnChange([start, end]);
|
|
67
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
68
|
-
}, []);
|
|
69
|
-
|
|
70
64
|
registerLocale("en", en);
|
|
71
65
|
|
|
72
66
|
const handleOnChange = (dates: any) => {
|
|
@@ -12,7 +12,7 @@ const SideModal = (props: ISideModalProps): JSX.Element | null => {
|
|
|
12
12
|
const { integrations, isOpen, toggleModal, handleClick } = props;
|
|
13
13
|
|
|
14
14
|
const node = useRef<HTMLDivElement>(null);
|
|
15
|
-
const handleClickOutside = (e:
|
|
15
|
+
const handleClickOutside = (e: MouseEvent) => {
|
|
16
16
|
if (node.current?.contains(e.target as Node)) {
|
|
17
17
|
return;
|
|
18
18
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import React, { useState, memo } from "react";
|
|
1
|
+
import React, { useState, memo, useRef } from "react";
|
|
2
2
|
|
|
3
3
|
import { ILanguage, ISite } from "@ax/types";
|
|
4
4
|
import AsyncCheckGroup from "@ax/components/Fields/AsyncCheckGroup";
|
|
5
5
|
import CheckGroup from "@ax/components/Fields/CheckGroup";
|
|
6
|
+
import { useHandleClickOutside } from "@ax/hooks";
|
|
6
7
|
|
|
7
8
|
import * as S from "./style";
|
|
8
9
|
|
|
@@ -26,13 +27,24 @@ const MultiCheckSelect = (props: IMultiCheckSelectProps) => {
|
|
|
26
27
|
} = props;
|
|
27
28
|
|
|
28
29
|
const [isOpen, setIsOpen] = useState(false);
|
|
30
|
+
const wrapperRef = useRef<HTMLDivElement | null>(null);
|
|
29
31
|
|
|
30
32
|
const handleClick = () => setIsOpen(!isOpen);
|
|
31
33
|
|
|
34
|
+
const handleClickOutside = (e: MouseEvent) => {
|
|
35
|
+
if (wrapperRef.current?.contains(e.target as HTMLElement)) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
setIsOpen(false);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
useHandleClickOutside(isOpen, handleClickOutside);
|
|
43
|
+
|
|
32
44
|
const Asterisk = () => (mandatory ? <S.Asterisk>*</S.Asterisk> : null);
|
|
33
45
|
|
|
34
46
|
return (
|
|
35
|
-
<S.Wrapper className={className} data-testid="multi-check-select-wrapper">
|
|
47
|
+
<S.Wrapper ref={wrapperRef} className={className} data-testid="multi-check-select-wrapper">
|
|
36
48
|
<S.Field isOpen={isOpen} onClick={handleClick} disabled={disabled} data-testid="field">
|
|
37
49
|
{placeholder} <Asterisk />
|
|
38
50
|
</S.Field>
|
|
@@ -76,6 +76,8 @@ export const EditorWrapper = styled.div<{ error: boolean | undefined; disabled?:
|
|
|
76
76
|
border-radius: 0 0 4px 4px;
|
|
77
77
|
}
|
|
78
78
|
.fr-wrapper {
|
|
79
|
+
max-height: 50vh;
|
|
80
|
+
overflow: auto;
|
|
79
81
|
border-left: 1px solid
|
|
80
82
|
${(p) =>
|
|
81
83
|
p.error === true
|
|
@@ -91,6 +93,7 @@ export const EditorWrapper = styled.div<{ error: boolean | undefined; disabled?:
|
|
|
91
93
|
? p.theme.color.interactiveDisabled
|
|
92
94
|
: p.theme.color.uiLine};
|
|
93
95
|
}
|
|
96
|
+
|
|
94
97
|
.fr-disabled {
|
|
95
98
|
color: ${(p) => p.theme.color.interactiveDisabled};
|
|
96
99
|
}
|
|
@@ -122,6 +125,9 @@ export const EditorWrapper = styled.div<{ error: boolean | undefined; disabled?:
|
|
|
122
125
|
}
|
|
123
126
|
}
|
|
124
127
|
}
|
|
128
|
+
.fr-fullscreen .fr-wrapper {
|
|
129
|
+
max-height: none !important;
|
|
130
|
+
}
|
|
125
131
|
.fr-inline {
|
|
126
132
|
.fr-wrapper {
|
|
127
133
|
background: ${(p) => p.theme.color.uiBackground02};
|
|
@@ -15,27 +15,28 @@ const FloatingMenu = (props: IFloatingProps): JSX.Element => {
|
|
|
15
15
|
reactiveToHover,
|
|
16
16
|
offset,
|
|
17
17
|
} = props;
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
const
|
|
18
|
+
const wrapperRef = useRef<HTMLDivElement | null>(null);
|
|
19
|
+
const buttonRef = useRef<HTMLDivElement | null>(null);
|
|
20
|
+
const menuOptionsRef = useRef<HTMLDivElement | null>(null);
|
|
21
21
|
const [isOpen, setOpen] = useState(false);
|
|
22
22
|
|
|
23
23
|
useEffect(() => {
|
|
24
|
-
if (isOpen &&
|
|
25
|
-
const bounding =
|
|
26
|
-
const boundingChild =
|
|
24
|
+
if (isOpen && menuOptionsRef?.current) {
|
|
25
|
+
const bounding = menuOptionsRef.current.children[0].getBoundingClientRect();
|
|
26
|
+
const boundingChild =
|
|
27
|
+
menuOptionsRef.current.children[0] && menuOptionsRef.current.children[0].getBoundingClientRect();
|
|
27
28
|
if (bounding.bottom > (window.innerHeight || document.documentElement.clientHeight)) {
|
|
28
|
-
|
|
29
|
+
menuOptionsRef.current.scrollIntoView({ block: "end", behavior: "smooth" });
|
|
29
30
|
}
|
|
30
31
|
if (boundingChild && boundingChild.right > window.innerWidth) {
|
|
31
|
-
|
|
32
|
+
menuOptionsRef.current.style.right = "130px";
|
|
32
33
|
}
|
|
33
34
|
}
|
|
34
35
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
35
36
|
}, [isOpen]);
|
|
36
37
|
|
|
37
|
-
const handleClickOutside = (e:
|
|
38
|
-
if (
|
|
38
|
+
const handleClickOutside = (e: MouseEvent) => {
|
|
39
|
+
if (wrapperRef.current?.contains(e.target as HTMLElement)) {
|
|
39
40
|
return;
|
|
40
41
|
}
|
|
41
42
|
|
|
@@ -50,8 +51,8 @@ const FloatingMenu = (props: IFloatingProps): JSX.Element => {
|
|
|
50
51
|
|
|
51
52
|
const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {
|
|
52
53
|
e.stopPropagation();
|
|
53
|
-
const buttonWasClicked =
|
|
54
|
-
const optionWasSelected = isOpen &&
|
|
54
|
+
const buttonWasClicked = buttonRef.current?.contains(e.target as HTMLElement);
|
|
55
|
+
const optionWasSelected = isOpen && menuOptionsRef.current?.contains(e.target as HTMLElement);
|
|
55
56
|
|
|
56
57
|
if (buttonWasClicked) {
|
|
57
58
|
setOpen(!isOpen);
|
|
@@ -71,20 +72,20 @@ const FloatingMenu = (props: IFloatingProps): JSX.Element => {
|
|
|
71
72
|
|
|
72
73
|
return (
|
|
73
74
|
<S.Wrapper
|
|
74
|
-
ref={
|
|
75
|
+
ref={wrapperRef}
|
|
75
76
|
onClick={handleClick}
|
|
76
77
|
onMouseEnter={handleMouseEnter}
|
|
77
78
|
onMouseLeave={handleMouseLeave}
|
|
78
79
|
data-testid="floating-menu"
|
|
79
80
|
>
|
|
80
|
-
<S.ButtonWrapper ref={
|
|
81
|
+
<S.ButtonWrapper ref={buttonRef} data-testid="floating-menu-button">
|
|
81
82
|
<Button />
|
|
82
83
|
</S.ButtonWrapper>
|
|
83
84
|
|
|
84
85
|
{isOpen && (
|
|
85
86
|
<S.MenuWrapper
|
|
86
87
|
isInAppBar={isInAppBar}
|
|
87
|
-
ref={
|
|
88
|
+
ref={menuOptionsRef}
|
|
88
89
|
position={position}
|
|
89
90
|
offset={offset}
|
|
90
91
|
data-testid="floating-menu-wrapper"
|
|
@@ -98,7 +99,7 @@ const FloatingMenu = (props: IFloatingProps): JSX.Element => {
|
|
|
98
99
|
|
|
99
100
|
export interface IFloatingProps {
|
|
100
101
|
children: JSX.Element | (JSX.Element | boolean | JSX.Element[])[] | boolean;
|
|
101
|
-
Button: any;
|
|
102
|
+
Button: (props?: any) => React.JSX.Element;
|
|
102
103
|
isInAppBar?: boolean;
|
|
103
104
|
position?: string;
|
|
104
105
|
closeOnSelect?: boolean;
|
|
@@ -34,7 +34,7 @@ const ActionMenu = (props: any) => {
|
|
|
34
34
|
<S.ActionMenu>
|
|
35
35
|
<S.ActionMenuTitle> More actions </S.ActionMenuTitle>
|
|
36
36
|
<ActionMenuBtn menu={menu} />
|
|
37
|
-
{menu && menu.options.map((item: any
|
|
37
|
+
{menu && menu.options.map((item: any) => item && ActionMenuItem(item))}
|
|
38
38
|
</S.ActionMenu>
|
|
39
39
|
);
|
|
40
40
|
};
|
|
@@ -51,7 +51,7 @@ const ActionSimpleMenu = (props: any) => {
|
|
|
51
51
|
menu &&
|
|
52
52
|
menu.options.length > 0 && (
|
|
53
53
|
<S.ActionMenu data-testid="action-simple-menu">
|
|
54
|
-
{menu.options.map((item: any
|
|
54
|
+
{menu.options.map((item: any) => ActionMenuItem(item, true))}
|
|
55
55
|
</S.ActionMenu>
|
|
56
56
|
)
|
|
57
57
|
);
|
|
@@ -87,7 +87,7 @@ const AppBar = (props: IProps): JSX.Element => {
|
|
|
87
87
|
};
|
|
88
88
|
|
|
89
89
|
const LanguageBtn = () =>
|
|
90
|
-
language
|
|
90
|
+
language ? (
|
|
91
91
|
<>
|
|
92
92
|
<S.FlagWrapper data-testid="language-menu-btn">
|
|
93
93
|
<Flag name={language.locale} size="24" />
|
|
@@ -95,6 +95,8 @@ const AppBar = (props: IProps): JSX.Element => {
|
|
|
95
95
|
<S.LanguageTextWrapper data-testid="language-locale-label">{language.locale}</S.LanguageTextWrapper>
|
|
96
96
|
<DownArrowButton />
|
|
97
97
|
</>
|
|
98
|
+
) : (
|
|
99
|
+
<></>
|
|
98
100
|
);
|
|
99
101
|
|
|
100
102
|
const ErrorCenterBtn = () => (
|
|
@@ -106,10 +108,12 @@ const AppBar = (props: IProps): JSX.Element => {
|
|
|
106
108
|
);
|
|
107
109
|
|
|
108
110
|
const StatusBtn = () =>
|
|
109
|
-
pageStatus
|
|
111
|
+
pageStatus ? (
|
|
110
112
|
<S.StatusBtn data-testid="status-button">
|
|
111
113
|
<Icon name={pageStatus} size="24" />
|
|
112
114
|
</S.StatusBtn>
|
|
115
|
+
) : (
|
|
116
|
+
<></>
|
|
113
117
|
);
|
|
114
118
|
|
|
115
119
|
const statusMenu = {
|
|
@@ -8,7 +8,7 @@ import { IFilterValue, IPageLiveStatus, IQueryValue } from "@ax/types";
|
|
|
8
8
|
import * as S from "./style";
|
|
9
9
|
|
|
10
10
|
const LiveFilter = (props: ILiveFilterProps): JSX.Element => {
|
|
11
|
-
const { filterItems, value,
|
|
11
|
+
const { filterItems, value, filterOptions } = props;
|
|
12
12
|
|
|
13
13
|
const filters: IFilterValue[] = [
|
|
14
14
|
{
|
|
@@ -24,7 +24,6 @@ const LiveFilter = (props: ILiveFilterProps): JSX.Element => {
|
|
|
24
24
|
const parsedValue = Array.isArray(value) && value.length ? value.map((value) => value.value) : initialState;
|
|
25
25
|
const [selectedValue, setSelectedValue] = useState(parsedValue);
|
|
26
26
|
const [options, setOptions] = useState(filters);
|
|
27
|
-
const basicStatus = ["offline", "active", "scheduled"];
|
|
28
27
|
|
|
29
28
|
useEffect(() => {
|
|
30
29
|
const parsedValue = Array.isArray(value) && value.length ? value.map((value) => value.value) : initialState;
|
|
@@ -55,7 +54,7 @@ const LiveFilter = (props: ILiveFilterProps): JSX.Element => {
|
|
|
55
54
|
title: item.title,
|
|
56
55
|
icon: item.status,
|
|
57
56
|
};
|
|
58
|
-
if ((
|
|
57
|
+
if ((filterOptions && filterOptions.includes(newFilter.value)) || !filterOptions) {
|
|
59
58
|
filters.push(newFilter);
|
|
60
59
|
}
|
|
61
60
|
});
|
|
@@ -112,8 +111,8 @@ const LiveFilter = (props: ILiveFilterProps): JSX.Element => {
|
|
|
112
111
|
export interface ILiveFilterProps {
|
|
113
112
|
filterItems(pointer: string, filter: IQueryValue[]): void;
|
|
114
113
|
value: IQueryValue[];
|
|
115
|
-
hasBasicStatus?: boolean;
|
|
116
114
|
isSite?: boolean;
|
|
115
|
+
filterOptions?: string[];
|
|
117
116
|
}
|
|
118
117
|
|
|
119
118
|
export default LiveFilter;
|
|
@@ -531,7 +531,7 @@ const getUpdatedComponents = (editorContent: any, element: any, key: string) =>
|
|
|
531
531
|
const mapValues = (item: any) => {
|
|
532
532
|
if (item.editorID !== undefined && item.editorID === editorID) {
|
|
533
533
|
if (isCollectionItem) {
|
|
534
|
-
item[key] = updateCollection(type, item[key]);
|
|
534
|
+
item[key] = updateCollection(type, item[key] || []);
|
|
535
535
|
} else {
|
|
536
536
|
addElement(type);
|
|
537
537
|
}
|
|
@@ -553,7 +553,9 @@ const getUpdatedComponents = (editorContent: any, element: any, key: string) =>
|
|
|
553
553
|
function addModule(
|
|
554
554
|
type: string,
|
|
555
555
|
key: string,
|
|
556
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
556
557
|
selectedID: number,
|
|
558
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
557
559
|
isComponentModule?: boolean
|
|
558
560
|
): (dispatch: Dispatch, getState: () => IRootState) => void {
|
|
559
561
|
return (dispatch, getState) => {
|
|
@@ -760,6 +762,10 @@ function replaceElementsInCollection(
|
|
|
760
762
|
const updatedContent = replaceElements(selectedContent[key], newValue);
|
|
761
763
|
|
|
762
764
|
updateEditorContent(selectedContent.editorID, key, updatedContent)(dispatch, getState);
|
|
765
|
+
|
|
766
|
+
const { editorContent } = getStateValues(getState);
|
|
767
|
+
if (!editorContent) return;
|
|
768
|
+
generateContent(editorContent)(dispatch, getState);
|
|
763
769
|
};
|
|
764
770
|
}
|
|
765
771
|
|
|
@@ -778,7 +784,6 @@ function generateContent(editorContent: INavigation): (dispatch: Dispatch, getSt
|
|
|
778
784
|
dispatch(updateBreadcrumb(selectedEditorID || 0));
|
|
779
785
|
dispatch(setSelectedDefaultContent(selectedContent));
|
|
780
786
|
dispatch(setSelectedDefaultParentContent(selectedParent));
|
|
781
|
-
dispatch(setTab("content"));
|
|
782
787
|
dispatch(setCurrentNavigationLanguages(editorContent.navigationLanguages));
|
|
783
788
|
dispatch(setIsLoading(false));
|
|
784
789
|
};
|
|
@@ -634,6 +634,7 @@ function resetCurrentData(): (dispatch: Dispatch) => Promise<void> {
|
|
|
634
634
|
dispatch(setCurrentDataID(null));
|
|
635
635
|
dispatch(setCurrentDataContent([]));
|
|
636
636
|
dispatch(setSchema({}));
|
|
637
|
+
dispatch(setFilter("all-pages"));
|
|
637
638
|
//dispatch(setCurrentSearch(""));
|
|
638
639
|
} catch (e) {
|
|
639
640
|
console.log("Error", e);
|
package/src/hooks/modals.tsx
CHANGED
|
@@ -18,7 +18,7 @@ const useModal = (initialState?: boolean, bodyBlock = true) => {
|
|
|
18
18
|
};
|
|
19
19
|
};
|
|
20
20
|
|
|
21
|
-
const useHandleClickOutside = (isOpen: boolean, handleClickOutside:
|
|
21
|
+
const useHandleClickOutside = (isOpen: boolean, handleClickOutside: (e: MouseEvent) => void) => {
|
|
22
22
|
useEffect(() => {
|
|
23
23
|
if (isOpen) {
|
|
24
24
|
document.addEventListener("mousedown", handleClickOutside);
|
|
@@ -5,7 +5,7 @@ import { version } from "./../../../../../package.json";
|
|
|
5
5
|
|
|
6
6
|
import { IRouter, multisite, site } from "@ax/routes";
|
|
7
7
|
|
|
8
|
-
import { ILanguage, IRootState, ISite } from "@ax/types";
|
|
8
|
+
import { ILanguage, IRootState, ISite, IStructuredData } from "@ax/types";
|
|
9
9
|
import { IGlobalSettings } from "@ax/containers/App/reducer";
|
|
10
10
|
import { appActions } from "@ax/containers/App";
|
|
11
11
|
import { Icon, Tag } from "@ax/components";
|
|
@@ -17,7 +17,17 @@ import { NavProvider } from "./context";
|
|
|
17
17
|
import * as S from "./style";
|
|
18
18
|
|
|
19
19
|
const NavMenu = (props: IProps) => {
|
|
20
|
-
const {
|
|
20
|
+
const {
|
|
21
|
+
location,
|
|
22
|
+
setHistoryPush,
|
|
23
|
+
logout,
|
|
24
|
+
currentSiteInfo,
|
|
25
|
+
siteLanguages,
|
|
26
|
+
lang,
|
|
27
|
+
categories,
|
|
28
|
+
globalSettings,
|
|
29
|
+
structuredData,
|
|
30
|
+
} = props;
|
|
21
31
|
|
|
22
32
|
const { useForms } = globalSettings;
|
|
23
33
|
|
|
@@ -129,9 +139,16 @@ const NavMenu = (props: IProps) => {
|
|
|
129
139
|
const isSitePublished = isSite && currentSiteInfo && currentSiteInfo.isPublished;
|
|
130
140
|
|
|
131
141
|
if (isSite) {
|
|
132
|
-
const isSiteCategoriesAvailable = categories.site.length;
|
|
142
|
+
const isSiteCategoriesAvailable = !!categories.site.length;
|
|
133
143
|
const siteCategoriesRouteIdx = config.routes.findIndex((route: IRouter) => route.path === "/sites/categories");
|
|
134
144
|
config.routes[siteCategoriesRouteIdx].showInNav = isSiteCategoriesAvailable;
|
|
145
|
+
} else {
|
|
146
|
+
const isGlobalCategoriesAvailable = !!categories.global.length;
|
|
147
|
+
const isGlobalDataAvailable = !!structuredData.global.length;
|
|
148
|
+
const globalCategoriesRouteIdx = config.routes.findIndex((route: IRouter) => route.path === "/categories");
|
|
149
|
+
const globalDataRouteIdx = config.routes.findIndex((route: IRouter) => route.path === "/data");
|
|
150
|
+
config.routes[globalCategoriesRouteIdx].showInNav = isGlobalCategoriesAvailable;
|
|
151
|
+
config.routes[globalDataRouteIdx].showInNav = isGlobalDataAvailable;
|
|
135
152
|
}
|
|
136
153
|
|
|
137
154
|
return (
|
|
@@ -197,18 +214,25 @@ const NavMenu = (props: IProps) => {
|
|
|
197
214
|
};
|
|
198
215
|
|
|
199
216
|
interface IDispatchProps {
|
|
200
|
-
logout():
|
|
217
|
+
logout(): void;
|
|
201
218
|
setHistoryPush(path: string): void;
|
|
202
219
|
}
|
|
203
220
|
|
|
204
221
|
interface IConfig {
|
|
205
222
|
routes: IRouter[];
|
|
206
223
|
type: string;
|
|
207
|
-
logo:
|
|
224
|
+
logo: JSX.Element;
|
|
208
225
|
}
|
|
209
226
|
|
|
210
227
|
interface INavMenuProps {
|
|
211
|
-
categories:
|
|
228
|
+
categories: {
|
|
229
|
+
global: IStructuredData[];
|
|
230
|
+
site: IStructuredData[];
|
|
231
|
+
};
|
|
232
|
+
structuredData: {
|
|
233
|
+
global: IStructuredData[];
|
|
234
|
+
site: IStructuredData[];
|
|
235
|
+
};
|
|
212
236
|
currentSiteInfo: ISite | null;
|
|
213
237
|
siteLanguages: ILanguage[];
|
|
214
238
|
lang: { locale: string; id: number };
|
|
@@ -217,6 +241,7 @@ interface INavMenuProps {
|
|
|
217
241
|
|
|
218
242
|
const mapStateToProps = (state: IRootState) => ({
|
|
219
243
|
categories: state.structuredData.categories,
|
|
244
|
+
structuredData: state.structuredData.structuredData,
|
|
220
245
|
currentSiteInfo: state.sites.currentSiteInfo,
|
|
221
246
|
siteLanguages: state.sites.currentSiteLanguages,
|
|
222
247
|
lang: state.app.lang,
|
|
@@ -84,7 +84,11 @@ const TableHeader = (props: IProps): JSX.Element => {
|
|
|
84
84
|
</S.NameWrapper>
|
|
85
85
|
{activeColumns.includes("live") && (
|
|
86
86
|
<S.HeaderWrapper>
|
|
87
|
-
<LiveFilter
|
|
87
|
+
<LiveFilter
|
|
88
|
+
filterItems={filterItems}
|
|
89
|
+
value={filterValues.liveStatus}
|
|
90
|
+
filterOptions={["offline", "active", "scheduled"]}
|
|
91
|
+
/>
|
|
88
92
|
</S.HeaderWrapper>
|
|
89
93
|
)}
|
|
90
94
|
{CategoryColumns}
|
|
@@ -18,7 +18,7 @@ const SideModalOption = (props: IProps) => {
|
|
|
18
18
|
|
|
19
19
|
return (
|
|
20
20
|
<S.Item onClick={setOption} data-testid="side-modal-option">
|
|
21
|
-
<S.Thumbnail data-testid="side-modal-option-img" {...thumbnailProps} />
|
|
21
|
+
{thumbnailProps && <S.Thumbnail data-testid="side-modal-option-img" {...thumbnailProps} />}
|
|
22
22
|
{label}
|
|
23
23
|
</S.Item>
|
|
24
24
|
);
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import styled from "styled-components";
|
|
2
2
|
|
|
3
3
|
const Item = styled.li`
|
|
4
|
+
${(p) => p.theme.textStyle.uiS};
|
|
4
5
|
cursor: pointer;
|
|
5
6
|
padding: ${(p) => p.theme.spacing.xs};
|
|
6
|
-
padding-bottom: ${(p) => p.theme.spacing.
|
|
7
|
+
padding-bottom: ${(p) => p.theme.spacing.xs};
|
|
8
|
+
padding-top: ${(p) => p.theme.spacing.xs};
|
|
7
9
|
margin-bottom: ${(p) => p.theme.spacing.xs};
|
|
8
10
|
box-shadow: ${(p) => p.theme.shadow.shadowS};
|
|
9
11
|
border-radius: ${(p) => p.theme.radii.s};
|
|
10
|
-
${(p) => p.theme.textStyle.uiS};
|
|
11
12
|
background-color: ${(p) => p.theme.color.interactiveBackground};
|
|
13
|
+
min-height: ${(p) => p.theme.spacing.l};
|
|
14
|
+
align-content: center;
|
|
12
15
|
&:hover {
|
|
13
16
|
background: ${(p) => p.theme.color.overlayHoverPrimary};
|
|
14
17
|
}
|
|
@@ -19,7 +22,7 @@ const Item = styled.li`
|
|
|
19
22
|
|
|
20
23
|
const Thumbnail = styled.img`
|
|
21
24
|
cursor: pointer;
|
|
22
|
-
padding-bottom: ${(p) => p.theme.spacing.
|
|
25
|
+
padding-bottom: ${(p) => p.theme.spacing.xs};
|
|
23
26
|
`;
|
|
24
27
|
|
|
25
28
|
const TagWrapper = styled.div`
|
|
@@ -80,7 +80,7 @@ const GlobalEditor = (props: IProps) => {
|
|
|
80
80
|
const [notification, setNotification] = useState<INotification | null>(null);
|
|
81
81
|
const { isDirty, setIsDirty, resetDirty } = useIsDirty(editorContent, isNewTranslation);
|
|
82
82
|
const [errorPagesChecked, setErrorPagesChecked] = useState(false);
|
|
83
|
-
const [scheduleDate, setScheduleDate] = useState({ date: "", time: "12:00 am" });
|
|
83
|
+
const [scheduleDate, setScheduleDate] = useState({ date: dateToString(new Date(), "yyy/MM/dd"), time: "12:00 am" });
|
|
84
84
|
const { isOpen: isScheduleOpen, toggleModal: toggleScheduleModal } = useModal();
|
|
85
85
|
const { isOpen: isCancelScheduleOpen, toggleModal: toggleCancelScheduleModal } = useModal();
|
|
86
86
|
const browserRef = useRef<HTMLDivElement>(null);
|
|
@@ -169,9 +169,10 @@ const GlobalEditor = (props: IProps) => {
|
|
|
169
169
|
status: pageStatus.UPLOAD_PENDING,
|
|
170
170
|
};
|
|
171
171
|
|
|
172
|
-
const isSaved =
|
|
173
|
-
|
|
174
|
-
|
|
172
|
+
const isSaved =
|
|
173
|
+
pageID && !isNewTranslation
|
|
174
|
+
? await updatePageStatus([pageID], pageStatus.UPLOAD_PENDING)
|
|
175
|
+
: await savePage(false, publishPage);
|
|
175
176
|
|
|
176
177
|
if (isSaved) {
|
|
177
178
|
resetDirty();
|
|
@@ -79,7 +79,7 @@ const PageEditor = (props: IProps) => {
|
|
|
79
79
|
const [isReadOnly, setIsReadOnly] = useState(false);
|
|
80
80
|
const [selectedTab, setSelectedTab] = useState(defaultTab);
|
|
81
81
|
const [notification, setNotification] = useState<INotification | null>(null);
|
|
82
|
-
const [scheduleDate, setScheduleDate] = useState({ date: "", time: "12:00 am" });
|
|
82
|
+
const [scheduleDate, setScheduleDate] = useState({ date: dateToString(new Date(), "yyy/MM/dd"), time: "12:00 am" });
|
|
83
83
|
const { isDirty, setIsDirty, resetDirty } = useIsDirty(editorContent, isNewTranslation);
|
|
84
84
|
const { isOpen, toggleModal } = useModal();
|
|
85
85
|
const { isOpen: isUnpublishOpen, toggleModal: toggleUnpublishModal } = useModal();
|
|
@@ -175,9 +175,10 @@ const PageEditor = (props: IProps) => {
|
|
|
175
175
|
status: pageStatus.UPLOAD_PENDING,
|
|
176
176
|
};
|
|
177
177
|
|
|
178
|
-
const isSaved =
|
|
179
|
-
|
|
180
|
-
|
|
178
|
+
const isSaved =
|
|
179
|
+
pageID && !isNewTranslation
|
|
180
|
+
? await updatePageStatus([pageID], pageStatus.UPLOAD_PENDING)
|
|
181
|
+
: await savePage(false, publishPage);
|
|
181
182
|
|
|
182
183
|
if (isSaved) {
|
|
183
184
|
resetDirty();
|
|
@@ -259,6 +260,7 @@ const PageEditor = (props: IProps) => {
|
|
|
259
260
|
};
|
|
260
261
|
|
|
261
262
|
const handleSchedulePublication = async () => {
|
|
263
|
+
console.log(scheduleDate, "scheduleDate");
|
|
262
264
|
const date = new Date(`${scheduleDate.date} ${scheduleDate.time}`);
|
|
263
265
|
const dateString = dateToString(date, "dd/MM/yyyy HH:mm:ss");
|
|
264
266
|
const saved = await schedulePublication(dateString, isDraft);
|
|
@@ -49,7 +49,7 @@ const TableHeader = (props: IProps): JSX.Element => {
|
|
|
49
49
|
</S.NameWrapper>
|
|
50
50
|
<S.DomainHeader>Domain</S.DomainHeader>
|
|
51
51
|
<S.LiveHeader>
|
|
52
|
-
<LiveFilter filterItems={filterItems} value={liveFilterValue}
|
|
52
|
+
<LiveFilter filterItems={filterItems} value={liveFilterValue} filterOptions={["offline", "active"]} />
|
|
53
53
|
</S.LiveHeader>
|
|
54
54
|
<S.LastAccessCell>
|
|
55
55
|
<LastAccessFilter sortItems={sortItems} sortedState={sortedListStatus} />
|
|
@@ -33,7 +33,10 @@ const useFilterQuery = (defaultValues?: { order: IQueryValue[]; liveStatus: IQue
|
|
|
33
33
|
|
|
34
34
|
let filterQuery = "";
|
|
35
35
|
const currentQuery = (pointer: string, values: IQueryValue[]) => {
|
|
36
|
-
|
|
36
|
+
if (!values.length || !values[0].value || values[0].value === "all") {
|
|
37
|
+
return "";
|
|
38
|
+
}
|
|
39
|
+
return `&${pointer}=${values[0].value}`;
|
|
37
40
|
};
|
|
38
41
|
|
|
39
42
|
const isNotInitialValue = (pointer: keyof Record<string, IQueryValue[]>) => {
|
|
@@ -54,7 +54,7 @@ const Form = (props: IProps) => {
|
|
|
54
54
|
|
|
55
55
|
const [isNewStructuredData, setIsNewStructuredData] = useState(!currentStructuredDataId);
|
|
56
56
|
const [notification, setNotification] = useState<INotification | null>(null);
|
|
57
|
-
const [scheduleDate, setScheduleDate] = useState({ date: "", time: "12:00 am" });
|
|
57
|
+
const [scheduleDate, setScheduleDate] = useState({ date: dateToString(new Date(), "yyy/MM/dd"), time: "12:00 am" });
|
|
58
58
|
const { isOpen: isScheduleOpen, toggleModal: toggleScheduleModal } = useModal();
|
|
59
59
|
const { isOpen: isCancelScheduleOpen, toggleModal: toggleCancelScheduleModal } = useModal();
|
|
60
60
|
const { isDirty, resetDirty, setIsDirty } = useIsDirty(form);
|
|
@@ -115,7 +115,11 @@ const TableHeader = (props: IProps): JSX.Element => {
|
|
|
115
115
|
</S.NameWrapper>
|
|
116
116
|
{activeColumns.includes("live") && (
|
|
117
117
|
<S.HeaderWrapper>
|
|
118
|
-
<LiveFilter
|
|
118
|
+
<LiveFilter
|
|
119
|
+
filterItems={filterItems}
|
|
120
|
+
value={filterValues.liveStatus}
|
|
121
|
+
filterOptions={["offline", "active", "scheduled"]}
|
|
122
|
+
/>
|
|
119
123
|
</S.HeaderWrapper>
|
|
120
124
|
)}
|
|
121
125
|
{CategoryColumns}
|