@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,73 @@
|
|
|
1
|
+
import styled from "styled-components";
|
|
2
|
+
import { Header } from "@ax/components/TableList/style";
|
|
3
|
+
|
|
4
|
+
const TableHeader = styled.div<{ isScrolling?: boolean }>`
|
|
5
|
+
width: 100%;
|
|
6
|
+
display: flex;
|
|
7
|
+
flex-direction: row;
|
|
8
|
+
padding: ${(p) => `${p.theme.spacing.xs} ${p.theme.spacing.m}`};
|
|
9
|
+
border-bottom: ${(p) => (p.isScrolling ? `1px solid ${p.theme.color.uiLine};` : "")};
|
|
10
|
+
margin-left: ${(p) => p.theme.spacing.xs};
|
|
11
|
+
margin-right: ${(p) => p.theme.spacing.xs};
|
|
12
|
+
`;
|
|
13
|
+
|
|
14
|
+
const UserHeader = styled(Header)`
|
|
15
|
+
width: 24%;
|
|
16
|
+
padding: ${(p) => `0 0 0 ${p.theme.spacing.s}`};
|
|
17
|
+
& > div {
|
|
18
|
+
margin-right: ${(p) => p.theme.spacing.m};
|
|
19
|
+
}
|
|
20
|
+
`;
|
|
21
|
+
|
|
22
|
+
const TimeHeader = styled(Header)`
|
|
23
|
+
width: 8%;
|
|
24
|
+
justify-content: center;
|
|
25
|
+
padding: 0;
|
|
26
|
+
`;
|
|
27
|
+
|
|
28
|
+
const SiteHeader = styled(Header)`
|
|
29
|
+
width: 15%;
|
|
30
|
+
justify-content: center;
|
|
31
|
+
padding: 0;
|
|
32
|
+
`;
|
|
33
|
+
|
|
34
|
+
const ContentHeader = styled(Header)`
|
|
35
|
+
width: 15%;
|
|
36
|
+
justify-content: center;
|
|
37
|
+
padding: 0;
|
|
38
|
+
`;
|
|
39
|
+
|
|
40
|
+
const EventHeader = styled(Header)`
|
|
41
|
+
width: 38%;
|
|
42
|
+
padding: 0;
|
|
43
|
+
`;
|
|
44
|
+
|
|
45
|
+
const FiltersHeader = styled(Header)`
|
|
46
|
+
width: 50%;
|
|
47
|
+
padding: ${(p) => `0 0 0 ${p.theme.spacing.s}`};
|
|
48
|
+
& > div {
|
|
49
|
+
margin-right: ${(p) => p.theme.spacing.m};
|
|
50
|
+
}
|
|
51
|
+
`;
|
|
52
|
+
|
|
53
|
+
const SiteUserHeader = styled(Header)`
|
|
54
|
+
width: 25%;
|
|
55
|
+
padding: 0;
|
|
56
|
+
`;
|
|
57
|
+
|
|
58
|
+
const ContentUserHeader = styled(Header)`
|
|
59
|
+
width: 25%;
|
|
60
|
+
padding: ${(p) => `0 ${p.theme.spacing.s} 0 0`};
|
|
61
|
+
`;
|
|
62
|
+
|
|
63
|
+
export {
|
|
64
|
+
TableHeader,
|
|
65
|
+
UserHeader,
|
|
66
|
+
TimeHeader,
|
|
67
|
+
SiteHeader,
|
|
68
|
+
ContentHeader,
|
|
69
|
+
EventHeader,
|
|
70
|
+
FiltersHeader,
|
|
71
|
+
ContentUserHeader,
|
|
72
|
+
SiteUserHeader,
|
|
73
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
const eventKey: Record<string, string> = Object.freeze({
|
|
2
|
+
DELETED_PAGE: "DELETED_PAGE",
|
|
3
|
+
DELETED_CONTENT_TYPE_PAGE: "DELETED_X_CONTENT_TYPE_PAGE",
|
|
4
|
+
DELETED_FOOTER: "DELETED_FOOTER",
|
|
5
|
+
DELETED_HEADER: "DELETED_HEADER",
|
|
6
|
+
DELETED_STRUCTURED_DATA: "DELETED_HEADER",
|
|
7
|
+
DELETED_CONTENT_TYPE: "DELETED_X_CONTENT_TYPE_SIMPLE",
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
export { eventKey };
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
import { IQueryValue } from "@ax/types";
|
|
3
|
+
|
|
4
|
+
const useFilterQuery = () => {
|
|
5
|
+
const initialQueryValues: Record<string, IQueryValue[]> = {
|
|
6
|
+
sites: [{ value: "all", label: "All" }],
|
|
7
|
+
users: [{ value: "all", label: "All" }],
|
|
8
|
+
eventTypes: [{ value: "all", label: "All" }],
|
|
9
|
+
contentTypes: [{ value: "all", label: "All" }],
|
|
10
|
+
date: [],
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const [query, setQuery] = useState(initialQueryValues);
|
|
14
|
+
const [currentFilterQuery, setCurrentFilterQuery] = useState<Record<string, string>>({});
|
|
15
|
+
|
|
16
|
+
const setFilterQuery = (filterValues: Record<string, IQueryValue[]>) => {
|
|
17
|
+
const filterQuery = Object.fromEntries(
|
|
18
|
+
Object.entries(filterValues)
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
20
|
+
.filter(([_, arr]) => Array.isArray(arr) && arr.length > 0 && !(arr.length === 1 && arr[0].value === "all"))
|
|
21
|
+
.map(([key, arr]) => [key, arr.map((item) => item.value).join(",")])
|
|
22
|
+
);
|
|
23
|
+
setCurrentFilterQuery(filterQuery);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const setFiltersSelection = (pointer: string, filter: IQueryValue[]) => {
|
|
27
|
+
const { sites, users, eventTypes, contentTypes, date } = query;
|
|
28
|
+
const filterValues: Record<string, IQueryValue[]> = {
|
|
29
|
+
sites: pointer === "sites" ? filter : sites,
|
|
30
|
+
users: pointer === "users" ? filter : users,
|
|
31
|
+
eventTypes: pointer === "eventTypes" ? filter : eventTypes,
|
|
32
|
+
contentTypes: pointer === "contentTypes" ? filter : contentTypes,
|
|
33
|
+
date: pointer === "date" ? filter : date,
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
setQuery(filterValues);
|
|
37
|
+
setFilterQuery(filterValues);
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const resetFilterQuery = () => {
|
|
41
|
+
setQuery(initialQueryValues);
|
|
42
|
+
setCurrentFilterQuery({});
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
setFiltersSelection,
|
|
47
|
+
resetFilterQuery,
|
|
48
|
+
filterValues: query,
|
|
49
|
+
filterQuery: currentFilterQuery,
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export { useFilterQuery };
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
import React, { useCallback, useEffect, useRef, useState } from "react";
|
|
2
|
+
import { connect } from "react-redux";
|
|
3
|
+
import { format, subDays } from "date-fns";
|
|
4
|
+
|
|
5
|
+
import { LogActivityExportRequest, LogActivityPaginationRequest } from "@griddo/api-types";
|
|
6
|
+
import { ILogItemsByDay, ILogItemsByUser, IQueryValue, IRootState } from "@ax/types";
|
|
7
|
+
import { EmptyState, ErrorToast, FilterTagsBar, MainWrapper, SearchTagsBar, Select, TableList } from "@ax/components";
|
|
8
|
+
import { activityLogActions } from "@ax/containers/ActivityLog";
|
|
9
|
+
import { structuredDataActions } from "@ax/containers/StructuredData";
|
|
10
|
+
import { useModal } from "@ax/hooks";
|
|
11
|
+
|
|
12
|
+
import { useFilterQuery } from "./hooks";
|
|
13
|
+
import TableHeader from "./TableHeader";
|
|
14
|
+
import ItemLog from "./ItemLog";
|
|
15
|
+
import ItemLogUser from "./ItemLogUser";
|
|
16
|
+
import DownloadModal from "./DownloadModal";
|
|
17
|
+
|
|
18
|
+
import * as S from "./style";
|
|
19
|
+
|
|
20
|
+
const ActivityLog = (props: IActivityLogProps) => {
|
|
21
|
+
const {
|
|
22
|
+
activityLog,
|
|
23
|
+
listMode,
|
|
24
|
+
setListMode,
|
|
25
|
+
getActivityLog,
|
|
26
|
+
getActivityLogByUser,
|
|
27
|
+
downloadActivityLog,
|
|
28
|
+
getStructuredData,
|
|
29
|
+
} = props;
|
|
30
|
+
|
|
31
|
+
const itemsPerPage = 100;
|
|
32
|
+
const firstPage = 1;
|
|
33
|
+
const [page, setPage] = useState(firstPage);
|
|
34
|
+
const [isScrolling, setIsScrolling] = useState(false);
|
|
35
|
+
const [searchQuery, setSearchQuery] = useState<string>("");
|
|
36
|
+
const [isSortAscending, setIsSortAscending] = useState(false);
|
|
37
|
+
const initialState: IDownloadFormState = {
|
|
38
|
+
dateRange: "7",
|
|
39
|
+
startTime: null,
|
|
40
|
+
maxEvents: 0,
|
|
41
|
+
format: "csv",
|
|
42
|
+
startDate: null,
|
|
43
|
+
endDate: null,
|
|
44
|
+
};
|
|
45
|
+
const [downloadForm, setDownloadForm] = useState(initialState);
|
|
46
|
+
const { setFiltersSelection, resetFilterQuery, filterValues, filterQuery } = useFilterQuery();
|
|
47
|
+
const tableRef = useRef<HTMLDivElement>(null);
|
|
48
|
+
const { isOpen: isDownloadOpen, toggleModal: toggleDownloadModal } = useModal();
|
|
49
|
+
|
|
50
|
+
const { totalItems } = activityLog;
|
|
51
|
+
const isEmpty = totalItems === 0;
|
|
52
|
+
const isModeUser = listMode === "user";
|
|
53
|
+
const isSearching = searchQuery.length > 0;
|
|
54
|
+
|
|
55
|
+
const getParams = useCallback(() => {
|
|
56
|
+
const params: LogActivityPaginationRequest = {
|
|
57
|
+
page,
|
|
58
|
+
itemsPerPage,
|
|
59
|
+
...(isSortAscending && { order: "ASC" }),
|
|
60
|
+
...(searchQuery.length && { search: searchQuery }),
|
|
61
|
+
...filterQuery,
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
return params;
|
|
65
|
+
}, [page, filterQuery, isSortAscending, searchQuery]);
|
|
66
|
+
|
|
67
|
+
const handleGetLog = async () => {
|
|
68
|
+
const params = getParams();
|
|
69
|
+
if (isModeUser) {
|
|
70
|
+
await getActivityLogByUser(params);
|
|
71
|
+
} else {
|
|
72
|
+
await getActivityLog(params);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const handleUpdateStructuredDate = async () => await getStructuredData(null, null, false);
|
|
77
|
+
|
|
78
|
+
useEffect(() => {
|
|
79
|
+
handleGetLog();
|
|
80
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
81
|
+
}, [getParams]);
|
|
82
|
+
|
|
83
|
+
useEffect(() => {
|
|
84
|
+
handleUpdateStructuredDate();
|
|
85
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
86
|
+
}, []);
|
|
87
|
+
|
|
88
|
+
const onScroll = (e: any) => setIsScrolling(e.target.scrollTop > 0);
|
|
89
|
+
|
|
90
|
+
const handleSelectChange = async (value: string) => {
|
|
91
|
+
const params = getParams();
|
|
92
|
+
if (value === "user") {
|
|
93
|
+
await getActivityLogByUser({ ...params, page: firstPage });
|
|
94
|
+
} else {
|
|
95
|
+
await getActivityLog({ ...params, page: firstPage });
|
|
96
|
+
}
|
|
97
|
+
setListMode(value);
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const sortItems = async (isAscending: boolean) => {
|
|
101
|
+
setPage(firstPage);
|
|
102
|
+
setIsSortAscending(isAscending);
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const filterItems = async (filterPointer: string, filtersSelected: IQueryValue[]) => {
|
|
106
|
+
setPage(firstPage);
|
|
107
|
+
setFiltersSelection(filterPointer, filtersSelected);
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const handleDownloadLog = async () => {
|
|
111
|
+
const nowString = format(new Date(), "yyyy/MM/dd");
|
|
112
|
+
let startDate = nowString;
|
|
113
|
+
let endDate = nowString;
|
|
114
|
+
|
|
115
|
+
if (downloadForm.dateRange === "7") {
|
|
116
|
+
startDate = format(subDays(new Date(), 7), "yyyy/MM/dd");
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (downloadForm.dateRange === "30") {
|
|
120
|
+
startDate = format(subDays(new Date(), 30), "yyyy/MM/dd");
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (downloadForm.dateRange === "custom" && downloadForm.startDate && downloadForm.endDate) {
|
|
124
|
+
startDate = format(new Date(downloadForm.startDate), "yyyy/MM/dd");
|
|
125
|
+
endDate = format(new Date(downloadForm.endDate), "yyyy/MM/dd");
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const data: LogActivityExportRequest = {
|
|
129
|
+
dateRange: `${startDate}-${endDate}`,
|
|
130
|
+
startTime: downloadForm.startTime,
|
|
131
|
+
maxEvents: downloadForm.maxEvents ? downloadForm.maxEvents : null,
|
|
132
|
+
format: [downloadForm.format],
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
await downloadActivityLog(data);
|
|
136
|
+
|
|
137
|
+
toggleDownloadModal();
|
|
138
|
+
setDownloadForm(initialState);
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
const header = (
|
|
142
|
+
<TableHeader
|
|
143
|
+
isScrolling={isScrolling}
|
|
144
|
+
filterItems={filterItems}
|
|
145
|
+
filterValues={filterValues}
|
|
146
|
+
sortItems={sortItems}
|
|
147
|
+
isSortAscending={isSortAscending}
|
|
148
|
+
isModeUser={isModeUser}
|
|
149
|
+
/>
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
const pagination = {
|
|
153
|
+
setPage,
|
|
154
|
+
itemsPerPage,
|
|
155
|
+
totalItems,
|
|
156
|
+
currPage: page,
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
const rightButtonProps = {
|
|
160
|
+
label: "Refresh",
|
|
161
|
+
action: handleGetLog,
|
|
162
|
+
buttonStyle: "line",
|
|
163
|
+
icon: "refresh",
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
const rightLineButtonProps = {
|
|
167
|
+
label: "Download",
|
|
168
|
+
action: toggleDownloadModal,
|
|
169
|
+
buttonStyle: "text",
|
|
170
|
+
icon: "download",
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
const mainDownloadAction = { title: "Download", onClick: handleDownloadLog };
|
|
174
|
+
|
|
175
|
+
const selectOptions = [
|
|
176
|
+
{ value: "default", label: "Activity timeline" },
|
|
177
|
+
{ value: "user", label: "Grouped by user" },
|
|
178
|
+
];
|
|
179
|
+
|
|
180
|
+
const filterLabels = {
|
|
181
|
+
date: "Date",
|
|
182
|
+
users: "User",
|
|
183
|
+
sites: "Site",
|
|
184
|
+
contentTypes: "Content Type",
|
|
185
|
+
eventTypes: "Event",
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
const emptyProps = {
|
|
189
|
+
message: (
|
|
190
|
+
<>
|
|
191
|
+
You will start to see the User Activity Log when you
|
|
192
|
+
<br />
|
|
193
|
+
make some changes.
|
|
194
|
+
</>
|
|
195
|
+
),
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
const emptySearchStateProps = {
|
|
199
|
+
icon: "search",
|
|
200
|
+
title: "Oh! No Results Found",
|
|
201
|
+
message: "We couldn’t find what you are looking for. Please, try another search.",
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
return (
|
|
205
|
+
<MainWrapper
|
|
206
|
+
title="Logs"
|
|
207
|
+
rightButton={rightButtonProps}
|
|
208
|
+
rightLineButton={rightLineButtonProps}
|
|
209
|
+
searchAction={setSearchQuery}
|
|
210
|
+
searchValue={searchQuery}
|
|
211
|
+
>
|
|
212
|
+
<S.TableWrapper>
|
|
213
|
+
<ErrorToast />
|
|
214
|
+
<S.Intro>
|
|
215
|
+
<S.IntroContent>
|
|
216
|
+
<S.IntroTitle>User Activity Log</S.IntroTitle>
|
|
217
|
+
<div>
|
|
218
|
+
<strong>Track</strong> and record <strong>all actions performed by users</strong> on the Griddo. This
|
|
219
|
+
enables monitoring, and issue identification,
|
|
220
|
+
<br />
|
|
221
|
+
and ensures the security and integrity of content and data within the system.
|
|
222
|
+
<br />
|
|
223
|
+
For more details on each action, please refer to the Activity Log Glossary.
|
|
224
|
+
</div>
|
|
225
|
+
</S.IntroContent>
|
|
226
|
+
<S.SelectWrapper>
|
|
227
|
+
<Select
|
|
228
|
+
name="visualSelect"
|
|
229
|
+
value={listMode}
|
|
230
|
+
options={selectOptions}
|
|
231
|
+
onChange={handleSelectChange}
|
|
232
|
+
mandatory={true}
|
|
233
|
+
/>
|
|
234
|
+
</S.SelectWrapper>
|
|
235
|
+
</S.Intro>
|
|
236
|
+
<TableList
|
|
237
|
+
tableHeader={header}
|
|
238
|
+
onScroll={onScroll}
|
|
239
|
+
pagination={pagination}
|
|
240
|
+
hasFixedHeader={true}
|
|
241
|
+
tableRef={tableRef}
|
|
242
|
+
>
|
|
243
|
+
<S.SearchTags>
|
|
244
|
+
<SearchTagsBar query={searchQuery} setQuery={setSearchQuery} />
|
|
245
|
+
<FilterTagsBar
|
|
246
|
+
filters={filterValues}
|
|
247
|
+
setFilters={setFiltersSelection}
|
|
248
|
+
resetFilters={resetFilterQuery}
|
|
249
|
+
labels={filterLabels}
|
|
250
|
+
/>
|
|
251
|
+
</S.SearchTags>
|
|
252
|
+
{isEmpty ? (
|
|
253
|
+
<S.EmptyWrapper>
|
|
254
|
+
{isSearching && <EmptyState {...emptySearchStateProps} />}
|
|
255
|
+
{!isSearching && <EmptyState {...emptyProps} />}
|
|
256
|
+
</S.EmptyWrapper>
|
|
257
|
+
) : (
|
|
258
|
+
<>
|
|
259
|
+
{isModeUser
|
|
260
|
+
? (activityLog as ILogItemsByUser).items.map((item) => (
|
|
261
|
+
<ItemLogUser key={item.date} items={item} getLog={handleGetLog} />
|
|
262
|
+
))
|
|
263
|
+
: (activityLog as ILogItemsByDay).items.map((item) => (
|
|
264
|
+
<ItemLog key={item.date} items={item} getLog={handleGetLog} />
|
|
265
|
+
))}
|
|
266
|
+
</>
|
|
267
|
+
)}
|
|
268
|
+
</TableList>
|
|
269
|
+
</S.TableWrapper>
|
|
270
|
+
<DownloadModal
|
|
271
|
+
isOpen={isDownloadOpen}
|
|
272
|
+
toggleModal={toggleDownloadModal}
|
|
273
|
+
mainModalAction={mainDownloadAction}
|
|
274
|
+
form={downloadForm}
|
|
275
|
+
setForm={setDownloadForm}
|
|
276
|
+
/>
|
|
277
|
+
</MainWrapper>
|
|
278
|
+
);
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
export interface IDownloadFormState {
|
|
282
|
+
dateRange: string;
|
|
283
|
+
startTime: string | null;
|
|
284
|
+
maxEvents: number | null;
|
|
285
|
+
format: string;
|
|
286
|
+
startDate: string | null;
|
|
287
|
+
endDate: string | null;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
interface IActivityLogProps {
|
|
291
|
+
activityLog: ILogItemsByDay | ILogItemsByUser;
|
|
292
|
+
listMode: string;
|
|
293
|
+
getActivityLog(params: LogActivityPaginationRequest): Promise<void>;
|
|
294
|
+
getActivityLogByUser(params: LogActivityPaginationRequest): Promise<void>;
|
|
295
|
+
setListMode(listMode: string): void;
|
|
296
|
+
downloadActivityLog(data: LogActivityExportRequest): Promise<void>;
|
|
297
|
+
getStructuredData(token: string | null, siteID?: number | null, hasLoading?: boolean): Promise<void>;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
const mapStateToProps = (state: IRootState) => ({
|
|
301
|
+
activityLog: state.activityLog.activityLog,
|
|
302
|
+
listMode: state.activityLog.listMode,
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
const mapDispatchToProps = {
|
|
306
|
+
getActivityLog: activityLogActions.getActivityLog,
|
|
307
|
+
getActivityLogByUser: activityLogActions.getActivityLogByUser,
|
|
308
|
+
setListMode: activityLogActions.setListMode,
|
|
309
|
+
downloadActivityLog: activityLogActions.downloadActivityLog,
|
|
310
|
+
getStructuredData: structuredDataActions.getStructuredData,
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
export default connect(mapStateToProps, mapDispatchToProps)(ActivityLog);
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import styled from "styled-components";
|
|
2
|
+
|
|
3
|
+
const TableWrapper = styled.div`
|
|
4
|
+
display: flex;
|
|
5
|
+
flex-direction: column;
|
|
6
|
+
width: 100%;
|
|
7
|
+
position: relative;
|
|
8
|
+
height: calc(100vh - ${(p) => p.theme.spacing.xl});
|
|
9
|
+
overflow: auto;
|
|
10
|
+
`;
|
|
11
|
+
|
|
12
|
+
const EmptyWrapper = styled.div`
|
|
13
|
+
height: ${(p) => `calc(100vh - (${p.theme.spacing.xl} * 3))`};
|
|
14
|
+
display: flex;
|
|
15
|
+
align-items: center;
|
|
16
|
+
`;
|
|
17
|
+
|
|
18
|
+
const Intro = styled.div`
|
|
19
|
+
display: flex;
|
|
20
|
+
flex-direction: row;
|
|
21
|
+
padding: ${(p) => p.theme.spacing.m};
|
|
22
|
+
border-bottom: 1px solid ${(p) => p.theme.color.uiLine};
|
|
23
|
+
margin-bottom: ${(p) => p.theme.spacing.xs};
|
|
24
|
+
`;
|
|
25
|
+
|
|
26
|
+
const IntroContent = styled.div`
|
|
27
|
+
${(p) => p.theme.textStyle.uiM};
|
|
28
|
+
color: ${(p) => p.theme.color.textMediumEmphasis};
|
|
29
|
+
flex-grow: 1;
|
|
30
|
+
`;
|
|
31
|
+
|
|
32
|
+
const IntroTitle = styled.div`
|
|
33
|
+
${(p) => p.theme.textStyle.headingM};
|
|
34
|
+
color: ${(p) => p.theme.color.textHighEmphasis};
|
|
35
|
+
margin-bottom: ${(p) => p.theme.spacing.xs};
|
|
36
|
+
`;
|
|
37
|
+
|
|
38
|
+
const SelectWrapper = styled.div`
|
|
39
|
+
displa: flex;
|
|
40
|
+
width: 196px;
|
|
41
|
+
align-content: center;
|
|
42
|
+
`;
|
|
43
|
+
|
|
44
|
+
const SearchTags = styled.div`
|
|
45
|
+
& > div:nth-child(1) {
|
|
46
|
+
margin-bottom: ${(p) => p.theme.spacing.xs};
|
|
47
|
+
}
|
|
48
|
+
& > div:nth-child(2) {
|
|
49
|
+
margin-bottom: ${(p) => p.theme.spacing.xs};
|
|
50
|
+
}
|
|
51
|
+
`;
|
|
52
|
+
|
|
53
|
+
const ModalContent = styled.div`
|
|
54
|
+
padding: ${(p) => `${p.theme.spacing.xs} ${p.theme.spacing.m}`};
|
|
55
|
+
`;
|
|
56
|
+
|
|
57
|
+
export { TableWrapper, EmptyWrapper, Intro, IntroContent, IntroTitle, SelectWrapper, SearchTags, ModalContent };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { pages, structuredData } from "@ax/api";
|
|
2
|
+
import { isReqOk } from "@ax/helpers";
|
|
3
|
+
import { IPage, IStructuredDataContent } from "@ax/types";
|
|
4
|
+
|
|
5
|
+
const getPageSchemaVersion = async (id: number) => {
|
|
6
|
+
try {
|
|
7
|
+
const result = await pages.getPageInfo(id);
|
|
8
|
+
if (result && isReqOk(result.status)) {
|
|
9
|
+
const page: IPage = result.data;
|
|
10
|
+
return page.schemaVersionTimestamp;
|
|
11
|
+
}
|
|
12
|
+
} catch (e) {
|
|
13
|
+
console.log(e);
|
|
14
|
+
}
|
|
15
|
+
return undefined;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const getContentTypeSchemaVersion = async (id: number) => {
|
|
19
|
+
try {
|
|
20
|
+
const result = await structuredData.getDataContent(id, null);
|
|
21
|
+
if (result && isReqOk(result.status)) {
|
|
22
|
+
const data: IStructuredDataContent = result.data;
|
|
23
|
+
return data.schemaVersionTimestamp;
|
|
24
|
+
}
|
|
25
|
+
} catch (e) {
|
|
26
|
+
console.log(e);
|
|
27
|
+
}
|
|
28
|
+
return undefined;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export { getPageSchemaVersion, getContentTypeSchemaVersion };
|
|
@@ -94,7 +94,7 @@ const CategoriesList = (props: IProps): JSX.Element => {
|
|
|
94
94
|
const currentCategories = categories[scope].sort(sortBy("title", false));
|
|
95
95
|
const isEmpty = currentDataContent && currentDataContent.length === 0;
|
|
96
96
|
const hasCategories = currentCategories.length > 0;
|
|
97
|
-
const categoryName = currentStructuredData && currentStructuredData.title;
|
|
97
|
+
const categoryName = (currentStructuredData && currentStructuredData.title) || "";
|
|
98
98
|
const availableLanguages = currentSiteID ? siteLanguages : globalLangs;
|
|
99
99
|
const isTranslatable = currentStructuredData ? currentStructuredData.translate : true;
|
|
100
100
|
const indentationWidth = 35;
|
|
@@ -16,6 +16,7 @@ export const Form = (props: IFormProps): JSX.Element => {
|
|
|
16
16
|
theme,
|
|
17
17
|
headerHeight,
|
|
18
18
|
errors,
|
|
19
|
+
isDisabled,
|
|
19
20
|
setSelectedTab,
|
|
20
21
|
setHistoryPush,
|
|
21
22
|
setErrors,
|
|
@@ -45,6 +46,7 @@ export const Form = (props: IFormProps): JSX.Element => {
|
|
|
45
46
|
setHistoryPush={setHistoryPush}
|
|
46
47
|
errors={errors}
|
|
47
48
|
setErrors={setErrors}
|
|
49
|
+
isReadOnly={isDisabled}
|
|
48
50
|
/>
|
|
49
51
|
);
|
|
50
52
|
};
|
|
@@ -86,6 +88,7 @@ export interface IFormProps {
|
|
|
86
88
|
headerHeight: number;
|
|
87
89
|
errors: IErrorItem[];
|
|
88
90
|
setErrors(errors: IErrorItem[]): void;
|
|
91
|
+
isDisabled: boolean;
|
|
89
92
|
}
|
|
90
93
|
|
|
91
94
|
export default Form;
|
|
@@ -25,6 +25,7 @@ const FormConfigPanel = (props: IStateProps): JSX.Element => {
|
|
|
25
25
|
selectedParent,
|
|
26
26
|
errors,
|
|
27
27
|
setErrors,
|
|
28
|
+
isDisabled,
|
|
28
29
|
} = props;
|
|
29
30
|
|
|
30
31
|
const wrapperRef = useRef<HTMLDivElement>(null);
|
|
@@ -66,6 +67,7 @@ const FormConfigPanel = (props: IStateProps): JSX.Element => {
|
|
|
66
67
|
headerHeight={headerHeight}
|
|
67
68
|
errors={errors}
|
|
68
69
|
setErrors={setErrors}
|
|
70
|
+
isDisabled={isDisabled}
|
|
69
71
|
/>
|
|
70
72
|
</S.Wrapper>
|
|
71
73
|
);
|
|
@@ -87,6 +89,7 @@ export interface IStateProps {
|
|
|
87
89
|
selectedParent: Record<string, unknown> | null;
|
|
88
90
|
errors: IErrorItem[];
|
|
89
91
|
setErrors(errors: IErrorItem[]): void;
|
|
92
|
+
isDisabled: boolean;
|
|
90
93
|
}
|
|
91
94
|
|
|
92
95
|
export default FormConfigPanel;
|
|
@@ -22,6 +22,7 @@ const Editor = (props: IProps) => {
|
|
|
22
22
|
selectedParent,
|
|
23
23
|
errors,
|
|
24
24
|
template,
|
|
25
|
+
isDisabled,
|
|
25
26
|
setErrors,
|
|
26
27
|
setNotification,
|
|
27
28
|
setSelectedTab,
|
|
@@ -84,7 +85,7 @@ const Editor = (props: IProps) => {
|
|
|
84
85
|
<ResizePanel
|
|
85
86
|
leftPanel={
|
|
86
87
|
<S.EditorWrapper>
|
|
87
|
-
{hasFieldArrays && (
|
|
88
|
+
{hasFieldArrays && !isDisabled && (
|
|
88
89
|
<SideModal
|
|
89
90
|
onClick={handleClick}
|
|
90
91
|
theme={theme}
|
|
@@ -93,7 +94,7 @@ const Editor = (props: IProps) => {
|
|
|
93
94
|
selectField={handleSetSelectedField}
|
|
94
95
|
/>
|
|
95
96
|
)}
|
|
96
|
-
<PageBrowser isReadOnly={
|
|
97
|
+
<PageBrowser isReadOnly={isDisabled} theme={theme} browserRef={browserRef} />
|
|
97
98
|
</S.EditorWrapper>
|
|
98
99
|
}
|
|
99
100
|
rightPanel={
|
|
@@ -110,6 +111,7 @@ const Editor = (props: IProps) => {
|
|
|
110
111
|
selectedParent={selectedParent}
|
|
111
112
|
errors={errors}
|
|
112
113
|
setErrors={setErrors}
|
|
114
|
+
isDisabled={isDisabled}
|
|
113
115
|
/>
|
|
114
116
|
}
|
|
115
117
|
full={true}
|
|
@@ -140,6 +142,7 @@ interface IPageBrowserDispatchProps {
|
|
|
140
142
|
theme: string;
|
|
141
143
|
browserRef: React.RefObject<HTMLDivElement>;
|
|
142
144
|
errors: IErrorItem[];
|
|
145
|
+
isDisabled: boolean;
|
|
143
146
|
setErrors(errors: IErrorItem[]): void;
|
|
144
147
|
}
|
|
145
148
|
|