@griddo/ax 12.6.0 → 12.6.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/griddo-config/index.js +1 -0
- package/package.json +3 -4
- package/src/GlobalStore.tsx +91 -35
- package/src/__tests__/modules/ActivityLog/ActivityLog.uc.test.tsx +132 -0
- package/src/__tests__/modules/Analytics/Analytics.uc.test.tsx +168 -0
- package/src/__tests__/modules/GlobalSettings/Robots/Robots.test.tsx +110 -0
- package/src/__tests__/modules/GlobalSettings/Robots/Robots.uc.test.tsx +125 -0
- package/src/__tests__/modules/Redirects/Redirects.uc.test.tsx +164 -0
- package/src/__tests__/modules/Settings/Languages/Languages.uc.test.tsx +213 -0
- package/src/__tests__/modules/Settings/Social/Social.uc.test.tsx +171 -0
- package/src/__tests__/store/activityLog.test.ts +301 -0
- package/src/__tests__/store/analytics.test.ts +134 -0
- package/src/__tests__/store/domains.test.ts +107 -0
- package/src/__tests__/store/languages.test.ts +129 -0
- package/src/__tests__/store/persist.test.ts +47 -0
- package/src/__tests__/store/redirects.test.ts +313 -0
- package/src/__tests__/store/social.test.ts +165 -0
- package/src/components/MainWrapper/index.tsx +14 -2
- package/src/containers/ActivityLog/index.tsx +16 -3
- package/src/containers/ActivityLog/slice.ts +45 -0
- package/src/containers/ActivityLog/{actions.tsx → thunks.ts} +104 -89
- package/src/containers/Analytics/index.tsx +14 -3
- package/src/containers/Analytics/slice.ts +48 -0
- package/src/containers/Analytics/thunks.ts +103 -0
- package/src/containers/Domains/index.tsx +12 -3
- package/src/containers/Domains/slice.ts +37 -0
- package/src/containers/Domains/thunks.ts +60 -0
- package/src/containers/Redirects/constants.tsx +1 -17
- package/src/containers/Redirects/index.tsx +14 -3
- package/src/containers/Redirects/slice.ts +60 -0
- package/src/containers/Redirects/thunks.ts +196 -0
- package/src/containers/Settings/Languages/index.tsx +15 -3
- package/src/containers/Settings/Languages/slice.ts +48 -0
- package/src/containers/Settings/Languages/thunks.ts +83 -0
- package/src/containers/Settings/Social/index.tsx +11 -3
- package/src/containers/Settings/Social/slice.ts +40 -0
- package/src/containers/Settings/Social/thunks.ts +68 -0
- package/src/containers/Sites/actions.tsx +6 -2
- package/src/index.tsx +7 -6
- package/src/modules/ActivityLog/ItemLog/EventItem/index.tsx +13 -27
- package/src/modules/ActivityLog/ItemLogUser/UserItem/EventItem/index.tsx +13 -27
- package/src/modules/ActivityLog/index.tsx +22 -51
- package/src/modules/Analytics/index.tsx +33 -42
- package/src/modules/App/Routing/index.tsx +5 -4
- package/src/modules/FileDrive/index.tsx +1 -1
- package/src/modules/GlobalSettings/Robots/index.tsx +24 -47
- package/src/modules/MediaGallery/index.tsx +1 -1
- package/src/modules/Redirects/RedirectItem/index.tsx +9 -22
- package/src/modules/Redirects/RedirectPanel/index.tsx +13 -14
- package/src/modules/Redirects/index.tsx +26 -69
- package/src/modules/Settings/ContentTypes/DataPacks/index.tsx +4 -3
- package/src/modules/Settings/Languages/LanguagePanel/Form/ConnectedField/index.tsx +11 -18
- package/src/modules/Settings/Languages/LanguagePanel/Form/index.tsx +7 -9
- package/src/modules/Settings/Languages/LanguagePanel/index.tsx +38 -44
- package/src/modules/Settings/Languages/Table/Header/index.tsx +12 -19
- package/src/modules/Settings/Languages/Table/Item/index.tsx +21 -36
- package/src/modules/Settings/Languages/Table/index.tsx +6 -14
- package/src/modules/Settings/Languages/index.tsx +18 -30
- package/src/modules/Settings/SeoAnalyticsSettings/Analytics/index.tsx +42 -52
- package/src/modules/Settings/Social/index.tsx +17 -12
- package/src/modules/StructuredData/StructuredDataList/index.tsx +3 -2
- package/src/store/hooks.ts +37 -0
- package/src/store/index.ts +2 -0
- package/src/types/index.tsx +5 -6
- package/tsconfig.paths.json +1 -0
- package/src/containers/ActivityLog/constants.tsx +0 -6
- package/src/containers/ActivityLog/interfaces.tsx +0 -12
- package/src/containers/ActivityLog/reducer.tsx +0 -24
- package/src/containers/Analytics/actions.tsx +0 -109
- package/src/containers/Analytics/constants.tsx +0 -5
- package/src/containers/Analytics/interfaces.tsx +0 -9
- package/src/containers/Analytics/reducer.tsx +0 -28
- package/src/containers/Domains/actions.tsx +0 -58
- package/src/containers/Domains/constants.tsx +0 -5
- package/src/containers/Domains/interfaces.tsx +0 -9
- package/src/containers/Domains/reducer.tsx +0 -22
- package/src/containers/Redirects/actions.tsx +0 -190
- package/src/containers/Redirects/interfaces.tsx +0 -23
- package/src/containers/Redirects/reducer.tsx +0 -35
- package/src/containers/Settings/Languages/actions.tsx +0 -88
- package/src/containers/Settings/Languages/constants.tsx +0 -6
- package/src/containers/Settings/Languages/reducer.tsx +0 -31
- package/src/containers/Settings/Social/actions.tsx +0 -63
- package/src/containers/Settings/Social/constants.tsx +0 -3
- package/src/containers/Settings/Social/interfaces.tsx +0 -9
- package/src/containers/Settings/Social/reducer.tsx +0 -18
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type React from "react";
|
|
2
2
|
import { useState } from "react";
|
|
3
|
-
import { connect } from "react-redux";
|
|
4
3
|
|
|
5
4
|
import { RestoreModal } from "@ax/components";
|
|
6
5
|
import { activityLogActions } from "@ax/containers/ActivityLog";
|
|
@@ -8,9 +7,9 @@ import { navigationActions } from "@ax/containers/Navigation";
|
|
|
8
7
|
import { pageEditorActions } from "@ax/containers/PageEditor";
|
|
9
8
|
import { structuredDataActions } from "@ax/containers/StructuredData";
|
|
10
9
|
import { useModal } from "@ax/hooks";
|
|
11
|
-
import
|
|
10
|
+
import { useAppDispatch, useAppSelector } from "@ax/store";
|
|
12
11
|
|
|
13
|
-
import type { LogActivityDTO
|
|
12
|
+
import type { LogActivityDTO } from "@griddo/api-types";
|
|
14
13
|
|
|
15
14
|
import { eventKey } from "./../../../constants";
|
|
16
15
|
import DetailModal from "./../../../DetailModal";
|
|
@@ -19,7 +18,10 @@ import { getContentTypeSchemaVersion, getPageSchemaVersion } from "./../../../ut
|
|
|
19
18
|
import * as S from "./style";
|
|
20
19
|
|
|
21
20
|
const EventItem = (props: IEventItemProps) => {
|
|
22
|
-
const { item,
|
|
21
|
+
const { item, getLog } = props;
|
|
22
|
+
|
|
23
|
+
const dispatch = useAppDispatch();
|
|
24
|
+
const schemaVersion = useAppSelector((state) => state.structuredData.schemaVersion);
|
|
23
25
|
|
|
24
26
|
const { created, site, contentType, content, eventType } = item;
|
|
25
27
|
|
|
@@ -33,14 +35,14 @@ const EventItem = (props: IEventItemProps) => {
|
|
|
33
35
|
switch (type) {
|
|
34
36
|
case eventKey.DELETED_PAGE:
|
|
35
37
|
case eventKey.DELETED_CONTENT_TYPE_PAGE:
|
|
36
|
-
return await restorePage(id);
|
|
38
|
+
return await dispatch(pageEditorActions.restorePage(id));
|
|
37
39
|
case eventKey.DELETED_HEADER:
|
|
38
|
-
return await restoreNavigation(id, "header");
|
|
40
|
+
return await dispatch(navigationActions.restoreNavigation(id, "header"));
|
|
39
41
|
case eventKey.DELETED_FOOTER:
|
|
40
|
-
return await restoreNavigation(id, "footer");
|
|
42
|
+
return await dispatch(navigationActions.restoreNavigation(id, "footer"));
|
|
41
43
|
case eventKey.DELETED_CATEGORY:
|
|
42
44
|
case eventKey.DELETED_CONTENT_TYPE:
|
|
43
|
-
return await
|
|
45
|
+
return await dispatch(structuredDataActions.restoreStructuredDataContent(id));
|
|
44
46
|
default:
|
|
45
47
|
return false;
|
|
46
48
|
}
|
|
@@ -84,12 +86,12 @@ const EventItem = (props: IEventItemProps) => {
|
|
|
84
86
|
const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {
|
|
85
87
|
e.stopPropagation();
|
|
86
88
|
const siteID = site?.id || null;
|
|
87
|
-
goToLogContent(contentType, content, siteID);
|
|
89
|
+
dispatch(activityLogActions.goToLogContent({ contentType, content, site: siteID }));
|
|
88
90
|
};
|
|
89
91
|
|
|
90
92
|
const handleKeyDown = () => {
|
|
91
93
|
const siteID = site?.id || null;
|
|
92
|
-
goToLogContent(contentType, content, siteID);
|
|
94
|
+
dispatch(activityLogActions.goToLogContent({ contentType, content, site: siteID }));
|
|
93
95
|
};
|
|
94
96
|
|
|
95
97
|
return (
|
|
@@ -151,23 +153,7 @@ const EventItem = (props: IEventItemProps) => {
|
|
|
151
153
|
|
|
152
154
|
interface IEventItemProps {
|
|
153
155
|
item: LogActivityDTO;
|
|
154
|
-
schemaVersion: string;
|
|
155
|
-
restorePage(id: number): Promise<boolean>;
|
|
156
|
-
restoreNavigation(navID: number, type: string): Promise<boolean>;
|
|
157
|
-
restoreStructuredData(dataID: number): Promise<boolean>;
|
|
158
|
-
goToLogContent(contentType: LogContentTypeDTO | null, content: LogContentDTO | null, site: number | null): void;
|
|
159
156
|
getLog(): void;
|
|
160
157
|
}
|
|
161
158
|
|
|
162
|
-
|
|
163
|
-
schemaVersion: state.structuredData.schemaVersion,
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
const mapDispatchToProps = {
|
|
167
|
-
restorePage: pageEditorActions.restorePage,
|
|
168
|
-
restoreNavigation: navigationActions.restoreNavigation,
|
|
169
|
-
restoreStructuredData: structuredDataActions.restoreStructuredDataContent,
|
|
170
|
-
goToLogContent: activityLogActions.goToLogContent,
|
|
171
|
-
};
|
|
172
|
-
|
|
173
|
-
export default connect(mapStateToProps, mapDispatchToProps)(EventItem);
|
|
159
|
+
export default EventItem;
|
|
@@ -1,33 +1,27 @@
|
|
|
1
1
|
import React, { useCallback, useEffect, useRef, useState } from "react";
|
|
2
|
-
import { connect } from "react-redux";
|
|
3
|
-
import { format, subDays } from "date-fns";
|
|
4
2
|
|
|
5
|
-
import type { LogActivityExportRequest, LogActivityPaginationRequest } from "@griddo/api-types";
|
|
6
|
-
import type { ILogItemsByDay, ILogItemsByUser, IQueryValue, IRootState, IStructuredData } from "@ax/types";
|
|
7
3
|
import { EmptyState, ErrorToast, FilterTagsBar, MainWrapper, SearchTagsBar, Select, TableList } from "@ax/components";
|
|
8
4
|
import { activityLogActions } from "@ax/containers/ActivityLog";
|
|
9
5
|
import { structuredDataActions } from "@ax/containers/StructuredData";
|
|
10
6
|
import { useModal } from "@ax/hooks";
|
|
7
|
+
import { useAppDispatch, useAppSelector } from "@ax/store";
|
|
8
|
+
import type { ILogItemsByDay, ILogItemsByUser, IQueryValue } from "@ax/types";
|
|
11
9
|
|
|
10
|
+
import type { LogActivityExportRequest, LogActivityPaginationRequest } from "@griddo/api-types";
|
|
11
|
+
import { format, subDays } from "date-fns";
|
|
12
|
+
|
|
13
|
+
import DownloadModal from "./DownloadModal";
|
|
12
14
|
import { useFilterQuery } from "./hooks";
|
|
13
|
-
import TableHeader from "./TableHeader";
|
|
14
15
|
import ItemLog from "./ItemLog";
|
|
15
16
|
import ItemLogUser from "./ItemLogUser";
|
|
16
|
-
import
|
|
17
|
+
import TableHeader from "./TableHeader";
|
|
17
18
|
|
|
18
19
|
import * as S from "./style";
|
|
19
20
|
|
|
20
|
-
const ActivityLog = (
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
setListMode,
|
|
25
|
-
getActivityLog,
|
|
26
|
-
getActivityLogByUser,
|
|
27
|
-
downloadActivityLog,
|
|
28
|
-
getStructuredData,
|
|
29
|
-
setCurrentData,
|
|
30
|
-
} = props;
|
|
21
|
+
const ActivityLog = () => {
|
|
22
|
+
const dispatch = useAppDispatch();
|
|
23
|
+
const activityLog = useAppSelector((state) => state.activityLog.activityLog);
|
|
24
|
+
const listMode = useAppSelector((state) => state.activityLog.listMode);
|
|
31
25
|
|
|
32
26
|
const itemsPerPage = 100;
|
|
33
27
|
const firstPage = 1;
|
|
@@ -68,13 +62,14 @@ const ActivityLog = (props: IActivityLogProps) => {
|
|
|
68
62
|
const handleGetLog = async () => {
|
|
69
63
|
const params = getParams();
|
|
70
64
|
if (isModeUser) {
|
|
71
|
-
await getActivityLogByUser(params);
|
|
65
|
+
await dispatch(activityLogActions.getActivityLogByUser(params));
|
|
72
66
|
} else {
|
|
73
|
-
await getActivityLog(params);
|
|
67
|
+
await dispatch(activityLogActions.getActivityLog(params));
|
|
74
68
|
}
|
|
75
69
|
};
|
|
76
70
|
|
|
77
|
-
const handleUpdateStructuredDate = async () =>
|
|
71
|
+
const handleUpdateStructuredDate = async () =>
|
|
72
|
+
await dispatch(structuredDataActions.getStructuredData(null, null, false));
|
|
78
73
|
|
|
79
74
|
// biome-ignore lint/correctness/useExhaustiveDependencies: TODO: fix this
|
|
80
75
|
useEffect(() => {
|
|
@@ -84,7 +79,7 @@ const ActivityLog = (props: IActivityLogProps) => {
|
|
|
84
79
|
// biome-ignore lint/correctness/useExhaustiveDependencies: TODO: fix this
|
|
85
80
|
useEffect(() => {
|
|
86
81
|
handleUpdateStructuredDate();
|
|
87
|
-
setCurrentData(null);
|
|
82
|
+
dispatch(structuredDataActions.setCurrentData(null));
|
|
88
83
|
}, []);
|
|
89
84
|
|
|
90
85
|
const onScroll = (e: any) => setIsScrolling(e.target.scrollTop > 0);
|
|
@@ -92,11 +87,11 @@ const ActivityLog = (props: IActivityLogProps) => {
|
|
|
92
87
|
const handleSelectChange = async (value: string) => {
|
|
93
88
|
const params = getParams();
|
|
94
89
|
if (value === "user") {
|
|
95
|
-
await getActivityLogByUser({ ...params, page: firstPage });
|
|
90
|
+
await dispatch(activityLogActions.getActivityLogByUser({ ...params, page: firstPage }));
|
|
96
91
|
} else {
|
|
97
|
-
await getActivityLog({ ...params, page: firstPage });
|
|
92
|
+
await dispatch(activityLogActions.getActivityLog({ ...params, page: firstPage }));
|
|
98
93
|
}
|
|
99
|
-
setListMode(value);
|
|
94
|
+
dispatch(activityLogActions.setListMode(value));
|
|
100
95
|
};
|
|
101
96
|
|
|
102
97
|
const sortItems = async (isAscending: boolean) => {
|
|
@@ -139,7 +134,7 @@ const ActivityLog = (props: IActivityLogProps) => {
|
|
|
139
134
|
format: [downloadForm.format],
|
|
140
135
|
};
|
|
141
136
|
|
|
142
|
-
await downloadActivityLog(data);
|
|
137
|
+
await dispatch(activityLogActions.downloadActivityLog(data));
|
|
143
138
|
|
|
144
139
|
toggleDownloadModal();
|
|
145
140
|
setDownloadForm(initialState);
|
|
@@ -211,6 +206,7 @@ const ActivityLog = (props: IActivityLogProps) => {
|
|
|
211
206
|
return (
|
|
212
207
|
<MainWrapper
|
|
213
208
|
title="Logs"
|
|
209
|
+
screen="activity-log"
|
|
214
210
|
rightButton={rightButtonProps}
|
|
215
211
|
rightLineButton={rightLineButtonProps}
|
|
216
212
|
searchAction={handleSearch}
|
|
@@ -294,29 +290,4 @@ export interface IDownloadFormState {
|
|
|
294
290
|
endDate: string | null;
|
|
295
291
|
}
|
|
296
292
|
|
|
297
|
-
|
|
298
|
-
activityLog: ILogItemsByDay | ILogItemsByUser;
|
|
299
|
-
listMode: string;
|
|
300
|
-
getActivityLog(params: LogActivityPaginationRequest): Promise<void>;
|
|
301
|
-
getActivityLogByUser(params: LogActivityPaginationRequest): Promise<void>;
|
|
302
|
-
setListMode(listMode: string): void;
|
|
303
|
-
downloadActivityLog(data: LogActivityExportRequest): Promise<void>;
|
|
304
|
-
getStructuredData(token: string | null, siteID?: number | null, hasLoading?: boolean): Promise<void>;
|
|
305
|
-
setCurrentData(currentStructuredData: IStructuredData | null): void;
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
const mapStateToProps = (state: IRootState) => ({
|
|
309
|
-
activityLog: state.activityLog.activityLog,
|
|
310
|
-
listMode: state.activityLog.listMode,
|
|
311
|
-
});
|
|
312
|
-
|
|
313
|
-
const mapDispatchToProps = {
|
|
314
|
-
getActivityLog: activityLogActions.getActivityLog,
|
|
315
|
-
getActivityLogByUser: activityLogActions.getActivityLogByUser,
|
|
316
|
-
setListMode: activityLogActions.setListMode,
|
|
317
|
-
downloadActivityLog: activityLogActions.downloadActivityLog,
|
|
318
|
-
getStructuredData: structuredDataActions.getStructuredData,
|
|
319
|
-
setCurrentData: structuredDataActions.setCurrentData,
|
|
320
|
-
};
|
|
321
|
-
|
|
322
|
-
export default connect(mapStateToProps, mapDispatchToProps)(ActivityLog);
|
|
293
|
+
export default ActivityLog;
|
|
@@ -1,22 +1,25 @@
|
|
|
1
|
-
import React, { useEffect, useState } from "react";
|
|
2
|
-
import { connect } from "react-redux";
|
|
1
|
+
import React, { memo, useEffect, useState } from "react";
|
|
3
2
|
|
|
4
|
-
import
|
|
5
|
-
import { appActions } from "@ax/containers/App";
|
|
3
|
+
import { ErrorToast, FieldsBehavior, Loading, MainWrapper } from "@ax/components";
|
|
6
4
|
import { analyticsActions } from "@ax/containers/Analytics";
|
|
7
|
-
import {
|
|
5
|
+
import { appActions } from "@ax/containers/App";
|
|
8
6
|
import { RouteLeavingGuard } from "@ax/guards";
|
|
9
|
-
import { useIsDirty } from "@ax/hooks";
|
|
10
|
-
import {
|
|
7
|
+
import { useIsDirty, useModal } from "@ax/hooks";
|
|
8
|
+
import { useAppDispatch, useAppSelector } from "@ax/store";
|
|
9
|
+
import type { IDimension, IDimensionsGroup } from "@ax/types";
|
|
11
10
|
|
|
12
11
|
import DimensionItem from "./DimensionItem";
|
|
13
12
|
import DimensionPanel from "./DimensionPanel";
|
|
14
13
|
import GroupItem from "./GroupItem";
|
|
15
14
|
import GroupPanel from "./GroupPanel";
|
|
15
|
+
|
|
16
16
|
import * as S from "./style";
|
|
17
17
|
|
|
18
|
-
const Analytics = (
|
|
19
|
-
const
|
|
18
|
+
const Analytics = (): JSX.Element => {
|
|
19
|
+
const dispatch = useAppDispatch();
|
|
20
|
+
const isSaving = useAppSelector((state) => state.app.isSaving);
|
|
21
|
+
const isLoading = useAppSelector((state) => state.app.isLoading);
|
|
22
|
+
const analytics = useAppSelector((state) => state.analytics);
|
|
20
23
|
|
|
21
24
|
const [analyticsState, setAnalyticsState] = useState(analytics);
|
|
22
25
|
const { isDirty, resetDirty } = useIsDirty(analyticsState);
|
|
@@ -31,16 +34,27 @@ const Analytics = (props: IProps): JSX.Element => {
|
|
|
31
34
|
|
|
32
35
|
// biome-ignore lint/correctness/useExhaustiveDependencies: TODO: fix this
|
|
33
36
|
useEffect(() => {
|
|
34
|
-
|
|
35
|
-
|
|
37
|
+
// `null` is the global scope, which the API spells "global".
|
|
38
|
+
dispatch(analyticsActions.getAnalytics(null));
|
|
36
39
|
}, []);
|
|
37
40
|
|
|
41
|
+
// `resetDirty()`, not `setIsDirty(false)`: it also moves useIsDirty's baseline to the
|
|
42
|
+
// state being hydrated here. useIsDirty snapshots its baseline during render, so on
|
|
43
|
+
// the first visit — nothing persisted for this scope — the store is still the initial
|
|
44
|
+
// state and the empty→loaded hop reads as an edit: Save enabled and the leave guard
|
|
45
|
+
// armed before the user touches anything, against this screen's own AC6. Same mine as
|
|
46
|
+
// Settings/Social (docs/RTK-MIGRATION.md §5).
|
|
38
47
|
useEffect(() => {
|
|
39
48
|
setAnalyticsState(analytics);
|
|
40
|
-
|
|
49
|
+
resetDirty();
|
|
50
|
+
}, [analytics, resetDirty]);
|
|
41
51
|
|
|
42
52
|
const handleSave = async () => {
|
|
43
|
-
|
|
53
|
+
// `.unwrap()` is what hands over handleRequest's boolean: the dispatch itself
|
|
54
|
+
// resolves to the fulfilled action, which would be truthy even on failure.
|
|
55
|
+
const isSaved = await dispatch(
|
|
56
|
+
analyticsActions.updateAnalytics({ analytics: analyticsState, siteId: null }),
|
|
57
|
+
).unwrap();
|
|
44
58
|
if (isSaved) resetDirty();
|
|
45
59
|
};
|
|
46
60
|
|
|
@@ -109,7 +123,7 @@ const Analytics = (props: IProps): JSX.Element => {
|
|
|
109
123
|
changeGroups(updatedGroups);
|
|
110
124
|
};
|
|
111
125
|
|
|
112
|
-
const setRoute = (path: string) => setHistoryPush(path);
|
|
126
|
+
const setRoute = (path: string) => dispatch(appActions.setHistoryPush(path));
|
|
113
127
|
const modalText = (
|
|
114
128
|
<>
|
|
115
129
|
Some analytics <strong>are not saved</strong>.{" "}
|
|
@@ -123,7 +137,7 @@ const Analytics = (props: IProps): JSX.Element => {
|
|
|
123
137
|
return (
|
|
124
138
|
<>
|
|
125
139
|
<RouteLeavingGuard when={isDirty} action={setRoute} text={modalText} />
|
|
126
|
-
<MainWrapper backLink={false} title="Analytics Settings" rightButton={rightButtonProps}>
|
|
140
|
+
<MainWrapper backLink={false} title="Analytics Settings" rightButton={rightButtonProps} screen="analytics-global">
|
|
127
141
|
<ErrorToast />
|
|
128
142
|
<S.Wrapper>
|
|
129
143
|
<S.FormWrapper>
|
|
@@ -186,30 +200,7 @@ const Analytics = (props: IProps): JSX.Element => {
|
|
|
186
200
|
);
|
|
187
201
|
};
|
|
188
202
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
const mapDispatchToProps = {
|
|
196
|
-
setHistoryPush: appActions.setHistoryPush,
|
|
197
|
-
getAnalytics: analyticsActions.getAnalytics,
|
|
198
|
-
updateAnalytics: analyticsActions.updateAnalytics,
|
|
199
|
-
};
|
|
200
|
-
|
|
201
|
-
interface IAnalyticsProps {
|
|
202
|
-
isSaving: boolean;
|
|
203
|
-
isLoading: boolean;
|
|
204
|
-
analytics: IAnalytics;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
interface IDispatchProps {
|
|
208
|
-
getAnalytics(siteId?: number | null): Promise<void>;
|
|
209
|
-
setHistoryPush(path: string, isEditor?: boolean): void;
|
|
210
|
-
updateAnalytics(analyticsState: IAnalytics, siteId?: number | null): Promise<boolean>;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
type IProps = IAnalyticsProps & IDispatchProps;
|
|
214
|
-
|
|
215
|
-
export default connect(mapStateToProps, mapDispatchToProps)(Analytics);
|
|
203
|
+
// This screen is the global scope of the analytics settings: it reads everything
|
|
204
|
+
// from the store and takes no props. `connect` memoised it implicitly; `memo` keeps
|
|
205
|
+
// that now it is gone.
|
|
206
|
+
export default memo(Analytics);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { useEffect } from "react";
|
|
2
2
|
import { connect } from "react-redux";
|
|
3
|
-
import { Switch, Route, matchPath } from "react-router-dom";
|
|
3
|
+
import { Switch, Route, matchPath, useLocation } from "react-router-dom";
|
|
4
4
|
|
|
5
5
|
import { ErrorGuard } from "@ax/guards";
|
|
6
6
|
import type { IRootState, IUser } from "@ax/types";
|
|
@@ -17,7 +17,10 @@ import Logout from "./Logout";
|
|
|
17
17
|
import * as S from "./style";
|
|
18
18
|
|
|
19
19
|
const Routing = (props: IProps) => {
|
|
20
|
-
const {
|
|
20
|
+
const { token, currentUser, globalSettings, setHistoryPush, logout } = props;
|
|
21
|
+
|
|
22
|
+
// Was `state.router.location.pathname` from connected-react-router's router slice.
|
|
23
|
+
const { pathname: path } = useLocation();
|
|
21
24
|
|
|
22
25
|
const { useForms } = globalSettings;
|
|
23
26
|
|
|
@@ -112,7 +115,6 @@ const Routing = (props: IProps) => {
|
|
|
112
115
|
};
|
|
113
116
|
|
|
114
117
|
const mapStateToProps = (state: IRootState) => ({
|
|
115
|
-
path: state.router.location.pathname,
|
|
116
118
|
token: state.app.token,
|
|
117
119
|
currentUser: state.users.currentUser,
|
|
118
120
|
globalSettings: state.app.globalSettings,
|
|
@@ -124,7 +126,6 @@ interface IDispatchProps {
|
|
|
124
126
|
}
|
|
125
127
|
|
|
126
128
|
interface IStateProps {
|
|
127
|
-
path?: string;
|
|
128
129
|
token: string;
|
|
129
130
|
currentUser: IUser | null;
|
|
130
131
|
globalSettings: IGlobalSettings;
|
|
@@ -605,7 +605,7 @@ const FileDrive = (props: IProps) => {
|
|
|
605
605
|
);
|
|
606
606
|
|
|
607
607
|
return (
|
|
608
|
-
<MainWrapper backLink={false} title="File Drive Manager" rightButton={rightButtonProps}>
|
|
608
|
+
<MainWrapper backLink={false} title="File Drive Manager" rightButton={rightButtonProps} screen="file-drive">
|
|
609
609
|
<S.Wrapper ref={wrapperRef}>
|
|
610
610
|
<S.FolderPanel
|
|
611
611
|
isOpen={isPanelOpen}
|
|
@@ -1,35 +1,31 @@
|
|
|
1
|
-
import { useEffect, useState } from "react";
|
|
2
|
-
import { connect } from "react-redux";
|
|
1
|
+
import { memo, useEffect, useState } from "react";
|
|
3
2
|
|
|
4
3
|
import { ErrorToast, Loading, MainWrapper, Nav } from "@ax/components";
|
|
5
4
|
import { appActions } from "@ax/containers/App";
|
|
6
5
|
import { domainsActions } from "@ax/containers/Domains";
|
|
7
6
|
import { RouteLeavingGuard } from "@ax/guards";
|
|
8
7
|
import { useIsDirty } from "@ax/hooks";
|
|
9
|
-
import
|
|
8
|
+
import { useAppDispatch, useAppSelector } from "@ax/store";
|
|
9
|
+
import type { IDomainRobot, INavItem } from "@ax/types";
|
|
10
10
|
|
|
11
11
|
import Item from "./Item";
|
|
12
12
|
|
|
13
13
|
import * as S from "./style";
|
|
14
14
|
|
|
15
15
|
const Robots = (props: IProps): JSX.Element => {
|
|
16
|
-
const {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
getDomainsRobots,
|
|
23
|
-
setHistoryPush,
|
|
24
|
-
updateDomainRobots,
|
|
25
|
-
} = props;
|
|
16
|
+
const { navItems, currentNavItem } = props;
|
|
17
|
+
|
|
18
|
+
const dispatch = useAppDispatch();
|
|
19
|
+
const isSaving = useAppSelector((state) => state.app.isSaving);
|
|
20
|
+
const isLoading = useAppSelector((state) => state.app.isLoading);
|
|
21
|
+
const robots = useAppSelector((state) => state.domains.robots);
|
|
26
22
|
|
|
27
23
|
const [robotItems, setRobotItems] = useState(robots);
|
|
28
24
|
const { isDirty, setIsDirty, resetDirty } = useIsDirty(robotItems);
|
|
29
25
|
|
|
30
26
|
// biome-ignore lint/correctness/useExhaustiveDependencies: TODO: fix this
|
|
31
27
|
useEffect(() => {
|
|
32
|
-
getDomainsRobots();
|
|
28
|
+
dispatch(domainsActions.getDomainsRobots());
|
|
33
29
|
resetDirty();
|
|
34
30
|
}, []);
|
|
35
31
|
|
|
@@ -38,7 +34,7 @@ const Robots = (props: IProps): JSX.Element => {
|
|
|
38
34
|
}, [robots]);
|
|
39
35
|
|
|
40
36
|
const handleSave = async () => {
|
|
41
|
-
const isSaved = await
|
|
37
|
+
const isSaved = await dispatch(domainsActions.updateDomainsRobots(robotItems)).unwrap();
|
|
42
38
|
if (isSaved) {
|
|
43
39
|
setIsDirty(false);
|
|
44
40
|
}
|
|
@@ -51,22 +47,23 @@ const Robots = (props: IProps): JSX.Element => {
|
|
|
51
47
|
};
|
|
52
48
|
|
|
53
49
|
const handleMenuClick = (path: string) => {
|
|
54
|
-
setHistoryPush(path);
|
|
50
|
+
dispatch(appActions.setHistoryPush(path));
|
|
55
51
|
};
|
|
56
52
|
|
|
57
53
|
const mapItemList = (items: IDomainRobot[]) =>
|
|
58
54
|
Array.isArray(items) &&
|
|
59
55
|
items.map((item: IDomainRobot, i: number) => {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
56
|
+
// Replaces the item instead of assigning onto it: the list comes from the
|
|
57
|
+
// store, so the previous `newItems[i].content = …` on a shallow copy was
|
|
58
|
+
// mutating state — and now that the slice runs through Immer, the object
|
|
59
|
+
// is frozen and that assignment would throw.
|
|
60
|
+
const handleSetItem = (newContent: string) =>
|
|
61
|
+
setRobotItems((current) => current.map((it, index) => (index === i ? { ...it, content: newContent } : it)));
|
|
65
62
|
|
|
66
63
|
return <Item key={`${item.path}${i}`} item={item} setItemContent={handleSetItem} />;
|
|
67
64
|
});
|
|
68
65
|
|
|
69
|
-
const setRoute = (path: string) => setHistoryPush(path);
|
|
66
|
+
const setRoute = (path: string) => dispatch(appActions.setHistoryPush(path));
|
|
70
67
|
const modalText = (
|
|
71
68
|
<>
|
|
72
69
|
Some robots <strong>are not saved</strong>.{" "}
|
|
@@ -76,7 +73,7 @@ const Robots = (props: IProps): JSX.Element => {
|
|
|
76
73
|
return (
|
|
77
74
|
<>
|
|
78
75
|
<RouteLeavingGuard when={isDirty} action={setRoute} text={modalText} />
|
|
79
|
-
<MainWrapper backLink={false} title="SEO Settings" rightButton={rightButtonProps}>
|
|
76
|
+
<MainWrapper backLink={false} title="SEO Settings" rightButton={rightButtonProps} screen="robots">
|
|
80
77
|
<S.Wrapper>
|
|
81
78
|
<Nav current={currentNavItem} items={navItems} onClick={handleMenuClick} />
|
|
82
79
|
<S.ContentWrapper>
|
|
@@ -93,31 +90,11 @@ const Robots = (props: IProps): JSX.Element => {
|
|
|
93
90
|
);
|
|
94
91
|
};
|
|
95
92
|
|
|
96
|
-
|
|
97
|
-
isSaving: state.app.isSaving,
|
|
98
|
-
isLoading: state.app.isLoading,
|
|
99
|
-
robots: state.domains.robots,
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
const mapDispatchToProps = {
|
|
103
|
-
setHistoryPush: appActions.setHistoryPush,
|
|
104
|
-
getDomainsRobots: domainsActions.getDomainsRobots,
|
|
105
|
-
updateDomainRobots: domainsActions.updateDomainsRobots,
|
|
106
|
-
};
|
|
107
|
-
interface IRobotsProps {
|
|
108
|
-
isSaving: boolean;
|
|
109
|
-
isLoading: boolean;
|
|
93
|
+
interface IProps {
|
|
110
94
|
navItems: INavItem[];
|
|
111
95
|
currentNavItem: INavItem;
|
|
112
|
-
robots: IDomainRobot[];
|
|
113
96
|
}
|
|
114
97
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
updateDomainRobots(robots: IDomainRobot[]): Promise<boolean>;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
type IProps = IRobotsProps & IDispatchProps;
|
|
122
|
-
|
|
123
|
-
export default connect(mapStateToProps, mapDispatchToProps)(Robots);
|
|
98
|
+
// `connect` memoised this screen implicitly; `memo` keeps that now that its props
|
|
99
|
+
// come from the parent instead of the store.
|
|
100
|
+
export default memo(Robots);
|
|
@@ -623,7 +623,7 @@ const MediaGallery = (props: IProps) => {
|
|
|
623
623
|
);
|
|
624
624
|
|
|
625
625
|
return (
|
|
626
|
-
<MainWrapper backLink={false} title="Media Gallery" rightButton={rightButtonProps}>
|
|
626
|
+
<MainWrapper backLink={false} title="Media Gallery" rightButton={rightButtonProps} screen="gallery">
|
|
627
627
|
<S.Wrapper ref={wrapperRef}>
|
|
628
628
|
<S.FolderPanel
|
|
629
629
|
isOpen={isPanelOpen}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { useState } from "react";
|
|
2
|
-
import { connect } from "react-redux";
|
|
3
2
|
|
|
4
3
|
import { CheckField, ContextMenu, ElementsTooltip } from "@ax/components";
|
|
5
4
|
import { redirectsActions } from "@ax/containers/Redirects";
|
|
6
5
|
import { useContextMenu, useModals } from "@ax/hooks";
|
|
7
|
-
import
|
|
6
|
+
import { useAppDispatch, useAppSelector } from "@ax/store";
|
|
7
|
+
import type { ICheck, IRedirect } from "@ax/types";
|
|
8
8
|
|
|
9
9
|
import { format } from "date-fns";
|
|
10
10
|
|
|
@@ -13,12 +13,11 @@ import RedirectPanel from "../RedirectPanel";
|
|
|
13
13
|
|
|
14
14
|
import * as S from "./style";
|
|
15
15
|
|
|
16
|
-
const RedirectItem = (props:
|
|
16
|
+
const RedirectItem = (props: IProps): JSX.Element => {
|
|
17
17
|
const {
|
|
18
18
|
redirect,
|
|
19
19
|
isSelected,
|
|
20
20
|
onChange,
|
|
21
|
-
deleteRedirect,
|
|
22
21
|
toggleToast,
|
|
23
22
|
setFormValues,
|
|
24
23
|
formValues,
|
|
@@ -26,9 +25,10 @@ const RedirectItem = (props: IRedirectItemProps): JSX.Element => {
|
|
|
26
25
|
currentFilter,
|
|
27
26
|
isSiteItem,
|
|
28
27
|
hoverCheck,
|
|
29
|
-
isSaving,
|
|
30
28
|
} = props;
|
|
31
29
|
|
|
30
|
+
const dispatch = useAppDispatch();
|
|
31
|
+
const isSaving = useAppSelector((state) => state.app.isSaving);
|
|
32
32
|
const { isOpen, toggleModal } = useModals(["edit", "delete"]);
|
|
33
33
|
const { contextMenu, handleContextMenu, closeContextMenu } = useContextMenu();
|
|
34
34
|
const [isOpenedSecond, setIsOpenedSecond] = useState(false);
|
|
@@ -47,7 +47,9 @@ const RedirectItem = (props: IRedirectItemProps): JSX.Element => {
|
|
|
47
47
|
const removeItem = async () => {
|
|
48
48
|
try {
|
|
49
49
|
if (redirect.id) {
|
|
50
|
-
const deleted = await
|
|
50
|
+
const deleted = await dispatch(
|
|
51
|
+
redirectsActions.deleteRedirect({ redirectID: redirect.id, filter: currentFilter }),
|
|
52
|
+
).unwrap();
|
|
51
53
|
if (deleted) {
|
|
52
54
|
toggleToast();
|
|
53
55
|
}
|
|
@@ -148,21 +150,6 @@ interface IProps {
|
|
|
148
150
|
currentFilter: string;
|
|
149
151
|
isSiteItem: boolean;
|
|
150
152
|
hoverCheck: boolean;
|
|
151
|
-
isSaving: boolean;
|
|
152
153
|
}
|
|
153
154
|
|
|
154
|
-
|
|
155
|
-
deleteRedirect(redirectID: number, filter?: string): Promise<boolean>;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
type IRedirectItemProps = IProps & IDispatchProps;
|
|
159
|
-
|
|
160
|
-
const mapStateToProps = (state: IRootState) => ({
|
|
161
|
-
isSaving: state.app.isSaving,
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
const mapDispatchToProps = {
|
|
165
|
-
deleteRedirect: redirectsActions.deleteRedirect,
|
|
166
|
-
};
|
|
167
|
-
|
|
168
|
-
export default connect(mapStateToProps, mapDispatchToProps)(RedirectItem);
|
|
155
|
+
export default RedirectItem;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { connect } from "react-redux";
|
|
3
2
|
|
|
4
3
|
import type { IRedirect } from "@ax/types";
|
|
5
4
|
import { Button, FieldsBehavior, FloatingPanel } from "@ax/components";
|
|
6
5
|
import { redirectsActions } from "@ax/containers/Redirects";
|
|
6
|
+
import { useAppDispatch } from "@ax/store";
|
|
7
7
|
|
|
8
8
|
import * as S from "./style";
|
|
9
9
|
|
|
@@ -15,12 +15,13 @@ const RedirectPanel = (props: IProps): JSX.Element => {
|
|
|
15
15
|
isOpenedSecond,
|
|
16
16
|
toggleSecondaryPanel,
|
|
17
17
|
addRedirect,
|
|
18
|
-
updateRedirect,
|
|
19
18
|
formValues,
|
|
20
19
|
setFormValues,
|
|
21
20
|
currentFilter,
|
|
22
21
|
} = props;
|
|
23
22
|
|
|
23
|
+
const dispatch = useAppDispatch();
|
|
24
|
+
|
|
24
25
|
const handleOldUrl = (newValue: string) => setFormValues({ ...formValues, from: newValue });
|
|
25
26
|
|
|
26
27
|
const handleNewUrl = (newValue: any) => {
|
|
@@ -34,7 +35,14 @@ const RedirectPanel = (props: IProps): JSX.Element => {
|
|
|
34
35
|
|
|
35
36
|
const editItemAction = async () => {
|
|
36
37
|
const toPage = formValues.to.pageId ? formValues.to.pageId : formValues.to.url;
|
|
37
|
-
formValues.id &&
|
|
38
|
+
formValues.id &&
|
|
39
|
+
(await dispatch(
|
|
40
|
+
redirectsActions.updateRedirect({
|
|
41
|
+
redirect: { from: formValues.from, to: toPage },
|
|
42
|
+
redirectID: formValues.id,
|
|
43
|
+
filter: currentFilter,
|
|
44
|
+
}),
|
|
45
|
+
));
|
|
38
46
|
toggleModal();
|
|
39
47
|
};
|
|
40
48
|
|
|
@@ -97,10 +105,7 @@ const RedirectPanel = (props: IProps): JSX.Element => {
|
|
|
97
105
|
);
|
|
98
106
|
};
|
|
99
107
|
|
|
100
|
-
|
|
101
|
-
updateRedirect: redirectsActions.updateRedirect,
|
|
102
|
-
};
|
|
103
|
-
interface ICategoryPanelProps {
|
|
108
|
+
interface IProps {
|
|
104
109
|
isOpen: boolean;
|
|
105
110
|
isOpenedSecond: boolean;
|
|
106
111
|
toggleSecondaryPanel(): any;
|
|
@@ -109,13 +114,7 @@ interface ICategoryPanelProps {
|
|
|
109
114
|
formValues: IRedirect;
|
|
110
115
|
setFormValues(redirect: IRedirect): void;
|
|
111
116
|
currentFilter: string;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
interface IDispatchProps {
|
|
115
117
|
addRedirect(force?: boolean): void;
|
|
116
|
-
updateRedirect(redirect: { from: string; to: string | number }, redirectID: number, filter?: string): Promise<void>;
|
|
117
118
|
}
|
|
118
119
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
export default connect(null, mapDispatchToProps)(RedirectPanel);
|
|
120
|
+
export default RedirectPanel;
|