@raketa-cloud/admin 0.0.97 → 0.0.98

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 (39) hide show
  1. package/package.json +1 -1
  2. package/src/Adapter.js +3 -1
  3. package/src/cloud/ArticleChanges.js +24 -3
  4. package/src/cloud/EventChanges.js +24 -3
  5. package/src/cloud/PageChanges.js +24 -3
  6. package/src/cloud/Pages.js +1 -1
  7. package/src/cloud/documents/articlesDocuments.js +18 -5
  8. package/src/cloud/documents/common.js +2 -0
  9. package/src/cloud/documents/eventsDocuments.js +17 -4
  10. package/src/cloud/documents/pagesDocuments.js +17 -4
  11. package/src/handlers/articles/ArticlesHandler.js +2 -2
  12. package/src/handlers/articles/HistoryHandler.js +31 -0
  13. package/src/handlers/events/EventsHandler.js +2 -2
  14. package/src/handlers/events/HistoryHandler.js +31 -0
  15. package/src/handlers/pages/HistoryHandler.js +31 -0
  16. package/src/handlers/pages/PagesHandler.js +2 -2
  17. package/src/helpers/historyUtils.js +133 -0
  18. package/src/routeArticlesModule.js +19 -13
  19. package/src/routeEventsModule.js +18 -12
  20. package/src/routePagesModule.js +7 -1
  21. package/src/tests/handlers/articles/ArticlesHandler.test/show.test.js +5 -5
  22. package/src/tests/handlers/articles/ArticlesHistoryHandler.test/index.test.js +87 -0
  23. package/src/tests/handlers/events/EventsHandler.test/show.test.js +5 -5
  24. package/src/tests/handlers/events/EventsHistoryHandler.test/index.test.js +87 -0
  25. package/src/tests/handlers/pages/PagesHandler.test/show.test.js +5 -5
  26. package/src/tests/handlers/pages/PagesHistoryHandler.test/index.test.js +87 -0
  27. package/src/tests/helpers/historyUtils.test.js +107 -0
  28. package/src/views/articles/_shared/_history_toolbar.ejs +9 -8
  29. package/src/views/articles/_shared/history_table.ejs +68 -0
  30. package/src/views/articles/history/index.ejs +87 -0
  31. package/src/views/articles/show.ejs +12 -52
  32. package/src/views/events/_shared/_history_toolbar.ejs +9 -8
  33. package/src/views/events/_shared/history_table.ejs +68 -0
  34. package/src/views/events/history/index.ejs +87 -0
  35. package/src/views/events/show.ejs +12 -52
  36. package/src/views/pages/_shared/_history_toolbar.ejs +8 -7
  37. package/src/views/pages/_shared/history_table.ejs +68 -0
  38. package/src/views/pages/history/index.ejs +87 -0
  39. package/src/views/pages/show.ejs +12 -52
