@griddo/ax 11.13.2 → 11.13.3-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/config/jest/setup.js +10 -0
- package/package.json +2 -2
- package/src/GlobalStore.tsx +1 -1
- package/src/__tests__/components/Fields/AsyncCheckGroup/AsyncCheckGroup.test.tsx +276 -66
- package/src/__tests__/components/FloatingMenu/FloatingMenu.test.tsx +300 -99
- package/src/__tests__/modules/Settings/Social/Social.test.tsx +12 -4
- package/src/api/checkgroups.tsx +4 -3
- package/src/api/selects.tsx +12 -5
- package/src/components/ActionMenu/index.tsx +1 -3
- package/src/components/Browser/index.tsx +12 -3
- package/src/components/Browser/style.tsx +7 -0
- package/src/components/ConfigPanel/Form/index.tsx +47 -53
- package/src/components/Fields/AnalyticsField/PageAnalytics/atoms.tsx +9 -13
- package/src/components/Fields/AnalyticsField/PageAnalytics/index.tsx +37 -29
- package/src/components/Fields/AnalyticsField/StructuredDataAnalytics/atoms.tsx +9 -13
- package/src/components/Fields/AnalyticsField/StructuredDataAnalytics/index.tsx +17 -11
- package/src/components/Fields/AnalyticsField/index.tsx +1 -2
- package/src/components/Fields/AnalyticsField/utils.tsx +4 -4
- package/src/components/Fields/AsyncCheckGroup/index.tsx +97 -79
- package/src/components/Fields/AsyncSelect/index.tsx +33 -22
- package/src/components/Fields/DateField/DatePickerInput/index.tsx +2 -2
- package/src/components/Fields/DateField/index.tsx +3 -3
- package/src/components/Fields/IntegrationsField/SideModal/index.tsx +2 -2
- package/src/components/Fields/IntegrationsField/index.tsx +14 -10
- package/src/components/Fields/MultiCheckSelect/index.tsx +6 -6
- package/src/components/Fields/MultiCheckSelectGroup/index.tsx +39 -37
- package/src/components/Fields/MultiCheckSelectGroup/style.tsx +1 -1
- package/src/components/Fields/ReferenceField/ManualPanel/index.tsx +0 -2
- package/src/components/Fields/RichText/index.tsx +15 -7
- package/src/components/Fields/TextArea/index.tsx +9 -6
- package/src/components/FloatingMenu/index.tsx +32 -31
- package/src/components/FloatingMenu/style.tsx +23 -5
- package/src/components/Loader/components/SmallCircle.js +3 -3
- package/src/components/MainWrapper/AppBar/style.tsx +1 -0
- package/src/components/SideModal/index.tsx +1 -1
- package/src/components/TableFilters/CategoryFilter/index.tsx +14 -15
- package/src/containers/App/actions.tsx +7 -1
- package/src/containers/App/constants.tsx +2 -0
- package/src/containers/App/interfaces.tsx +5 -0
- package/src/containers/App/reducer.tsx +11 -2
- package/src/containers/Forms/actions.tsx +5 -7
- package/src/containers/Integrations/actions.tsx +1 -3
- package/src/containers/Navigation/Menu/actions.tsx +2 -2
- package/src/containers/PageEditor/actions.tsx +3 -2
- package/src/containers/Settings/DataPacks/actions.tsx +35 -29
- package/src/containers/Sites/actions.tsx +40 -33
- package/src/containers/StructuredData/actions.tsx +3 -9
- package/src/modules/ActivityLog/LogFilters/DateFilter/index.tsx +5 -4
- package/src/modules/Content/NewContentModal/PageImporter/index.tsx +1 -2
- package/src/modules/Content/index.tsx +8 -3
- package/src/modules/Content/style.tsx +7 -0
- package/src/modules/Navigation/Defaults/DefaultsEditor/index.tsx +58 -45
- package/src/modules/Navigation/Defaults/index.tsx +103 -104
- package/src/modules/PageEditor/index.tsx +9 -1
- package/src/modules/PublicPreview/index.tsx +2 -1
- package/src/modules/Settings/ContentTypes/DataPacks/Config/Form/index.tsx +60 -44
- package/src/modules/Settings/ContentTypes/DataPacks/Config/index.tsx +32 -37
- package/src/modules/Sites/index.tsx +3 -3
- package/src/modules/Users/UserList/index.tsx +1 -1
|
@@ -2,7 +2,7 @@ import { useEffect, useMemo, useRef, useState } from "react";
|
|
|
2
2
|
|
|
3
3
|
import type { IShareData } from "@ax/api";
|
|
4
4
|
import { shareToken as shareTokenApi } from "@ax/api";
|
|
5
|
-
import { BrowserContent, Icon, OcassionalToast, Select, SharePageModal, Toast, Tooltip } from "@ax/components";
|
|
5
|
+
import { BrowserContent, Icon, Loading, OcassionalToast, Select, SharePageModal, Toast, Tooltip } from "@ax/components";
|
|
6
6
|
import { findByEditorID } from "@ax/forms";
|
|
7
7
|
import { DEV_NOW, getShareTokenInfo } from "@ax/helpers";
|
|
8
8
|
import { useModal, useOnMessageReceivedFromIframe, useToast } from "@ax/hooks";
|
|
@@ -65,10 +65,10 @@ const Browser = (props: IBrowserProps): JSX.Element => {
|
|
|
65
65
|
const isKeywordsEditor = editorType === "keywords";
|
|
66
66
|
const isZoomEditor = isPageEditor || isHeadingsEditor || isKeywordsEditor;
|
|
67
67
|
|
|
68
|
-
const
|
|
69
|
-
|
|
68
|
+
const [isIframeLoading, setIsIframeLoading] = useState(!!showIframe);
|
|
70
69
|
const [previewResolution, setPreviewResolution] = useState("desktop");
|
|
71
70
|
const [dimensions, setDimensions] = useState({ resolution: DEFAULT_RESOLUTION, zoom: "100" });
|
|
71
|
+
const frameWrapperRef = useRef<HTMLDivElement>(null);
|
|
72
72
|
|
|
73
73
|
const urlPreview = `${domain}/editor/page-preview?preview=${!!isPreview}&disabled=${!!disabled}&type=${editorType}${headingFilterParam}${keywordsFilterParam}`;
|
|
74
74
|
const { isVisible, toggleToast, setIsVisible, state: toastState } = useToast();
|
|
@@ -297,6 +297,11 @@ const Browser = (props: IBrowserProps): JSX.Element => {
|
|
|
297
297
|
/>
|
|
298
298
|
)}
|
|
299
299
|
<S.FrameWrapper hasBorder={isZoomEditor} isFormEditor={isFormEditor} data-testid="navbar-iframe-wrapper">
|
|
300
|
+
{isIframeLoading && (
|
|
301
|
+
<S.FrameLoading>
|
|
302
|
+
<Loading />
|
|
303
|
+
</S.FrameLoading>
|
|
304
|
+
)}
|
|
300
305
|
{isPreview ? (
|
|
301
306
|
<iframe
|
|
302
307
|
title="Preview"
|
|
@@ -305,6 +310,8 @@ const Browser = (props: IBrowserProps): JSX.Element => {
|
|
|
305
310
|
src={urlPreview}
|
|
306
311
|
loading="lazy"
|
|
307
312
|
className="frame-content"
|
|
313
|
+
onLoad={() => setIsIframeLoading(false)}
|
|
314
|
+
style={{ visibility: isIframeLoading ? "hidden" : "visible" }}
|
|
308
315
|
/>
|
|
309
316
|
) : (
|
|
310
317
|
<div
|
|
@@ -321,11 +328,13 @@ const Browser = (props: IBrowserProps): JSX.Element => {
|
|
|
321
328
|
src={urlPreview}
|
|
322
329
|
loading="lazy"
|
|
323
330
|
className="frame-content"
|
|
331
|
+
onLoad={() => setIsIframeLoading(false)}
|
|
324
332
|
style={{
|
|
325
333
|
display: "block",
|
|
326
334
|
transform: isZoomEditor ? `scale(${parseInt(dimensions.zoom) / 100})` : "scale(1)",
|
|
327
335
|
transformOrigin: "0 0",
|
|
328
336
|
height: isZoomEditor ? `${Math.round(100 / (parseInt(dimensions.zoom) / 100))}%` : "100%",
|
|
337
|
+
visibility: isIframeLoading ? "hidden" : "visible",
|
|
329
338
|
}}
|
|
330
339
|
/>
|
|
331
340
|
</div>
|
|
@@ -78,6 +78,12 @@ const OuterContainer = styled.div`
|
|
|
78
78
|
height: 100%;
|
|
79
79
|
`;
|
|
80
80
|
|
|
81
|
+
const FrameLoading = styled.div`
|
|
82
|
+
position: absolute;
|
|
83
|
+
inset: 0;
|
|
84
|
+
z-index: 1;
|
|
85
|
+
`;
|
|
86
|
+
|
|
81
87
|
const Wrapper = styled.div`
|
|
82
88
|
border-left: 1px solid ${(p) => p.theme.color.uiLine};
|
|
83
89
|
border-right: 1px solid ${(p) => p.theme.color.uiLine};
|
|
@@ -146,4 +152,5 @@ export {
|
|
|
146
152
|
ResolutionWrapper,
|
|
147
153
|
ZoomWrapper,
|
|
148
154
|
SelectLabel,
|
|
155
|
+
FrameLoading,
|
|
149
156
|
};
|
|
@@ -1,18 +1,25 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { useState } from "react";
|
|
2
2
|
|
|
3
|
-
import { ISchema, ISchemaTab, ISchemaField } from "@ax/types";
|
|
4
3
|
import { Tabs } from "@ax/components";
|
|
5
4
|
import { usePermission } from "@ax/hooks";
|
|
5
|
+
import type { ISchema, ISchemaField, ISchemaTab } from "@ax/types";
|
|
6
6
|
|
|
7
7
|
import ConnectedField from "./ConnectedField";
|
|
8
8
|
|
|
9
9
|
import * as S from "./style";
|
|
10
10
|
|
|
11
|
+
const tabPermissions: Record<string, string> = {
|
|
12
|
+
content: "content",
|
|
13
|
+
config: "config",
|
|
14
|
+
"seo & analytics": "seo",
|
|
15
|
+
};
|
|
16
|
+
|
|
11
17
|
export const Form = (props: IFormProps): JSX.Element => {
|
|
12
18
|
const {
|
|
13
19
|
schema,
|
|
14
20
|
selectedTab,
|
|
15
21
|
setSelectedTab,
|
|
22
|
+
setSelectedContent,
|
|
16
23
|
actions,
|
|
17
24
|
isPage,
|
|
18
25
|
isGlobal,
|
|
@@ -37,15 +44,19 @@ export const Form = (props: IFormProps): JSX.Element => {
|
|
|
37
44
|
(!isGlobal && isAllowedToEditConfigPages) || (isGlobal && isAllowedToEditGlobalData);
|
|
38
45
|
const isAllowedToEditPageSEO = (!isGlobal && isAllowedToEditSiteSeo) || (isGlobal && isAllowedToEditGlobalSeo);
|
|
39
46
|
|
|
47
|
+
const permissionsByTab: Record<string, boolean | undefined> = {
|
|
48
|
+
content: isAllowedToEditPageContent,
|
|
49
|
+
config: isAllowedToEditPageConfig,
|
|
50
|
+
seo: isAllowedToEditPageSEO,
|
|
51
|
+
};
|
|
52
|
+
|
|
40
53
|
const tabContent = schema.configTabs.find((tab: ISchemaTab) => tab.title.toLowerCase() === selectedTab);
|
|
41
|
-
|
|
54
|
+
|
|
55
|
+
const goTo = (editorID: number) => setSelectedContent(editorID);
|
|
42
56
|
|
|
43
57
|
const generateFields = (field: ISchemaField) => {
|
|
44
|
-
const { setSelectedContent } = props;
|
|
45
58
|
const { key, whiteList } = field;
|
|
46
59
|
|
|
47
|
-
const goTo = (editorID: number) => setSelectedContent(editorID);
|
|
48
|
-
|
|
49
60
|
return (
|
|
50
61
|
<ConnectedField
|
|
51
62
|
selectedTab={selectedTab}
|
|
@@ -67,48 +78,47 @@ export const Form = (props: IFormProps): JSX.Element => {
|
|
|
67
78
|
);
|
|
68
79
|
};
|
|
69
80
|
|
|
70
|
-
const getTabs = () => {
|
|
71
|
-
let mappedTabs;
|
|
81
|
+
const getTabs = (): string[] => {
|
|
72
82
|
const isHeader = schema.type === "header";
|
|
73
83
|
const isPageSchema = schema.schemaType === "page";
|
|
84
|
+
|
|
74
85
|
if (isHeader && isPage) {
|
|
75
|
-
|
|
76
|
-
.
|
|
77
|
-
|
|
78
|
-
return hasModifiableFields && tab.title;
|
|
79
|
-
})
|
|
80
|
-
.filter((value: string | boolean) => !!value);
|
|
81
|
-
} else {
|
|
82
|
-
mappedTabs = schema.configTabs.reduce((acc: string[], curr: ISchemaTab) => {
|
|
83
|
-
const currTitle = curr.title.toLowerCase();
|
|
84
|
-
if (
|
|
85
|
-
!isPageSchema ||
|
|
86
|
-
(isPageSchema &&
|
|
87
|
-
((currTitle === "content" && isAllowedToEditPageContent) ||
|
|
88
|
-
(currTitle === "config" && isAllowedToEditPageConfig) ||
|
|
89
|
-
(currTitle === "seo & analytics" && isAllowedToEditPageSEO)))
|
|
90
|
-
) {
|
|
91
|
-
return [...acc, currTitle];
|
|
92
|
-
}
|
|
93
|
-
return acc;
|
|
94
|
-
}, []);
|
|
86
|
+
return schema.configTabs
|
|
87
|
+
.filter((tab) => tab.fields.some((field: any) => field.modifiable))
|
|
88
|
+
.map((tab) => tab.title);
|
|
95
89
|
}
|
|
96
90
|
|
|
97
|
-
return
|
|
91
|
+
return schema.configTabs
|
|
92
|
+
.filter((tab: ISchemaTab) => {
|
|
93
|
+
const currTitle = tab.title.toLowerCase();
|
|
94
|
+
const permKey = tabPermissions[currTitle];
|
|
95
|
+
return !isPageSchema || (permKey && permissionsByTab[permKey]);
|
|
96
|
+
})
|
|
97
|
+
.map((tab: ISchemaTab) => tab.title.toLowerCase());
|
|
98
98
|
};
|
|
99
99
|
|
|
100
100
|
const tabs = getTabs();
|
|
101
101
|
|
|
102
|
-
const
|
|
103
|
-
actions.restorePageNavigationAction && actions.restorePageNavigationAction("header");
|
|
102
|
+
const handleRestore = (type: "header" | "footer") => actions.restorePageNavigationAction?.(type);
|
|
104
103
|
|
|
105
|
-
const
|
|
106
|
-
|
|
104
|
+
const renderRestoreNotice = (type: "header" | "footer", value?: number | null) => {
|
|
105
|
+
if (selectedTab !== "content" || isGlobal || value !== 0) return null;
|
|
106
|
+
|
|
107
|
+
return (
|
|
108
|
+
<S.FieldWrapper>
|
|
109
|
+
This page doesn't have a {type}. Click{" "}
|
|
110
|
+
<S.Link data-testid={`${type}-link`} onClick={() => handleRestore(type)}>
|
|
111
|
+
here
|
|
112
|
+
</S.Link>{" "}
|
|
113
|
+
to restore it.
|
|
114
|
+
</S.FieldWrapper>
|
|
115
|
+
);
|
|
116
|
+
};
|
|
107
117
|
|
|
108
118
|
return (
|
|
109
119
|
<S.Wrapper data-testid="form-section">
|
|
110
120
|
<S.TabsWrapper headerHeight={headerHeight}>
|
|
111
|
-
<Tabs tabs={tabs} active={selectedTab} setSelectedTab={
|
|
121
|
+
<Tabs tabs={tabs} active={selectedTab} setSelectedTab={setSelectedTab} />
|
|
112
122
|
</S.TabsWrapper>
|
|
113
123
|
{selectedTab === "content" && isEditLive && (
|
|
114
124
|
<S.FieldWrapper>
|
|
@@ -116,25 +126,9 @@ export const Form = (props: IFormProps): JSX.Element => {
|
|
|
116
126
|
published version, you should <strong>discard or publish your draft</strong>.
|
|
117
127
|
</S.FieldWrapper>
|
|
118
128
|
)}
|
|
119
|
-
{
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
<S.Link data-testid="header-link" onClick={handleRestoreHeader}>
|
|
123
|
-
here
|
|
124
|
-
</S.Link>{" "}
|
|
125
|
-
to restore it.
|
|
126
|
-
</S.FieldWrapper>
|
|
127
|
-
)}
|
|
128
|
-
{selectedTab === "content" && !isGlobal && footer === 0 && (
|
|
129
|
-
<S.FieldWrapper>
|
|
130
|
-
This page doesn't have a footer. Click{" "}
|
|
131
|
-
<S.Link data-testid="footer-link" onClick={handleRestoreFooter}>
|
|
132
|
-
here
|
|
133
|
-
</S.Link>{" "}
|
|
134
|
-
to restore it.
|
|
135
|
-
</S.FieldWrapper>
|
|
136
|
-
)}
|
|
137
|
-
{tabContent && tabContent.fields.map((field: ISchemaField) => generateFields(field))}
|
|
129
|
+
{renderRestoreNotice("header", header)}
|
|
130
|
+
{renderRestoreNotice("footer", footer)}
|
|
131
|
+
{tabContent?.fields.map((field: ISchemaField) => generateFields(field))}
|
|
138
132
|
</S.Wrapper>
|
|
139
133
|
);
|
|
140
134
|
};
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
|
|
3
1
|
import { FieldsBehavior } from "@ax/components";
|
|
4
2
|
import { splitAndTrim } from "@ax/helpers";
|
|
5
|
-
import { IAnalytics, IDimension } from "@ax/types";
|
|
3
|
+
import type { IAnalytics, IDimension } from "@ax/types";
|
|
6
4
|
|
|
7
|
-
import { IState } from "..";
|
|
5
|
+
import type { IState } from "..";
|
|
8
6
|
import * as S from "../style";
|
|
9
7
|
|
|
10
8
|
const DimensionsGroup = (props: {
|
|
@@ -25,11 +23,10 @@ const DimensionsGroup = (props: {
|
|
|
25
23
|
return (
|
|
26
24
|
<>
|
|
27
25
|
<S.FieldsDivider />
|
|
28
|
-
{groupDimensions
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
)}
|
|
26
|
+
{groupDimensions?.map(
|
|
27
|
+
(dimension, idx) =>
|
|
28
|
+
dimension && <DimensionValue key={idx} {...{ dimension, setDimension, values, disabled }} />,
|
|
29
|
+
)}
|
|
33
30
|
</>
|
|
34
31
|
);
|
|
35
32
|
};
|
|
@@ -47,10 +44,9 @@ const DimensionsSelection = (props: {
|
|
|
47
44
|
return (
|
|
48
45
|
<>
|
|
49
46
|
{selectedDimensions?.length ? <S.FieldsDivider /> : <></>}
|
|
50
|
-
{selectedDimensions
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
))}
|
|
47
|
+
{selectedDimensions?.map((dimension, idx) => (
|
|
48
|
+
<DimensionValue key={idx} {...{ dimension, setDimension, values, disabled }} />
|
|
49
|
+
))}
|
|
54
50
|
</>
|
|
55
51
|
);
|
|
56
52
|
};
|
|
@@ -1,26 +1,32 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { useEffect, useRef, useState } from "react";
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { FieldsBehavior, NoteField } from "@ax/components";
|
|
4
4
|
|
|
5
|
-
import { IAnalyticsFieldProps, IState } from "..";
|
|
6
|
-
import { DimensionsGroup, DimensionsSelection } from "./atoms";
|
|
5
|
+
import type { IAnalyticsFieldProps, IState } from "..";
|
|
7
6
|
import * as S from "../style";
|
|
7
|
+
import { DimensionsGroup, DimensionsSelection } from "./atoms";
|
|
8
|
+
|
|
9
|
+
const initialState: IState = {
|
|
10
|
+
contentSelect: "",
|
|
11
|
+
groupSelect: "",
|
|
12
|
+
dimensionsSelect: [],
|
|
13
|
+
values: {},
|
|
14
|
+
};
|
|
8
15
|
|
|
9
16
|
const PageAnalytics = (props: IAnalyticsFieldProps): JSX.Element => {
|
|
10
17
|
const { value, onChange, analytics, disabled } = props;
|
|
11
18
|
|
|
12
|
-
const initialState = {
|
|
13
|
-
contentSelect: "",
|
|
14
|
-
groupSelect: "",
|
|
15
|
-
dimensionsSelect: [],
|
|
16
|
-
values: {},
|
|
17
|
-
};
|
|
18
|
-
|
|
19
19
|
const [state, setState] = useState<IState>(value || initialState);
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
const isMountRef = useRef(true);
|
|
22
|
+
|
|
23
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies: onChange is not memoized by parent, adding it causes infinite loop
|
|
22
24
|
useEffect(() => {
|
|
23
|
-
|
|
25
|
+
if (isMountRef.current) {
|
|
26
|
+
isMountRef.current = false;
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
onChange?.(state);
|
|
24
30
|
}, [state]);
|
|
25
31
|
|
|
26
32
|
const handleContentSelect = (contentSelect: string) => {
|
|
@@ -28,7 +34,7 @@ const PageAnalytics = (props: IAnalyticsFieldProps): JSX.Element => {
|
|
|
28
34
|
};
|
|
29
35
|
|
|
30
36
|
const handleGroupSelect = (groupSelect: string) => {
|
|
31
|
-
setState((
|
|
37
|
+
setState((prev: IState) => ({ ...prev, groupSelect, values: {} }));
|
|
32
38
|
};
|
|
33
39
|
|
|
34
40
|
const handleDimensionsSelect = (selection: string[]) => {
|
|
@@ -36,15 +42,17 @@ const PageAnalytics = (props: IAnalyticsFieldProps): JSX.Element => {
|
|
|
36
42
|
let dimensionsSelect = selection;
|
|
37
43
|
|
|
38
44
|
if (selection.includes("all")) {
|
|
39
|
-
dimensionsSelect = analytics.dimensions?.map((dimension) => dimension.name);
|
|
45
|
+
dimensionsSelect = analytics.dimensions?.map((dimension) => dimension.name) ?? [];
|
|
40
46
|
}
|
|
41
47
|
|
|
42
|
-
dimensionsSelect
|
|
43
|
-
|
|
48
|
+
dimensionsSelect.forEach((dimension) => {
|
|
49
|
+
values[dimension] = state.values[dimension];
|
|
50
|
+
});
|
|
51
|
+
setState((prev: IState) => ({ ...prev, dimensionsSelect, values }));
|
|
44
52
|
};
|
|
45
53
|
|
|
46
54
|
const setDimension = (value: Record<string, string>) => {
|
|
47
|
-
setState((
|
|
55
|
+
setState((prev: IState) => ({ ...prev, values: { ...prev.values, ...value } }));
|
|
48
56
|
};
|
|
49
57
|
|
|
50
58
|
const contentOptions = [
|
|
@@ -58,10 +66,11 @@ const PageAnalytics = (props: IAnalyticsFieldProps): JSX.Element => {
|
|
|
58
66
|
},
|
|
59
67
|
];
|
|
60
68
|
|
|
61
|
-
const groupOptions
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
69
|
+
const groupOptions =
|
|
70
|
+
analytics.groups?.map((group) => ({
|
|
71
|
+
label: group.name,
|
|
72
|
+
value: group.name,
|
|
73
|
+
})) ?? [];
|
|
65
74
|
|
|
66
75
|
const noteText = (
|
|
67
76
|
<>
|
|
@@ -82,15 +91,12 @@ const PageAnalytics = (props: IAnalyticsFieldProps): JSX.Element => {
|
|
|
82
91
|
value: "all",
|
|
83
92
|
title: "Select All",
|
|
84
93
|
},
|
|
85
|
-
|
|
86
|
-
analytics.dimensions?.forEach((dimension) => {
|
|
87
|
-
const option = {
|
|
94
|
+
...(analytics.dimensions?.map((dimension) => ({
|
|
88
95
|
name: dimension.name,
|
|
89
96
|
value: dimension.name,
|
|
90
97
|
title: dimension.name,
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
});
|
|
98
|
+
})) ?? []),
|
|
99
|
+
];
|
|
94
100
|
|
|
95
101
|
return (
|
|
96
102
|
<>
|
|
@@ -133,7 +139,9 @@ const PageAnalytics = (props: IAnalyticsFieldProps): JSX.Element => {
|
|
|
133
139
|
disabled={disabled}
|
|
134
140
|
floating
|
|
135
141
|
/>
|
|
136
|
-
{
|
|
142
|
+
{state.dimensionsSelect.length > 0 && (
|
|
143
|
+
<DimensionsSelection {...{ analytics, state, setDimension, disabled }} />
|
|
144
|
+
)}
|
|
137
145
|
</>
|
|
138
146
|
)}
|
|
139
147
|
</>
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
|
|
3
1
|
import { FieldsBehavior } from "@ax/components";
|
|
4
2
|
import { splitAndTrim } from "@ax/helpers";
|
|
5
|
-
import { IAnalytics, IDimension } from "@ax/types";
|
|
3
|
+
import type { IAnalytics, IDimension } from "@ax/types";
|
|
6
4
|
|
|
7
|
-
import { IState } from "..";
|
|
5
|
+
import type { IState } from "..";
|
|
8
6
|
|
|
9
7
|
const TemplateDimensions = (props: ITemplateDimensions): JSX.Element => {
|
|
10
8
|
const { analytics, state, setDimension, dimensionNames, disabled } = props;
|
|
@@ -16,11 +14,10 @@ const TemplateDimensions = (props: ITemplateDimensions): JSX.Element => {
|
|
|
16
14
|
|
|
17
15
|
return (
|
|
18
16
|
<>
|
|
19
|
-
{groupDimensions
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
)}
|
|
17
|
+
{groupDimensions?.map(
|
|
18
|
+
(dimension, idx) =>
|
|
19
|
+
dimension && <DimensionValue key={idx} {...{ dimension, setDimension, values, disabled }} />,
|
|
20
|
+
)}
|
|
24
21
|
</>
|
|
25
22
|
);
|
|
26
23
|
};
|
|
@@ -37,10 +34,9 @@ const DimensionsSelection = (props: {
|
|
|
37
34
|
|
|
38
35
|
return (
|
|
39
36
|
<>
|
|
40
|
-
{selectedDimensions
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
))}
|
|
37
|
+
{selectedDimensions?.map((dimension, idx) => (
|
|
38
|
+
<DimensionValue key={idx} {...{ dimension, setDimension, values, disabled }} />
|
|
39
|
+
))}
|
|
44
40
|
</>
|
|
45
41
|
);
|
|
46
42
|
};
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
2
|
|
|
3
3
|
import { FieldsBehavior } from "@ax/components";
|
|
4
4
|
|
|
5
|
-
import { IAnalyticsFieldProps, IState } from "..";
|
|
6
|
-
import { getTemplateDimensions } from "../utils";
|
|
7
|
-
import { TemplateDimensions, DimensionsSelection } from "./atoms";
|
|
5
|
+
import type { IAnalyticsFieldProps, IState } from "..";
|
|
8
6
|
import * as S from "../style";
|
|
7
|
+
import { getTemplateDimensions } from "../utils";
|
|
8
|
+
import { DimensionsSelection, TemplateDimensions } from "./atoms";
|
|
9
9
|
|
|
10
10
|
const StructuredDataAnalytics = (props: IAnalyticsFieldProps): JSX.Element => {
|
|
11
11
|
const { value, onChange, analytics, template, disabled } = props;
|
|
@@ -17,28 +17,32 @@ const StructuredDataAnalytics = (props: IAnalyticsFieldProps): JSX.Element => {
|
|
|
17
17
|
|
|
18
18
|
const [state, setState] = useState<IState>({ ...initialState, ...value });
|
|
19
19
|
|
|
20
|
-
// biome-ignore lint/correctness/useExhaustiveDependencies:
|
|
20
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies: onChange is not memoized by parent, adding it causes infinite loop
|
|
21
21
|
useEffect(() => {
|
|
22
|
-
onChange
|
|
22
|
+
onChange?.(state);
|
|
23
23
|
}, [state]);
|
|
24
24
|
|
|
25
25
|
const templateDimensions = getTemplateDimensions(analytics.groups, template);
|
|
26
26
|
|
|
27
27
|
const handleDimensionsSelect = (selection: string[]) => {
|
|
28
28
|
const values: Record<string, string> = {};
|
|
29
|
-
templateDimensions.forEach((dimension) =>
|
|
29
|
+
templateDimensions.forEach((dimension) => {
|
|
30
|
+
values[dimension] = state.values[dimension];
|
|
31
|
+
});
|
|
30
32
|
let dimensionsSelect = selection;
|
|
31
33
|
|
|
32
34
|
if (selection.includes("all")) {
|
|
33
35
|
dimensionsSelect = dimensionOptions.map((dimension) => dimension.name);
|
|
34
36
|
}
|
|
35
37
|
|
|
36
|
-
dimensionsSelect?.forEach((dimension) =>
|
|
37
|
-
|
|
38
|
+
dimensionsSelect?.forEach((dimension) => {
|
|
39
|
+
values[dimension] = state.values[dimension];
|
|
40
|
+
});
|
|
41
|
+
setState((prev: IState) => ({ ...prev, dimensionsSelect, values }));
|
|
38
42
|
};
|
|
39
43
|
|
|
40
44
|
const setDimension = (value: Record<string, string>) => {
|
|
41
|
-
setState((
|
|
45
|
+
setState((prev: IState) => ({ ...prev, values: { ...prev.values, ...value } }));
|
|
42
46
|
};
|
|
43
47
|
|
|
44
48
|
const dimensionOptions = [
|
|
@@ -76,7 +80,9 @@ const StructuredDataAnalytics = (props: IAnalyticsFieldProps): JSX.Element => {
|
|
|
76
80
|
disabled={disabled}
|
|
77
81
|
floating
|
|
78
82
|
/>
|
|
79
|
-
{
|
|
83
|
+
{state.dimensionsSelect.length > 0 && (
|
|
84
|
+
<DimensionsSelection {...{ analytics, state, setDimension, disabled }} />
|
|
85
|
+
)}
|
|
80
86
|
</>
|
|
81
87
|
)}
|
|
82
88
|
</>
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import React from "react";
|
|
2
1
|
import { connect } from "react-redux";
|
|
3
2
|
|
|
4
|
-
import { IAnalytics, IRootState } from "@ax/types";
|
|
3
|
+
import type { IAnalytics, IRootState } from "@ax/types";
|
|
5
4
|
import { isEmptyArray } from "@ax/helpers";
|
|
6
5
|
|
|
7
6
|
import PageAnalytics from "./PageAnalytics";
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { IDimensionsGroup } from "@ax/types";
|
|
2
1
|
import { splitAndTrim } from "@ax/helpers";
|
|
2
|
+
import type { IDimensionsGroup } from "@ax/types";
|
|
3
3
|
|
|
4
4
|
const getTemplateDimensions = (groups: IDimensionsGroup[], template: string): string[] => {
|
|
5
5
|
const templateDimensionsGroups = groups?.filter((group) => group.templates?.includes(template));
|
|
6
|
-
const templateDimensions = templateDimensionsGroups?.
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
const templateDimensions = templateDimensionsGroups?.flatMap((group: IDimensionsGroup) =>
|
|
7
|
+
splitAndTrim(group.dimensions, ";"),
|
|
8
|
+
);
|
|
9
9
|
const uniqueTemplateDimensions = [...new Set(templateDimensions)];
|
|
10
10
|
return uniqueTemplateDimensions;
|
|
11
11
|
};
|