@griddo/ax 11.7.13 → 11.8.0-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 +3 -2
- package/src/GlobalStore.tsx +3 -0
- package/src/api/index.tsx +4 -0
- package/src/api/logs.tsx +97 -0
- package/src/api/navigation.tsx +1 -1
- package/src/api/pages.tsx +1 -1
- package/src/api/schemas.tsx +18 -0
- package/src/api/users.tsx +17 -0
- package/src/components/ConfigPanel/Form/ConnectedField/NavConnectedField/index.tsx +3 -2
- package/src/components/ConfigPanel/Form/index.tsx +3 -1
- package/src/components/ConfigPanel/index.tsx +3 -0
- package/src/components/Fields/SummaryButton/index.tsx +6 -4
- package/src/components/Fields/TimeField/style.tsx +0 -1
- package/src/components/Fields/TranslateButton/index.tsx +3 -0
- package/src/components/FloatingMenu/index.tsx +25 -1
- package/src/components/FloatingMenu/style.tsx +3 -2
- package/src/components/LanguageMenu/index.tsx +1 -1
- package/src/components/MainWrapper/AppBar/index.tsx +4 -3
- package/src/components/RestoreModal/index.tsx +51 -0
- package/src/components/RestoreModal/style.tsx +7 -0
- package/src/components/SearchField/index.tsx +1 -1
- package/src/components/SearchField/style.tsx +4 -4
- package/src/components/TableFilters/CheckGroupFilter/index.tsx +42 -5
- package/src/components/TableFilters/CheckGroupFilter/style.tsx +8 -1
- package/src/components/TableFilters/SiteFilter/index.tsx +26 -57
- package/src/components/Tag/index.tsx +6 -3
- package/src/components/Tag/style.tsx +2 -2
- package/src/components/index.tsx +2 -0
- package/src/containers/ActivityLog/actions.tsx +262 -0
- package/src/containers/ActivityLog/constants.tsx +6 -0
- package/src/containers/ActivityLog/index.tsx +4 -0
- package/src/containers/ActivityLog/interfaces.tsx +12 -0
- package/src/containers/ActivityLog/reducer.tsx +25 -0
- package/src/containers/Navigation/Defaults/actions.tsx +4 -3
- package/src/containers/StructuredData/actions.tsx +7 -4
- package/src/containers/StructuredData/interfaces.tsx +2 -8
- package/src/containers/StructuredData/reducer.tsx +2 -8
- package/src/containers/Users/actions.tsx +22 -19
- package/src/modules/ActivityLog/DetailModal/index.tsx +108 -0
- package/src/modules/ActivityLog/DetailModal/style.tsx +52 -0
- package/src/modules/ActivityLog/DownloadModal/index.tsx +104 -0
- package/src/modules/ActivityLog/DownloadModal/style.tsx +12 -0
- package/src/modules/ActivityLog/ItemGroup/index.tsx +27 -0
- package/src/modules/ActivityLog/ItemGroup/style.tsx +39 -0
- package/src/modules/ActivityLog/ItemLog/EventItem/index.tsx +167 -0
- package/src/modules/ActivityLog/ItemLog/EventItem/style.tsx +79 -0
- package/src/modules/ActivityLog/ItemLog/index.tsx +24 -0
- package/src/modules/ActivityLog/ItemLogUser/UserItem/EventItem/index.tsx +170 -0
- package/src/modules/ActivityLog/ItemLogUser/UserItem/EventItem/style.tsx +79 -0
- package/src/modules/ActivityLog/ItemLogUser/UserItem/index.tsx +46 -0
- package/src/modules/ActivityLog/ItemLogUser/UserItem/style.tsx +60 -0
- package/src/modules/ActivityLog/ItemLogUser/index.tsx +25 -0
- package/src/modules/ActivityLog/LogFilters/ContentFilter/index.tsx +79 -0
- package/src/modules/ActivityLog/LogFilters/DateFilter/index.tsx +91 -0
- package/src/modules/ActivityLog/LogFilters/DateFilter/style.tsx +208 -0
- package/src/modules/ActivityLog/LogFilters/EventFilter/index.tsx +80 -0
- package/src/modules/ActivityLog/LogFilters/OrderFilter/index.tsx +49 -0
- package/src/modules/ActivityLog/LogFilters/OrderFilter/style.tsx +35 -0
- package/src/modules/ActivityLog/LogFilters/UserFilter/index.tsx +79 -0
- package/src/modules/ActivityLog/TableHeader/index.tsx +72 -0
- package/src/modules/ActivityLog/TableHeader/style.tsx +73 -0
- package/src/modules/ActivityLog/constants.tsx +10 -0
- package/src/modules/ActivityLog/hooks.tsx +53 -0
- package/src/modules/ActivityLog/index.tsx +313 -0
- package/src/modules/ActivityLog/style.tsx +57 -0
- package/src/modules/ActivityLog/utils.tsx +31 -0
- package/src/modules/Categories/CategoriesList/index.tsx +1 -1
- package/src/modules/Forms/FormEditor/Editor/FormConfigPanel/Form/index.tsx +3 -0
- package/src/modules/Forms/FormEditor/Editor/FormConfigPanel/index.tsx +3 -0
- package/src/modules/Forms/FormEditor/Editor/index.tsx +5 -2
- package/src/modules/Forms/FormEditor/index.tsx +20 -3
- package/src/modules/GlobalEditor/Editor/index.tsx +3 -0
- package/src/modules/GlobalEditor/index.tsx +48 -9
- package/src/modules/Navigation/Defaults/DefaultsEditor/Editor/DefaultsBrowser/index.tsx +3 -1
- package/src/modules/Navigation/Defaults/DefaultsEditor/Editor/index.tsx +4 -1
- package/src/modules/Navigation/Defaults/DefaultsEditor/index.tsx +45 -6
- package/src/modules/PageEditor/Editor/index.tsx +4 -1
- package/src/modules/PageEditor/index.tsx +46 -7
- package/src/modules/Redirects/BulkHeader/TableHeader/style.tsx +1 -7
- package/src/modules/StructuredData/Form/index.tsx +56 -7
- package/src/modules/StructuredData/StructuredDataList/BulkHeader/TableHeader/index.tsx +2 -2
- package/src/modules/StructuredData/StructuredDataList/BulkHeader/index.tsx +2 -8
- package/src/modules/StructuredData/StructuredDataList/hooks.tsx +9 -9
- package/src/modules/StructuredData/StructuredDataList/index.tsx +3 -4
- package/src/modules/Users/Roles/index.tsx +0 -2
- package/src/modules/Users/UserEdit/index.tsx +12 -28
- package/src/modules/Users/UserList/BulkHeader/TableHeader/style.tsx +1 -0
- package/src/modules/Users/UserList/UserItem/index.tsx +10 -25
- package/src/modules/Users/UserList/index.tsx +8 -10
- package/src/routes/multisite.tsx +9 -0
- package/src/themes/theme.json +2 -1
- package/src/types/forms.tsx +1 -0
- package/src/types/index.tsx +8 -0
- package/src/types/logs.tsx +12 -0
- package/src/components/TableFilters/SiteFilter/style.tsx +0 -28
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
import { connect } from "react-redux";
|
|
3
|
+
|
|
4
|
+
import { LogActivityDTO, LogContentDTO, LogContentTypeDTO } from "@griddo/api-types";
|
|
5
|
+
import { Avatar, Tag, RestoreModal } from "@ax/components";
|
|
6
|
+
import { useModal } from "@ax/hooks";
|
|
7
|
+
import { pageEditorActions } from "@ax/containers/PageEditor";
|
|
8
|
+
import { activityLogActions } from "@ax/containers/ActivityLog";
|
|
9
|
+
import { navigationActions } from "@ax/containers/Navigation";
|
|
10
|
+
import { structuredDataActions } from "@ax/containers/StructuredData";
|
|
11
|
+
import { IRootState } from "@ax/types";
|
|
12
|
+
|
|
13
|
+
import DetailModal from "../../DetailModal";
|
|
14
|
+
import { eventKey } from "../../constants";
|
|
15
|
+
import { getContentTypeSchemaVersion, getPageSchemaVersion } from "../../utils";
|
|
16
|
+
|
|
17
|
+
import * as S from "./style";
|
|
18
|
+
|
|
19
|
+
const EventItem = (props: IEventItemProps) => {
|
|
20
|
+
const { item, schemaVersion, restorePage, restoreNavigation, restoreStructuredData, goToLogContent, getLog } = props;
|
|
21
|
+
const { user, created, site, contentType, content, eventType } = item;
|
|
22
|
+
|
|
23
|
+
const { isOpen: isDetailOpen, toggleModal: toggleDetailModal } = useModal();
|
|
24
|
+
const { isOpen: isRestoreOpen, toggleModal: toggleRestoreModal } = useModal();
|
|
25
|
+
const [schemaChange, setSchemaChange] = useState(false);
|
|
26
|
+
|
|
27
|
+
const isDeleteEvent = eventType?.internal_key ? eventType.internal_key.includes("DELETED") : false;
|
|
28
|
+
|
|
29
|
+
const restoreByContent = async (type: string, id: number) => {
|
|
30
|
+
switch (type) {
|
|
31
|
+
case eventKey.DELETED_PAGE:
|
|
32
|
+
case eventKey.DELETED_CONTENT_TYPE_PAGE:
|
|
33
|
+
return await restorePage(id);
|
|
34
|
+
case eventKey.DELETED_HEADER:
|
|
35
|
+
return await restoreNavigation(id, "header");
|
|
36
|
+
case eventKey.DELETED_FOOTER:
|
|
37
|
+
return await restoreNavigation(id, "footer");
|
|
38
|
+
case eventKey.DELETED_CATEGORY:
|
|
39
|
+
case eventKey.DELETED_CONTENT_TYPE:
|
|
40
|
+
return await restoreStructuredData(id);
|
|
41
|
+
default:
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const handleRestore = async () => {
|
|
47
|
+
const contentID = contentType?.id || content?.id;
|
|
48
|
+
if (contentID && eventType?.internal_key) {
|
|
49
|
+
const isRestored = await restoreByContent(eventType.internal_key, contentID);
|
|
50
|
+
if (isRestored) {
|
|
51
|
+
getLog();
|
|
52
|
+
isRestoreOpen && toggleRestoreModal();
|
|
53
|
+
isDetailOpen && toggleDetailModal();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const handleDetailRestorePage = async () => {
|
|
59
|
+
const contentID = contentType?.id || content?.id || null;
|
|
60
|
+
const hasSchemaVersion = [
|
|
61
|
+
eventKey.DELETED_PAGE,
|
|
62
|
+
eventKey.DELETED_CONTENT_TYPE_PAGE,
|
|
63
|
+
eventKey.DELETED_CONTENT_TYPE,
|
|
64
|
+
].includes(eventType?.internal_key || "");
|
|
65
|
+
|
|
66
|
+
if (contentID && hasSchemaVersion) {
|
|
67
|
+
const pageSchemaVersion =
|
|
68
|
+
eventType?.internal_key === eventKey.DELETED_CONTENT_TYPE
|
|
69
|
+
? await getContentTypeSchemaVersion(contentID)
|
|
70
|
+
: await getPageSchemaVersion(contentID);
|
|
71
|
+
if (schemaVersion !== pageSchemaVersion) {
|
|
72
|
+
setSchemaChange(true);
|
|
73
|
+
} else {
|
|
74
|
+
setSchemaChange(false);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
toggleRestoreModal();
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {
|
|
82
|
+
e.stopPropagation();
|
|
83
|
+
const siteID = site?.id || null;
|
|
84
|
+
goToLogContent(contentType, content, siteID);
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const handleKeyDown = () => {
|
|
88
|
+
const siteID = site?.id || null;
|
|
89
|
+
goToLogContent(contentType, content, siteID);
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
return (
|
|
93
|
+
<>
|
|
94
|
+
<S.Item onClick={toggleDetailModal}>
|
|
95
|
+
<S.User>
|
|
96
|
+
<S.AvatarWrapper>
|
|
97
|
+
<Avatar image={user.image} name={user.name || ""} />
|
|
98
|
+
</S.AvatarWrapper>
|
|
99
|
+
<S.Name>{user.name}</S.Name>
|
|
100
|
+
</S.User>
|
|
101
|
+
<S.Time>{created.hour}</S.Time>
|
|
102
|
+
<S.Site>
|
|
103
|
+
<Tag
|
|
104
|
+
text={site && site.name ? site.name : "Global"}
|
|
105
|
+
type="square"
|
|
106
|
+
color={site ? undefined : "#C3F4FF"}
|
|
107
|
+
textColor="rgba(32, 34, 76, 0.6)"
|
|
108
|
+
/>
|
|
109
|
+
</S.Site>
|
|
110
|
+
<S.ContentType>
|
|
111
|
+
{!!contentType && <Tag text={contentType.content?.title || ""} color="#E6E7F8" small={true} />}
|
|
112
|
+
</S.ContentType>
|
|
113
|
+
<S.Event>
|
|
114
|
+
{eventType?.name || ""}{" "}
|
|
115
|
+
<div
|
|
116
|
+
onClick={!isDeleteEvent ? handleClick : undefined}
|
|
117
|
+
role="button"
|
|
118
|
+
tabIndex={0}
|
|
119
|
+
onKeyDown={!isDeleteEvent ? handleKeyDown : undefined}
|
|
120
|
+
>
|
|
121
|
+
{content?.title || contentType?.title || ""}
|
|
122
|
+
</div>
|
|
123
|
+
</S.Event>
|
|
124
|
+
</S.Item>
|
|
125
|
+
<DetailModal
|
|
126
|
+
isOpen={isDetailOpen}
|
|
127
|
+
toggleModal={toggleDetailModal}
|
|
128
|
+
itemLog={item}
|
|
129
|
+
restorePage={handleDetailRestorePage}
|
|
130
|
+
onClick={handleClick}
|
|
131
|
+
onKeyDown={handleKeyDown}
|
|
132
|
+
/>
|
|
133
|
+
{isRestoreOpen && (
|
|
134
|
+
<RestoreModal
|
|
135
|
+
isOpen={isRestoreOpen}
|
|
136
|
+
toggleModal={toggleRestoreModal}
|
|
137
|
+
isChild={true}
|
|
138
|
+
hasIssues={schemaChange}
|
|
139
|
+
restorePage={handleRestore}
|
|
140
|
+
/>
|
|
141
|
+
)}
|
|
142
|
+
</>
|
|
143
|
+
);
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
interface IEventItemProps {
|
|
147
|
+
item: LogActivityDTO;
|
|
148
|
+
schemaVersion: string;
|
|
149
|
+
restorePage(id: number): Promise<boolean>;
|
|
150
|
+
restoreNavigation(navID: number, type: string): Promise<boolean>;
|
|
151
|
+
restoreStructuredData(dataID: number): Promise<boolean>;
|
|
152
|
+
goToLogContent(contentType: LogContentTypeDTO | null, content: LogContentDTO | null, site: number | null): void;
|
|
153
|
+
getLog(): void;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const mapStateToProps = (state: IRootState) => ({
|
|
157
|
+
schemaVersion: state.structuredData.schemaVersion,
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
const mapDispatchToProps = {
|
|
161
|
+
restorePage: pageEditorActions.restorePage,
|
|
162
|
+
restoreNavigation: navigationActions.restoreNavigation,
|
|
163
|
+
restoreStructuredData: structuredDataActions.restoreStructuredDataContent,
|
|
164
|
+
goToLogContent: activityLogActions.goToLogContent,
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
export default connect(mapStateToProps, mapDispatchToProps)(EventItem);
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import styled from "styled-components";
|
|
2
|
+
|
|
3
|
+
const Item = styled.div`
|
|
4
|
+
display: flex;
|
|
5
|
+
background-color: ${(p) => p.theme.color.uiBackground02};
|
|
6
|
+
border: ${(p) => `1px solid ${p.theme.color.uiLine}`};
|
|
7
|
+
height: ${(p) => p.theme.spacing.l};
|
|
8
|
+
cursor: pointer;
|
|
9
|
+
position: relative;
|
|
10
|
+
:before {
|
|
11
|
+
content: "";
|
|
12
|
+
background-color: transparent;
|
|
13
|
+
position: absolute;
|
|
14
|
+
top: 0;
|
|
15
|
+
left: 0;
|
|
16
|
+
width: 100%;
|
|
17
|
+
height: 100%;
|
|
18
|
+
pointer-events: none;
|
|
19
|
+
}
|
|
20
|
+
&:hover {
|
|
21
|
+
&:before {
|
|
22
|
+
background-color: ${(p) => p.theme.color.overlayHoverPrimary};
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
`;
|
|
26
|
+
|
|
27
|
+
const User = styled.div`
|
|
28
|
+
display: flex;
|
|
29
|
+
align-items: center;
|
|
30
|
+
width: 24%;
|
|
31
|
+
padding-left: ${(p) => p.theme.spacing.s};
|
|
32
|
+
`;
|
|
33
|
+
|
|
34
|
+
const Name = styled.div`
|
|
35
|
+
${(p) => p.theme.textStyle.uiS};
|
|
36
|
+
color: ${(p) => p.theme.colors.textHighEmphasis};
|
|
37
|
+
`;
|
|
38
|
+
|
|
39
|
+
const AvatarWrapper = styled.div`
|
|
40
|
+
margin-right: ${(p) => p.theme.spacing.s};
|
|
41
|
+
`;
|
|
42
|
+
|
|
43
|
+
const Time = styled.div`
|
|
44
|
+
${(p) => p.theme.textStyle.uiXS};
|
|
45
|
+
display: flex;
|
|
46
|
+
align-items: center;
|
|
47
|
+
justify-content: center;
|
|
48
|
+
color: ${(p) => p.theme.colors.textMediumEmphasis};
|
|
49
|
+
width: 8%;
|
|
50
|
+
`;
|
|
51
|
+
|
|
52
|
+
const Site = styled.div`
|
|
53
|
+
display: flex;
|
|
54
|
+
align-items: center;
|
|
55
|
+
justify-content: center;
|
|
56
|
+
width: 15%;
|
|
57
|
+
`;
|
|
58
|
+
|
|
59
|
+
const ContentType = styled.div`
|
|
60
|
+
display: flex;
|
|
61
|
+
align-items: center;
|
|
62
|
+
justify-content: center;
|
|
63
|
+
width: 15%;
|
|
64
|
+
`;
|
|
65
|
+
|
|
66
|
+
const Event = styled.div`
|
|
67
|
+
${(p) => p.theme.textStyle.uiS};
|
|
68
|
+
display: flex;
|
|
69
|
+
align-items: center;
|
|
70
|
+
color: ${(p) => p.theme.colors.textMediumEmphasis};
|
|
71
|
+
width: 38%;
|
|
72
|
+
padding-right: ${(p) => p.theme.spacing.s};
|
|
73
|
+
div {
|
|
74
|
+
margin-left: ${(p) => p.theme.spacing.xxs};
|
|
75
|
+
color: ${(p) => p.theme.colors.interactive01};
|
|
76
|
+
}
|
|
77
|
+
`;
|
|
78
|
+
|
|
79
|
+
export { Item, User, Name, AvatarWrapper, Time, Site, ContentType, Event };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { LogActivityGroupedDayDTO } from "@griddo/api-types";
|
|
3
|
+
import ItemGroup from "../ItemGroup";
|
|
4
|
+
import EventItem from "./EventItem";
|
|
5
|
+
|
|
6
|
+
const ItemLog = (props: IItemLogProps) => {
|
|
7
|
+
const { items, getLog } = props;
|
|
8
|
+
const { date, items: dayItems, totalItems } = items;
|
|
9
|
+
|
|
10
|
+
return (
|
|
11
|
+
<ItemGroup date={date} count={totalItems}>
|
|
12
|
+
{dayItems.map((item) => (
|
|
13
|
+
<EventItem key={item.id} item={item} getLog={getLog} />
|
|
14
|
+
))}
|
|
15
|
+
</ItemGroup>
|
|
16
|
+
);
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
interface IItemLogProps {
|
|
20
|
+
items: LogActivityGroupedDayDTO;
|
|
21
|
+
getLog(): void;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export default ItemLog;
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
import { connect } from "react-redux";
|
|
3
|
+
|
|
4
|
+
import { LogActivityDTO, LogContentDTO, LogContentTypeDTO } from "@griddo/api-types";
|
|
5
|
+
import { useModal } from "@ax/hooks";
|
|
6
|
+
import { pageEditorActions } from "@ax/containers/PageEditor";
|
|
7
|
+
import { activityLogActions } from "@ax/containers/ActivityLog";
|
|
8
|
+
import { navigationActions } from "@ax/containers/Navigation";
|
|
9
|
+
import { structuredDataActions } from "@ax/containers/StructuredData";
|
|
10
|
+
import { IRootState } from "@ax/types";
|
|
11
|
+
import { RestoreModal } from "@ax/components";
|
|
12
|
+
|
|
13
|
+
import DetailModal from "./../../../DetailModal";
|
|
14
|
+
import { eventKey } from "./../../../constants";
|
|
15
|
+
import { getContentTypeSchemaVersion, getPageSchemaVersion } from "./../../../utils";
|
|
16
|
+
|
|
17
|
+
import * as S from "./style";
|
|
18
|
+
|
|
19
|
+
const EventItem = (props: IEventItemProps) => {
|
|
20
|
+
const { item, schemaVersion, restorePage, restoreNavigation, restoreStructuredData, goToLogContent, getLog } = props;
|
|
21
|
+
|
|
22
|
+
const { created, site, contentType, content, eventType } = item;
|
|
23
|
+
|
|
24
|
+
const { isOpen: isDetailOpen, toggleModal: toggleDetailModal } = useModal();
|
|
25
|
+
const { isOpen: isRestoreOpen, toggleModal: toggleRestoreModal } = useModal();
|
|
26
|
+
const [schemaChange, setSchemaChange] = useState(false);
|
|
27
|
+
|
|
28
|
+
const isDeleteEvent = eventType?.internal_key ? eventType.internal_key.includes("DELETED") : false;
|
|
29
|
+
|
|
30
|
+
const restoreByContent = async (type: string, id: number) => {
|
|
31
|
+
switch (type) {
|
|
32
|
+
case eventKey.DELETED_PAGE:
|
|
33
|
+
case eventKey.DELETED_CONTENT_TYPE_PAGE:
|
|
34
|
+
return await restorePage(id);
|
|
35
|
+
case eventKey.DELETED_HEADER:
|
|
36
|
+
return await restoreNavigation(id, "header");
|
|
37
|
+
case eventKey.DELETED_FOOTER:
|
|
38
|
+
return await restoreNavigation(id, "footer");
|
|
39
|
+
case eventKey.DELETED_CATEGORY:
|
|
40
|
+
case eventKey.DELETED_CONTENT_TYPE:
|
|
41
|
+
return await restoreStructuredData(id);
|
|
42
|
+
default:
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const handleRestore = async () => {
|
|
48
|
+
const contentID = contentType?.id || content?.id;
|
|
49
|
+
if (contentID && eventType?.internal_key) {
|
|
50
|
+
const isRestored = await restoreByContent(eventType.internal_key, contentID);
|
|
51
|
+
if (isRestored) {
|
|
52
|
+
getLog();
|
|
53
|
+
isRestoreOpen && toggleRestoreModal();
|
|
54
|
+
isDetailOpen && toggleDetailModal();
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const handleDetailRestorePage = async () => {
|
|
60
|
+
const contentID = contentType?.id || content?.id || null;
|
|
61
|
+
const hasSchemaVersion = [
|
|
62
|
+
eventKey.DELETED_PAGE,
|
|
63
|
+
eventKey.DELETED_CONTENT_TYPE_PAGE,
|
|
64
|
+
eventKey.DELETED_CONTENT_TYPE,
|
|
65
|
+
].includes(eventType?.internal_key || "");
|
|
66
|
+
|
|
67
|
+
if (contentID && hasSchemaVersion) {
|
|
68
|
+
const pageSchemaVersion =
|
|
69
|
+
eventType?.internal_key === eventKey.DELETED_CONTENT_TYPE
|
|
70
|
+
? await getContentTypeSchemaVersion(contentID)
|
|
71
|
+
: await getPageSchemaVersion(contentID);
|
|
72
|
+
if (schemaVersion !== pageSchemaVersion) {
|
|
73
|
+
setSchemaChange(true);
|
|
74
|
+
} else {
|
|
75
|
+
setSchemaChange(false);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
toggleRestoreModal();
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {
|
|
83
|
+
e.stopPropagation();
|
|
84
|
+
const siteID = site?.id || null;
|
|
85
|
+
goToLogContent(contentType, content, siteID);
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const handleKeyDown = () => {
|
|
89
|
+
const siteID = site?.id || null;
|
|
90
|
+
goToLogContent(contentType, content, siteID);
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
return (
|
|
94
|
+
<>
|
|
95
|
+
<S.ActivityItem onClick={toggleDetailModal}>
|
|
96
|
+
<S.EventWrapper>
|
|
97
|
+
<S.Time>{created.hour}</S.Time>
|
|
98
|
+
<S.Event>
|
|
99
|
+
{eventType?.name || ""}{" "}
|
|
100
|
+
<div
|
|
101
|
+
onClick={!isDeleteEvent ? handleClick : undefined}
|
|
102
|
+
role="button"
|
|
103
|
+
tabIndex={0}
|
|
104
|
+
onKeyDown={!isDeleteEvent ? handleKeyDown : undefined}
|
|
105
|
+
>
|
|
106
|
+
{content?.title || contentType?.title || ""}
|
|
107
|
+
</div>
|
|
108
|
+
</S.Event>
|
|
109
|
+
</S.EventWrapper>
|
|
110
|
+
<S.Site>
|
|
111
|
+
<S.Label>Site</S.Label>
|
|
112
|
+
<S.StyledTag
|
|
113
|
+
text={site ? site.name : "Global"}
|
|
114
|
+
type="square"
|
|
115
|
+
color={site ? undefined : "#C3F4FF"}
|
|
116
|
+
textColor="rgba(32, 34, 76, 0.6)"
|
|
117
|
+
/>
|
|
118
|
+
</S.Site>
|
|
119
|
+
<S.ContentType>
|
|
120
|
+
{!!contentType && (
|
|
121
|
+
<>
|
|
122
|
+
<S.Label>Content type</S.Label>
|
|
123
|
+
<S.StyledTag text={contentType.content?.title || ""} color="#E6E7F8" small={true} />
|
|
124
|
+
</>
|
|
125
|
+
)}
|
|
126
|
+
</S.ContentType>
|
|
127
|
+
</S.ActivityItem>
|
|
128
|
+
<DetailModal
|
|
129
|
+
isOpen={isDetailOpen}
|
|
130
|
+
toggleModal={toggleDetailModal}
|
|
131
|
+
itemLog={item}
|
|
132
|
+
restorePage={handleDetailRestorePage}
|
|
133
|
+
onClick={handleClick}
|
|
134
|
+
onKeyDown={handleKeyDown}
|
|
135
|
+
/>
|
|
136
|
+
{isRestoreOpen && (
|
|
137
|
+
<RestoreModal
|
|
138
|
+
isOpen={isRestoreOpen}
|
|
139
|
+
toggleModal={toggleRestoreModal}
|
|
140
|
+
isChild={true}
|
|
141
|
+
restorePage={handleRestore}
|
|
142
|
+
hasIssues={schemaChange}
|
|
143
|
+
/>
|
|
144
|
+
)}
|
|
145
|
+
</>
|
|
146
|
+
);
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
interface IEventItemProps {
|
|
150
|
+
item: LogActivityDTO;
|
|
151
|
+
schemaVersion: string;
|
|
152
|
+
restorePage(id: number): Promise<boolean>;
|
|
153
|
+
restoreNavigation(navID: number, type: string): Promise<boolean>;
|
|
154
|
+
restoreStructuredData(dataID: number): Promise<boolean>;
|
|
155
|
+
goToLogContent(contentType: LogContentTypeDTO | null, content: LogContentDTO | null, site: number | null): void;
|
|
156
|
+
getLog(): void;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const mapStateToProps = (state: IRootState) => ({
|
|
160
|
+
schemaVersion: state.structuredData.schemaVersion,
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
const mapDispatchToProps = {
|
|
164
|
+
restorePage: pageEditorActions.restorePage,
|
|
165
|
+
restoreNavigation: navigationActions.restoreNavigation,
|
|
166
|
+
restoreStructuredData: structuredDataActions.restoreStructuredDataContent,
|
|
167
|
+
goToLogContent: activityLogActions.goToLogContent,
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
export default connect(mapStateToProps, mapDispatchToProps)(EventItem);
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import styled from "styled-components";
|
|
3
|
+
import { Tag } from "@ax/components";
|
|
4
|
+
|
|
5
|
+
const ActivityItem = styled.div`
|
|
6
|
+
display: flex;
|
|
7
|
+
margin-bottom: ${(p) => p.theme.spacing.xxs};
|
|
8
|
+
position: relative;
|
|
9
|
+
cursor: pointer;
|
|
10
|
+
&:last-child {
|
|
11
|
+
margin-bottom: ${(p) => p.theme.spacing.xs};
|
|
12
|
+
}
|
|
13
|
+
:before {
|
|
14
|
+
content: "";
|
|
15
|
+
background-color: transparent;
|
|
16
|
+
position: absolute;
|
|
17
|
+
top: 0;
|
|
18
|
+
left: 0;
|
|
19
|
+
width: 100%;
|
|
20
|
+
height: 100%;
|
|
21
|
+
pointer-events: none;
|
|
22
|
+
}
|
|
23
|
+
&:hover {
|
|
24
|
+
&:before {
|
|
25
|
+
background-color: ${(p) => p.theme.color.overlayHoverPrimary};
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
`;
|
|
29
|
+
|
|
30
|
+
const EventWrapper = styled.div`
|
|
31
|
+
display: flex;
|
|
32
|
+
width: 50%;
|
|
33
|
+
`;
|
|
34
|
+
|
|
35
|
+
const Time = styled.div`
|
|
36
|
+
${(p) => p.theme.textStyle.uiXS};
|
|
37
|
+
display: flex;
|
|
38
|
+
align-items: center;
|
|
39
|
+
justify-content: center;
|
|
40
|
+
color: ${(p) => p.theme.colors.textMediumEmphasis};
|
|
41
|
+
width: 56px;
|
|
42
|
+
flex-shrink: 0;
|
|
43
|
+
`;
|
|
44
|
+
|
|
45
|
+
const Site = styled.div`
|
|
46
|
+
display: flex;
|
|
47
|
+
align-items: center;
|
|
48
|
+
width: 25%;
|
|
49
|
+
`;
|
|
50
|
+
|
|
51
|
+
const ContentType = styled.div`
|
|
52
|
+
display: flex;
|
|
53
|
+
align-items: center;
|
|
54
|
+
width: 25%;
|
|
55
|
+
`;
|
|
56
|
+
|
|
57
|
+
const Event = styled.div`
|
|
58
|
+
${(p) => p.theme.textStyle.uiS};
|
|
59
|
+
display: flex;
|
|
60
|
+
align-items: center;
|
|
61
|
+
color: ${(p) => p.theme.colors.textMediumEmphasis};
|
|
62
|
+
flex-grow: 1;
|
|
63
|
+
div {
|
|
64
|
+
margin-left: ${(p) => p.theme.spacing.xxs};
|
|
65
|
+
color: ${(p) => p.theme.colors.interactive01};
|
|
66
|
+
}
|
|
67
|
+
`;
|
|
68
|
+
|
|
69
|
+
const Label = styled.div`
|
|
70
|
+
${(p) => p.theme.textStyle.uiM};
|
|
71
|
+
color: ${(p) => p.theme.colors.textMediumEmphasis};
|
|
72
|
+
margin-right: ${(p) => p.theme.spacing.xs};
|
|
73
|
+
`;
|
|
74
|
+
|
|
75
|
+
const StyledTag = styled((props) => <Tag {...props} />)`
|
|
76
|
+
margin-bottom: 0;
|
|
77
|
+
`;
|
|
78
|
+
|
|
79
|
+
export { ActivityItem, EventWrapper, Time, Site, ContentType, Event, Label, StyledTag };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
import { Avatar } from "@ax/components";
|
|
3
|
+
import EventItem from "./EventItem";
|
|
4
|
+
|
|
5
|
+
import * as S from "./style";
|
|
6
|
+
|
|
7
|
+
const UserItem = (props: IUserItemProps) => {
|
|
8
|
+
const { user, getLog } = props;
|
|
9
|
+
const { logActivity, ...userProps } = user;
|
|
10
|
+
const { image, name } = userProps;
|
|
11
|
+
|
|
12
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
13
|
+
|
|
14
|
+
const handleToggle = () => setIsOpen((state) => !state);
|
|
15
|
+
|
|
16
|
+
const buttonText = isOpen ? "Hide events" : "Show events";
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<S.Item>
|
|
20
|
+
<S.User>
|
|
21
|
+
<S.AvatarWrapper>
|
|
22
|
+
<Avatar image={image} name={name || ""} size="s" />
|
|
23
|
+
</S.AvatarWrapper>
|
|
24
|
+
<S.Name>{name}</S.Name>
|
|
25
|
+
{!isOpen && <S.CounterWrapper>{logActivity.length} events created</S.CounterWrapper>}
|
|
26
|
+
<S.ToggleWrapper>
|
|
27
|
+
<S.Toggle onClick={handleToggle} isOpen={isOpen}>
|
|
28
|
+
{buttonText}
|
|
29
|
+
</S.Toggle>
|
|
30
|
+
</S.ToggleWrapper>
|
|
31
|
+
</S.User>
|
|
32
|
+
<S.EventList isOpen={isOpen}>
|
|
33
|
+
{logActivity.map((item: any, index: number) => (
|
|
34
|
+
<EventItem key={index} item={{ ...item, user: userProps }} getLog={getLog} />
|
|
35
|
+
))}
|
|
36
|
+
</S.EventList>
|
|
37
|
+
</S.Item>
|
|
38
|
+
);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
interface IUserItemProps {
|
|
42
|
+
user: any;
|
|
43
|
+
getLog(): void;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export default UserItem;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import styled from "styled-components";
|
|
2
|
+
|
|
3
|
+
const Item = styled.div`
|
|
4
|
+
display: flex;
|
|
5
|
+
flex-direction: column;
|
|
6
|
+
background-color: ${(p) => p.theme.color.uiBackground02};
|
|
7
|
+
border: ${(p) => `1px solid ${p.theme.color.uiLine}`};
|
|
8
|
+
min-height: ${(p) => p.theme.spacing.l};
|
|
9
|
+
`;
|
|
10
|
+
|
|
11
|
+
const User = styled.div`
|
|
12
|
+
display: flex;
|
|
13
|
+
align-items: center;
|
|
14
|
+
padding: ${(p) => `11px ${p.theme.spacing.s} ${p.theme.spacing.xs} ${p.theme.spacing.s}`};
|
|
15
|
+
`;
|
|
16
|
+
|
|
17
|
+
const Name = styled.div`
|
|
18
|
+
${(p) => p.theme.textStyle.uiS};
|
|
19
|
+
color: ${(p) => p.theme.colors.textHighEmphasis};
|
|
20
|
+
width: 25%;
|
|
21
|
+
`;
|
|
22
|
+
|
|
23
|
+
const AvatarWrapper = styled.div`
|
|
24
|
+
margin-right: ${(p) => p.theme.spacing.s};
|
|
25
|
+
`;
|
|
26
|
+
|
|
27
|
+
const CounterWrapper = styled.div`
|
|
28
|
+
${(p) => p.theme.textStyle.uiL};
|
|
29
|
+
color: ${(p) => p.theme.colors.textMediumEmphasis};
|
|
30
|
+
`;
|
|
31
|
+
|
|
32
|
+
const ToggleWrapper = styled.div`
|
|
33
|
+
margin-left: auto;
|
|
34
|
+
`;
|
|
35
|
+
|
|
36
|
+
const EventList = styled.div<{ isOpen: boolean }>`
|
|
37
|
+
display: flex;
|
|
38
|
+
flex-direction: column;
|
|
39
|
+
height: ${(p) => (p.isOpen ? "auto" : "0px")};
|
|
40
|
+
overflow: hidden;
|
|
41
|
+
`;
|
|
42
|
+
|
|
43
|
+
const Toggle = styled.button<{ isOpen: boolean }>`
|
|
44
|
+
${(p) => p.theme.textStyle.uiS};
|
|
45
|
+
position: relative;
|
|
46
|
+
padding-right: ${(p) => p.theme.spacing.s};
|
|
47
|
+
color: ${(p) => p.theme.colors.textMediumEmphasis};
|
|
48
|
+
&:after {
|
|
49
|
+
position: absolute;
|
|
50
|
+
top: 6px;
|
|
51
|
+
right: 0;
|
|
52
|
+
content: "";
|
|
53
|
+
border: solid ${(p) => p.theme.color.interactive01};
|
|
54
|
+
border-width: 0 2px 2px 0;
|
|
55
|
+
padding: 3px;
|
|
56
|
+
transform: ${(p) => (p.isOpen ? `rotate(-135deg) translate(-3px, 0)` : `rotate(45deg) translate(0, -3px)`)};
|
|
57
|
+
}
|
|
58
|
+
`;
|
|
59
|
+
|
|
60
|
+
export { Item, User, Name, AvatarWrapper, EventList, CounterWrapper, ToggleWrapper, Toggle };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import ItemGroup from "../ItemGroup";
|
|
3
|
+
import UserItem from "./UserItem";
|
|
4
|
+
|
|
5
|
+
const ItemLogUser = (props: IItemLogUserProps) => {
|
|
6
|
+
const { items, getLog } = props;
|
|
7
|
+
const { date, user: users } = items;
|
|
8
|
+
|
|
9
|
+
const count = users.reduce((total: number, user: any) => total + user.logActivity.length, 0);
|
|
10
|
+
|
|
11
|
+
return (
|
|
12
|
+
<ItemGroup date={date} count={count}>
|
|
13
|
+
{users.map((user: any) => (
|
|
14
|
+
<UserItem key={user.id} user={user} getLog={getLog} />
|
|
15
|
+
))}
|
|
16
|
+
</ItemGroup>
|
|
17
|
+
);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
interface IItemLogUserProps {
|
|
21
|
+
items: any;
|
|
22
|
+
getLog(): void;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export default ItemLogUser;
|