@@ -0,0 +1,87 @@
1
+ <div class="page-wrapper">
2
+ <div class="page-title">
3
+ <div>
4
+ <h1 class="heading-1">Articles / History of changes</h1>
5
+ <span class="body-2 opacity-50"><%= %></span>
6
+ </div>
7
+
8
+ <div class="actions-toolbar">
9
+ <a href="<%= `/${_context.locale}/${_context.resourceConfig.articleTypePlural}/${resource.id}` %>" class="btn-text">Back</a>
10
+ <button type="button" data-toggle-sidebar="1" class="p-2.5 rounded hover:bg-neutral-200 transition-all duration-300 ease-in-out dark:hover:bg-neutral-700">
11
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-4">
12
+ <path stroke-linecap="round" stroke-linejoin="round" d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z" />
13
+ </svg>
14
+ </button>
15
+ </div>
16
+ </div>
17
+
18
+ <%- render_partial('../_shared/history_table.ejs', {
19
+ changes,
20
+ resource,
21
+ _context,
22
+ render_partial,
23
+ skipPagination: false,
24
+ toolbarPath: '../_shared/_history_toolbar.ejs'
25
+ }) %>
26
+
27
+ </div>
28
+
29
+ <div data-sidebar="1" class="search-sidebar <%= Object.keys(_context.query).some(k => k.startsWith('f:')) ? '' : 'hidden' %>">
30
+ <span class="heading-2">Search by</span>
31
+
32
+ <form action="<%= `/${_context.locale}/${_context.resourceConfig.articleTypePlural}/${resource.id}/history` %>" method="GET" class="form mt-4">
33
+ <input type="hidden" name="order_direction" value="<%= _context.query.order_direction %>" />
34
+ <input type="hidden" name="order_by" value="<%= _context.query.order_by %>" />
35
+
36
+ <div class="mb-4">
37
+ <label for="date_from" class="font-semibold hover:cursor-pointer body-3">From</label>
38
+ <input type="date" name="f:date_from" value="<%= _context.query["f:date_from"] %>" />
39
+ </div>
40
+
41
+ <div class="mb-4">
42
+ <label for="date_to" class="font-semibold hover:cursor-pointer body-3">To</label>
43
+ <input type="date" name="f:date_to" value="<%= _context.query["f:date_to"] %>" />
44
+ </div>
45
+
46
+ <div class="mb-4">
47
+ <%- f.field('f:operator', {
48
+ as: 'select',
49
+ options: editors.map(editor => [editor.id, editor.name]),
50
+ label: "Editor",
51
+ include_blank: 'All Editors',
52
+ value: _context.query["f:operator"]
53
+ }) %>
54
+ </div>
55
+
56
+ <div class="mb-4">
57
+ <label for="" class="font-semibold hover:cursor-pointer body-3">Changes</label>
58
+ <div class="checkbox-group mb-4">
59
+ <% Object.entries(history.changeTypes(_context.resourceConfig.articleType)).forEach(([key, {label}])=> { %>
60
+ <div class="flex items-center gap-1">
61
+ <% if (Array.from(_context.query["f:change_type"] || []).includes(key)) { %>
62
+ <input type="checkbox" name="f:change_type" id='change-<%= key %>' checked value="<%= key %>" class="hover:cursor-pointer">
63
+ <% } else { %>
64
+ <input type="checkbox" name="f:change_type" id='change-<%= key %>' value="<%= key %>" class="hover:cursor-pointer">
65
+ <% } %>
66
+ <label for='change-<%= key %>' class="body-2 hover:cursor-pointer">
67
+ <%= label %>
68
+ </label>
69
+ </div>
70
+ <% }); %>
71
+ </div>
72
+ </div>
73
+
74
+ <div class="btn-toolbar">
75
+ <button type="submit" class="btn-primary">Search</button>
76
+ <a href="<%= `/${_context.locale}/${_context.resourceConfig.articleTypePlural}/${resource.id}/history` %>" class="btn-text">Clear search</a>
77
+ </div>
78
+ </form>
79
+ </div>
80
+
81
+ <script>
82
+ const sidebar = document.querySelector("[data-sidebar]");
83
+ const searchToggle = document.querySelector('[data-toggle-sidebar]');
84
+ searchToggle.addEventListener('click', () => {
85
+ sidebar.classList.toggle('hidden');
86
+ });
87
+ </script>
@@ -218,57 +218,17 @@
218
218
  History of changes
219
219
  </h4>
220
220
 
