@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.
Files changed (95) hide show
  1. package/package.json +3 -2
  2. package/src/GlobalStore.tsx +3 -0
  3. package/src/api/index.tsx +4 -0
  4. package/src/api/logs.tsx +97 -0
  5. package/src/api/navigation.tsx +1 -1
  6. package/src/api/pages.tsx +1 -1
  7. package/src/api/schemas.tsx +18 -0
  8. package/src/api/users.tsx +17 -0
  9. package/src/components/ConfigPanel/Form/ConnectedField/NavConnectedField/index.tsx +3 -2
  10. package/src/components/ConfigPanel/Form/index.tsx +3 -1
  11. package/src/components/ConfigPanel/index.tsx +3 -0
  12. package/src/components/Fields/SummaryButton/index.tsx +6 -4
  13. package/src/components/Fields/TimeField/style.tsx +0 -1
  14. package/src/components/Fields/TranslateButton/index.tsx +3 -0
  15. package/src/components/FloatingMenu/index.tsx +25 -1
  16. package/src/components/FloatingMenu/style.tsx +3 -2
  17. package/src/components/LanguageMenu/index.tsx +1 -1
  18. package/src/components/MainWrapper/AppBar/index.tsx +4 -3
  19. package/src/components/RestoreModal/index.tsx +51 -0
  20. package/src/components/RestoreModal/style.tsx +7 -0
  21. package/src/components/SearchField/index.tsx +1 -1
  22. package/src/components/SearchField/style.tsx +4 -4
  23. package/src/components/TableFilters/CheckGroupFilter/index.tsx +42 -5
  24. package/src/components/TableFilters/CheckGroupFilter/style.tsx +8 -1
  25. package/src/components/TableFilters/SiteFilter/index.tsx +26 -57
  26. package/src/components/Tag/index.tsx +6 -3
  27. package/src/components/Tag/style.tsx +2 -2
  28. package/src/components/index.tsx +2 -0
  29. package/src/containers/ActivityLog/actions.tsx +262 -0
  30. package/src/containers/ActivityLog/constants.tsx +6 -0
  31. package/src/containers/ActivityLog/index.tsx +4 -0
  32. package/src/containers/ActivityLog/interfaces.tsx +12 -0
  33. package/src/containers/ActivityLog/reducer.tsx +25 -0
  34. package/src/containers/Navigation/Defaults/actions.tsx +4 -3
  35. package/src/containers/StructuredData/actions.tsx +7 -4
  36. package/src/containers/StructuredData/interfaces.tsx +2 -8
  37. package/src/containers/StructuredData/reducer.tsx +2 -8
  38. package/src/containers/Users/actions.tsx +22 -19
  39. package/src/modules/ActivityLog/DetailModal/index.tsx +108 -0
  40. package/src/modules/ActivityLog/DetailModal/style.tsx +52 -0
  41. package/src/modules/ActivityLog/DownloadModal/index.tsx +104 -0
  42. package/src/modules/ActivityLog/DownloadModal/style.tsx +12 -0
  43. package/src/modules/ActivityLog/ItemGroup/index.tsx +27 -0
  44. package/src/modules/ActivityLog/ItemGroup/style.tsx +39 -0
  45. package/src/modules/ActivityLog/ItemLog/EventItem/index.tsx +167 -0
  46. package/src/modules/ActivityLog/ItemLog/EventItem/style.tsx +79 -0
  47. package/src/modules/ActivityLog/ItemLog/index.tsx +24 -0
  48. package/src/modules/ActivityLog/ItemLogUser/UserItem/EventItem/index.tsx +170 -0
  49. package/src/modules/ActivityLog/ItemLogUser/UserItem/EventItem/style.tsx +79 -0
  50. package/src/modules/ActivityLog/ItemLogUser/UserItem/index.tsx +46 -0
  51. package/src/modules/ActivityLog/ItemLogUser/UserItem/style.tsx +60 -0
  52. package/src/modules/ActivityLog/ItemLogUser/index.tsx +25 -0
  53. package/src/modules/ActivityLog/LogFilters/ContentFilter/index.tsx +79 -0
  54. package/src/modules/ActivityLog/LogFilters/DateFilter/index.tsx +91 -0
  55. package/src/modules/ActivityLog/LogFilters/DateFilter/style.tsx +208 -0
  56. package/src/modules/ActivityLog/LogFilters/EventFilter/index.tsx +80 -0
  57. package/src/modules/ActivityLog/LogFilters/OrderFilter/index.tsx +49 -0
  58. package/src/modules/ActivityLog/LogFilters/OrderFilter/style.tsx +35 -0
  59. package/src/modules/ActivityLog/LogFilters/UserFilter/index.tsx +79 -0
  60. package/src/modules/ActivityLog/TableHeader/index.tsx +72 -0
  61. package/src/modules/ActivityLog/TableHeader/style.tsx +73 -0
  62. package/src/modules/ActivityLog/constants.tsx +10 -0
  63. package/src/modules/ActivityLog/hooks.tsx +53 -0
  64. package/src/modules/ActivityLog/index.tsx +313 -0
  65. package/src/modules/ActivityLog/style.tsx +57 -0
  66. package/src/modules/ActivityLog/utils.tsx +31 -0
  67. package/src/modules/Categories/CategoriesList/index.tsx +1 -1
  68. package/src/modules/Forms/FormEditor/Editor/FormConfigPanel/Form/index.tsx +3 -0
  69. package/src/modules/Forms/FormEditor/Editor/FormConfigPanel/index.tsx +3 -0
  70. package/src/modules/Forms/FormEditor/Editor/index.tsx +5 -2
  71. package/src/modules/Forms/FormEditor/index.tsx +20 -3
  72. package/src/modules/GlobalEditor/Editor/index.tsx +3 -0
  73. package/src/modules/GlobalEditor/index.tsx +48 -9
  74. package/src/modules/Navigation/Defaults/DefaultsEditor/Editor/DefaultsBrowser/index.tsx +3 -1
  75. package/src/modules/Navigation/Defaults/DefaultsEditor/Editor/index.tsx +4 -1
  76. package/src/modules/Navigation/Defaults/DefaultsEditor/index.tsx +45 -6
  77. package/src/modules/PageEditor/Editor/index.tsx +4 -1
  78. package/src/modules/PageEditor/index.tsx +46 -7
  79. package/src/modules/Redirects/BulkHeader/TableHeader/style.tsx +1 -7
  80. package/src/modules/StructuredData/Form/index.tsx +56 -7
  81. package/src/modules/StructuredData/StructuredDataList/BulkHeader/TableHeader/index.tsx +2 -2
  82. package/src/modules/StructuredData/StructuredDataList/BulkHeader/index.tsx +2 -8
  83. package/src/modules/StructuredData/StructuredDataList/hooks.tsx +9 -9
  84. package/src/modules/StructuredData/StructuredDataList/index.tsx +3 -4
  85. package/src/modules/Users/Roles/index.tsx +0 -2
  86. package/src/modules/Users/UserEdit/index.tsx +12 -28
  87. package/src/modules/Users/UserList/BulkHeader/TableHeader/style.tsx +1 -0
  88. package/src/modules/Users/UserList/UserItem/index.tsx +10 -25
  89. package/src/modules/Users/UserList/index.tsx +8 -10
  90. package/src/routes/multisite.tsx +9 -0
  91. package/src/themes/theme.json +2 -1
  92. package/src/types/forms.tsx +1 -0
  93. package/src/types/index.tsx +8 -0
  94. package/src/types/logs.tsx +12 -0
  95. 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={false} theme={theme} browserRef={browserRef} />
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