221
- <table class="data-grid">
222
- <thead>
223
- <tr>
224
- <th>Title</th>
225
- <th>Date of change</th>
226
- <th>Published by</th>
227
- <th>&nbsp;</th>
228
- </tr>
229
- </thead>
230
-
231
- <tbody>
232
- <% const maxVersion = Math.max(...changes.map((ch) => ch.version)); %>
233
- <% changes.forEach((change, idx)=> { %>
234
- <tr class="border-b border-mono-25">
235
- <td class="py-4 pl-2">
236
- <div class="flex items-center gap-2">
237
- <%= [change.title, change.description].filter(Boolean).join(": ") %>
238
-
239
- <% if (change.source === "revert") { %>
240
- <img src="/static/_assets/revert.svg" alt="Revert version" class="size-4">
241
- <% } %>
242
- </div>
243
- </td>
244
-
245
- <td class="whitespace-nowrap">
246
- <div class="body-3 text-raketa-foreground/50">
247
- <div class="flex items-center gap-1">
248
- <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-4 text-raketa-foreground">
249
- <path stroke-linecap="round" stroke-linejoin="round" d="M12 6v6h4.5m4.5 0a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />
250
- </svg>
251
-
252
- <time data-pretty-datetime datetime="<%= change.insertedAt %>"><%= change.insertedAt %></time>
253
- </div>
254
- </div>
255
- </td>
256
-
257
- <td class="whitespace-nowrap">
258
- <div class="body-3 text-raketa-foreground/50">
259
- <div class="flex items-center gap-1" title="<%= change.operatorMeta.name %>">
260
- <img src="<%= change.operatorMeta.avatar %>" class="size-4 rounded-full">
261
- <%= change.operatorMeta.name %>
262
- </div>
263
- </div>
264
- </td>
265
-
266
- <td>
267
- <%- render_partial('./_shared/_history_toolbar.ejs', { maxVersion, change }) %>
268
- </td>
269
- </tr>
270
- <% }); %>
271
- </tbody>
272
- </table>
221
+ <%- render_partial('./_shared/history_table.ejs', {
222
+ changes,
223
+ resource,
224
+ _context,
225
+ render_partial,
226
+ skipPagination: true,
227
+ toolbarPath: './_shared/_history_toolbar.ejs'
228
+ }) %>
229
+
230
+ <a href="<%= `/${_context.locale}/${_context.resourceConfig.articleTypePlural}/${resource.id}/history` %>" class="btn-text ml-2 my-8">
231
+ Full page history
232
+ </a>
273
233
  </div>
274
234
  </div>
@@ -1,16 +1,17 @@
1
1
  <div class="actions-toolbar justify-end">
2
- <% if (maxVersion !== change.version) { %>
3
- <form method="POST" action="<%= `/${_context.locale}/${_context.resourceConfig.eventTypePlural}/${resource.id}/event_changes/reverts` %>" class="inline-block">
4
- <input type="hidden" name="version" value=<%= change.version %>>
5
- <button type="submit" class="btn-text has-icon">
6
- <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-4">
7
- <path stroke-linecap="round" stroke-linejoin="round" d="M9 15 3 9m0 0 6-6M3 9h12a6 6 0 0 1 0 12h-3" />
8
- </svg>
2
+ <form method="POST" action="<%= `/${_context.locale}/${_context.resourceConfig.pageTypePlural}/${resource.id}/${_context.resourceConfig.pageType}_changes/reverts` %>" class="inline-block">
3
+ <input type="hidden" name="version" value="<%= change.version %>">
9
4
 
5
+ <% if (history.isChangeRevertable(change, maxVersion)) { %>
6
+ <button type="submit" class="btn-text">
10
7
  Revert
11
8
  </button>
9
+ <% } else { %>
10
+ <button type="submit" disabled class="btn-text opacity-50 cursor-not-allowed">
11
+ Revert
12
+ </button>
13
+ <% } %>
12
14
  </form>
13
- <% } %>
14
15
 
15
16
  <a href="/remote/login?redirect_to=/<%= _context.locale %>/admin/<%= _context.resourceConfig.eventTypePlural %>/<%= resource.id %>/changes/<%= change.version %>" class="btn-text has-icon">
16
17
  <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-4">
@@ -0,0 +1,68 @@
1
+ <% const maxVersion = history.getMaxVersion(changes); %>
2
+
3
+ <div class="history-table-wrapper">
4
+ <table class="data-grid">
5
+ <thead>
6
+ <tr>
7
+ <th>#</th>
8
+ <th>Date of change</th>
9
+ <th>Editor</th>
10
+ <th>Action</th>
11
+ <th>Reason</th>
12
+ <th>&nbsp;</th>
13
+ </tr>
14
+ </thead>
15
+
16
+ <tbody>
17
+ <% changes.list.forEach((change)=> { %>
18
+ <tr class="border-b border-mono-25">
19
+ <td class="py-4 pl-2">
20
+ <div class="flex items-center gap-2">
21
+ <%= change.version %>
22
+ </div>
23
+ </td>
24
+
25
+ <td class="whitespace-nowrap">
26
+ <div class="body-3 text-raketa-foreground/50">
27
+ <div class="flex items-center gap-1">
28
+ <time data-pretty-datetime datetime="<%= change.insertedAt %>"><%= change.insertedAt %></time>
29
+ </div>
30
+ </div>
31
+ </td>
32
+
33
+ <td class="whitespace-nowrap">
34
+ <div class="body-3 text-raketa-foreground/50">
35
+ <div class="flex items-center gap-1" title="<%= change.operatorMeta.name %>">
36
+ <% if (change.operatorMeta.avatar) { %>
37
+ <img src="<%= change.operatorMeta.avatar %>" class="size-4 rounded-full">
38
+ <% } %>
39
+
40
+ <%= change.operatorMeta.name %>
41
+ </div>
42
+ </div>
43
+ </td>
44
+
45
+ <td class="py-4 pl-2">
46
+ <div class="flex items-center gap-2">
47
+ <%= history.changeAction(change, _context.resourceConfig.eventType) %>
48
+ </div>
49
+ </td>
50
+
51
+ <td class="py-4 pl-2">
52
+ <div class="flex items-center gap-2">
53
+ <%= history.changeReason(change) %>
54
+ </div>
55
+ </td>
56
+
57
+ <td>
58
+ <%- render_partial(toolbarPath, { maxVersion, change }) %>
59
+ </td>
60
+ </tr>
61
+ <% }); %>
62
+ </tbody>
63
+ </table>
64
+
65
+ <% if (!skipPagination) { %>
66
+ <%- pagination(changes.pagination, _context) %>
67
+ <% } %>
68
+ </div>
@@ -0,0 +1,87 @@
1
+ <div class="page-wrapper">
2
+ <div class="page-title">
3
+ <div>
4
+ <h1 class="heading-1">Events / History of changes</h1>
5
+ <span class="body-2 opacity-50"><%= %></span>
6
+ </div>
7
+
8
+ <div class="actions-toolbar">
9
+ <a href="<%= `/${_context.locale}/${_context.resourceConfig.eventTypePlural}/${resource.id}` %>" class="btn-text">Back</a>
10
+ <button type="button" data-toggle-sidebar="1" class="p-2.5 rounded hover:bg-neutral-200 transition-all duration-300 ease-in-out dark:hover:bg-neutral-700">
11
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-4">
12
+ <path stroke-linecap="round" stroke-linejoin="round" d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z" />
13
+ </svg>
14
+ </button>
15
+ </div>
16
+ </div>
17
+
18
+ <%- render_partial('../_shared/history_table.ejs', {
19
+ changes,
20
+ resource,
21
+ _context,
22
+ render_partial,
23
+ skipPagination: false,
24
+ toolbarPath: '../_shared/_history_toolbar.ejs'
25
+ }) %>
26
+
27
+ </div>
28
+
29
+ <div data-sidebar="1" class="search-sidebar <%= Object.keys(_context.query).some(k => k.startsWith('f:')) ? '' : 'hidden' %>">
30
+ <span class="heading-2">Search by</span>
31
+
32
+ <form action="<%= `/${_context.locale}/${_context.resourceConfig.eventTypePlural}/${resource.id}/history` %>" method="GET" class="form mt-4">
33
+ <input type="hidden" name="order_direction" value="<%= _context.query.order_direction %>" />
34
+ <input type="hidden" name="order_by" value="<%= _context.query.order_by %>" />
35
+
36
+ <div class="mb-4">
37
+ <label for="date_from" class="font-semibold hover:cursor-pointer body-3">From</label>
38
+ <input type="date" name="f:date_from" value="<%= _context.query["f:date_from"] %>" />
39
+ </div>
40
+
41
+ <div class="mb-4">
42
+ <label for="date_to" class="font-semibold hover:cursor-pointer body-3">To</label>
43
+ <input type="date" name="f:date_to" value="<%= _context.query["f:date_to"] %>" />
44
+ </div>
45
+
46
+ <div class="mb-4">
47
+ <%- f.field('f:operator', {
48
+ as: 'select',
49
+ options: editors.map(editor => [editor.id, editor.name]),
50
+ label: "Editor",
51
+ include_blank: 'All Editors',
52
+ value: _context.query["f:operator"]
53
+ }) %>
54
+ </div>
55
+
56
+ <div class="mb-4">
57
+ <label for="" class="font-semibold hover:cursor-pointer body-3">Changes</label>
58
+ <div class="checkbox-group mb-4">
59
+ <% Object.entries(history.changeTypes(_context.resourceConfig.eventType)).forEach(([key, {label}])=> { %>
60
+ <div class="flex items-center gap-1">
61
+ <% if (Array.from(_context.query["f:change_type"] || []).includes(key)) { %>
62
+ <input type="checkbox" name="f:change_type" id='change-<%= key %>' checked value="<%= key %>" class="hover:cursor-pointer">
63
+ <% } else { %>
64
+ <input type="checkbox" name="f:change_type" id='change-<%= key %>' value="<%= key %>" class="hover:cursor-pointer">
65
+ <% } %>
66
+ <label for='change-<%= key %>' class="body-2 hover:cursor-pointer">
67
+ <%= label %>
68
+ </label>
69
+ </div>
70
+ <% }); %>
71
+ </div>
72
+ </div>
73
+
74
+ <div class="btn-toolbar">
75
+ <button type="submit" class="btn-primary">Search</button>
76
+ <a href="<%= `/${_context.locale}/${_context.resourceConfig.eventTypePlural}/${resource.id}/history` %>" class="btn-text">Clear search</a>
77
+ </div>
78
+ </form>
79
+ </div>
80
+
81
+ <script>
82
+ const sidebar = document.querySelector("[data-sidebar]");
83
+ const searchToggle = document.querySelector('[data-toggle-sidebar]');
84
+ searchToggle.addEventListener('click', () => {
85
+ sidebar.classList.toggle('hidden');
86
+ });
87
+ </script>
@@ -218,57 +218,17 @@
218
218
  History of changes
219
219
  </h4>
220
220
 
221
- <table class="data-grid">
222
- <thead>
223
- <tr>
224
- <th>Title</th>
225
- <th>Date of change</th>
226
- <th>Published by</th>
227
- <th>&nbsp;</th>
228
- </tr>
229
- </thead>
230
-
231
- <tbody>
232
- <% const maxVersion = Math.max(...changes.map((ch) => ch.version)); %>
233
- <% changes.forEach((change, idx)=> { %>
234
- <tr class="border-b border-mono-25">
235
- <td class="py-4 pl-2">
236
- <div class="flex items-center gap-2">
237
- <%= [change.title, change.description].filter(Boolean).join(": ") %>
238
-
239
- <% if (change.source === "revert") { %>
240
- <img src="/static/_assets/revert.svg" alt="Revert version" class="size-4">
241
- <% } %>
242
- </div>
243
- </td>
244
-
245
- <td class="whitespace-nowrap">
246
- <div class="body-3 text-raketa-foreground/50">
247
- <div class="flex items-center gap-1">
248
- <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-4 text-raketa-foreground">
249
- <path stroke-linecap="round" stroke-linejoin="round" d="M12 6v6h4.5m4.5 0a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />
250
- </svg>
251
-
252
- <time data-pretty-datetime datetime="<%= change.insertedAt %>"><%= change.insertedAt %></time>
253
- </div>
254
- </div>
255
- </td>
256
-
257
- <td class="whitespace-nowrap">
258
- <div class="body-3 text-raketa-foreground/50">
259
- <div class="flex items-center gap-1" title="<%= change.operatorMeta.name %>">
260
- <img src="<%= change.operatorMeta.avatar %>" class="size-4 rounded-full">
261
- <%= change.operatorMeta.name %>
262
- </div>
263
- </div>
264
- </td>
265
-
266
- <td>
267
- <%- render_partial('./_shared/_history_toolbar.ejs', { maxVersion, change }) %>
268
- </td>
269
- </tr>
270
- <% }); %>
271
- </tbody>
272
- </table>
221
+ <%- render_partial('./_shared/history_table.ejs', {
222
+ changes,
223
+ resource,
224
+ _context,
225
+ render_partial,
226
+ skipPagination: true,
227
+ toolbarPath: './_shared/_history_toolbar.ejs'
228
+ }) %>
229
+
230
+ <a href="<%= `/${_context.locale}/${_context.resourceConfig.eventTypePlural}/${resource.id}/history` %>" class="btn-text ml-2 my-8">
231
+ Full page history
232
+ </a>
273
233
  </div>
274
234
  </div>
@@ -1,16 +1,17 @@
1
1
  <div class="actions-toolbar justify-end">
2
- <% if (maxVersion !== change.version) { %>
3
2
  <form method="POST" action="<%= `/${_context.locale}/${_context.resourceConfig.pageTypePlural}/${resource.id}/${_context.resourceConfig.pageType}_changes/reverts` %>" class="inline-block">
4
- <input type="hidden" name="version" value=<%= change.version %>>
5
- <button type="submit" class="btn-text has-icon">
6
- <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-4">
7
- <path stroke-linecap="round" stroke-linejoin="round" d="M9 15 3 9m0 0 6-6M3 9h12a6 6 0 0 1 0 12h-3" />
8
- </svg>
3
+ <input type="hidden" name="version" value="<%= change.version %>">
9
4
 
5
+ <% if (history.isChangeRevertable(change, maxVersion)) { %>
6
+ <button type="submit" class="btn-text">
10
7
  Revert
11
8
  </button>
9
+ <% } else { %>
10
+ <button type="submit" disabled class="btn-text opacity-50 cursor-not-allowed">
11
+ Revert
12
+ </button>
13
+ <% } %>
12
14
  </form>
13
- <% } %>
14
15
 
15
16
  <a href="/remote/login?redirect_to=/<%= _context.locale %>/admin/<%= _context.resourceConfig.pageTypePlural %>/<%= resource.id %>/changes/<%= change.version %>" class="btn-text has-icon">
16
17
  <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-4">
@@ -0,0 +1,68 @@
1
+ <% const maxVersion = history.getMaxVersion(changes); %>
2
+
3
+ <div class="history-table-wrapper">
4
+ <table class="data-grid">
5
+ <thead>
6
+ <tr>
7
+ <th>#</th>
8
+ <th>Date of change</th>
9
+ <th>Editor</th>
10
+ <th>Action</th>
11
+ <th>Reason</th>
12
+ <th>&nbsp;</th>
13
+ </tr>
14
+ </thead>
15
+
16
+ <tbody>
17
+ <% changes.list.forEach((change)=> { %>
18
+ <tr class="border-b border-mono-25">
19
+ <td class="py-4 pl-2">
20
+ <div class="flex items-center gap-2">
21
+ <%= change.version %>
22
+ </div>
23
+ </td>
24
+
25
+ <td class="whitespace-nowrap">
26
+ <div class="body-3 text-raketa-foreground/50">
27
+ <div class="flex items-center gap-1">
28
+ <time data-pretty-datetime datetime="<%= change.insertedAt %>"><%= change.insertedAt %></time>
29
+ </div>
30
+ </div>
31
+ </td>
32
+
33
+ <td class="whitespace-nowrap">
34
+ <div class="body-3 text-raketa-foreground/50">
35
+ <div class="flex items-center gap-1" title="<%= change.operatorMeta.name %>">
36
+ <% if (change.operatorMeta.avatar) { %>
37
+ <img src="<%= change.operatorMeta.avatar %>" class="size-4 rounded-full">
38
+ <% } %>
39
+
40
+ <%= change.operatorMeta.name %>
41
+ </div>
42
+ </div>
43
+ </td>
44
+
45
+ <td class="py-4 pl-2">
46
+ <div class="flex items-center gap-2">
47
+ <%= history.changeAction(change, _context.resourceConfig.pageType) %>
48
+ </div>
49
+ </td>
50
+
51
+ <td class="py-4 pl-2">
52
+ <div class="flex items-center gap-2">
53
+ <%= history.changeReason(change) %>
54
+ </div>
55
+ </td>
56
+
57
+ <td>
58
+ <%- render_partial(toolbarPath, { maxVersion, change }) %>
59
+ </td>
60
+ </tr>
61
+ <% }); %>
62
+ </tbody>
63
+ </table>
64
+
65
+ <% if (!skipPagination) { %>
66
+ <%- pagination(changes.pagination, _context) %>
67
+ <% } %>
68
+ </div>
@@ -0,0 +1,87 @@
1
+ <div class="page-wrapper">
2
+ <div class="page-title">
3
+ <div>
4
+ <h1 class="heading-1">Pages / History of changes</h1>
5
+ <span class="body-2 opacity-50"><%= %></span>
6
+ </div>
7
+
8
+ <div class="actions-toolbar">
9
+ <a href="<%= `/${_context.locale}/${_context.resourceConfig.pageTypePlural}/${resource.id}` %>" class="btn-text">Back</a>
10
+ <button type="button" data-toggle-sidebar="1" class="p-2.5 rounded hover:bg-neutral-200 transition-all duration-300 ease-in-out dark:hover:bg-neutral-700">
11
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-4">
12
+ <path stroke-linecap="round" stroke-linejoin="round" d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z" />
13
+ </svg>
14
+ </button>
15
+ </div>
16
+ </div>
17
+
18
+ <%- render_partial('../_shared/history_table.ejs', {
19
+ changes,
20
+ resource,
21
+ _context,
22
+ render_partial,
23
+ skipPagination: false,
24
+ toolbarPath: '../_shared/_history_toolbar.ejs'
25
+ }) %>
26
+
27
+ </div>
28
+
29
+ <div data-sidebar="1" class="search-sidebar <%= Object.keys(_context.query).some(k => k.startsWith('f:')) ? '' : 'hidden' %>">
30
+ <span class="heading-2">Search by</span>
31
+
32
+ <form action="<%= `/${_context.locale}/${_context.resourceConfig.pageTypePlural}/${resource.id}/history` %>" method="GET" class="form mt-4">
33
+ <input type="hidden" name="order_direction" value="<%= _context.query.order_direction %>" />
34
+ <input type="hidden" name="order_by" value="<%= _context.query.order_by %>" />
35
+
36
+ <div class="mb-4">
37
+ <label for="date_from" class="font-semibold hover:cursor-pointer body-3">From</label>
38
+ <input type="date" name="f:date_from" value="<%= _context.query["f:date_from"] %>" />
39
+ </div>
40
+
41
+ <div class="mb-4">
42
+ <label for="date_to" class="font-semibold hover:cursor-pointer body-3">To</label>
43
+ <input type="date" name="f:date_to" value="<%= _context.query["f:date_to"] %>" />
44
+ </div>
45
+
46
+ <div class="mb-4">
47
+ <%- f.field('f:operator', {
48
+ as: 'select',
49
+ options: editors.map(editor => [editor.id, editor.name]),
50
+ label: "Editor",
51
+ include_blank: 'All Editors',
52
+ value: _context.query["f:operator"]
53
+ }) %>
54
+ </div>
55
+
56
+ <div class="mb-4">
57
+ <label for="" class="font-semibold hover:cursor-pointer body-3">Changes</label>
58
+ <div class="checkbox-group mb-4">
59
+ <% Object.entries(history.changeTypes(_context.resourceConfig.pageType)).forEach(([key, {label}])=> { %>
60
+ <div class="flex items-center gap-1">
61
+ <% if (Array.from(_context.query["f:change_type"] || []).includes(key)) { %>
62
+ <input type="checkbox" name="f:change_type" id='change-<%= key %>' checked value="<%= key %>" class="hover:cursor-pointer">
63
+ <% } else { %>
64
+ <input type="checkbox" name="f:change_type" id='change-<%= key %>' value="<%= key %>" class="hover:cursor-pointer">
65
+ <% } %>
66
+ <label for='change-<%= key %>' class="body-2 hover:cursor-pointer">
67
+ <%= label %>
68
+ </label>
69
+ </div>
70
+ <% }); %>
71
+ </div>
72
+ </div>
73
+
74
+ <div class="btn-toolbar">
75
+ <button type="submit" class="btn-primary">Search</button>
76
+ <a href="<%= `/${_context.locale}/${_context.resourceConfig.pageTypePlural}/${resource.id}/history` %>" class="btn-text">Clear search</a>
77
+ </div>
78
+ </form>
79
+ </div>
80
+
81
+ <script>
82
+ const sidebar = document.querySelector("[data-sidebar]");
83
+ const searchToggle = document.querySelector('[data-toggle-sidebar]');
84
+ searchToggle.addEventListener('click', () => {
85
+ sidebar.classList.toggle('hidden');
86
+ });
87
+ </script>