trusty-cms 7.0.31 → 7.0.32
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.
- checksums.yaml +4 -4
- data/Gemfile.lock +17 -7
- data/app/assets/javascripts/admin/recent-changes.js +17 -0
- data/app/assets/javascripts/admin.js +1 -0
- data/app/assets/stylesheets/admin/main.scss +1 -0
- data/app/assets/stylesheets/admin/partials/_recent_changes.scss +80 -0
- data/app/assets/stylesheets/admin/partials/_table.scss +37 -39
- data/app/controllers/admin/changes_controller.rb +118 -0
- data/app/controllers/admin/pages_controller.rb +1 -0
- data/app/controllers/admin/resource_controller.rb +7 -0
- data/app/helpers/admin/pages_helper.rb +6 -0
- data/app/models/page.rb +8 -7
- data/app/models/page_part.rb +2 -2
- data/app/views/admin/changes/show.html.haml +57 -0
- data/app/views/admin/layouts/_site_chooser.html.haml +1 -1
- data/app/views/admin/pages/_previous_versions.haml +14 -5
- data/config/routes.rb +1 -0
- data/db/migrate/20250606144908_add_object_changes_to_versions.trusty_cms.rb +8 -0
- data/lib/trusty_cms/admin_ui.rb +14 -1
- data/lib/trusty_cms/version.rb +1 -1
- data/trusty_cms.gemspec +1 -0
- data/vendor/extensions/multi-site-extension/multi_site_extension.rb +2 -0
- metadata +21 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fcafb280a56612c280982244b9a3bc76e4460aabef9ea7bb28eed7cdccfd880c
|
4
|
+
data.tar.gz: 281618eabbfbf3c6b14dba86edc1ce57aa5d362607c7e68f4aab09ad81a4fbca
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bf4134454382b20f1e8bad14286963d02fa3dd7079ab3786516408e1a744514a147e58bfdd3f4ae60c2e355f252aa4bc6cab8fb22a8315f924aba6303a9f30ac
|
7
|
+
data.tar.gz: 27bce35c3fb49517d7af5825049bf68e40ca0af29c117f60aca5066c005080cc5e8e3fa4c60dc78691d9c5898299f5b3c286851bd6a23644c7253b3478cc7a1a
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
trusty-cms (7.0.
|
4
|
+
trusty-cms (7.0.32)
|
5
5
|
RedCloth (= 4.3.3)
|
6
6
|
activestorage-validator
|
7
7
|
acts_as_list (>= 0.9.5, < 1.3.0)
|
@@ -12,6 +12,7 @@ PATH
|
|
12
12
|
delocalize (>= 0.2, < 2.0)
|
13
13
|
devise
|
14
14
|
devise-two-factor
|
15
|
+
diffy
|
15
16
|
drb
|
16
17
|
execjs (~> 2.7)
|
17
18
|
haml (>= 5.0, < 6.0)
|
@@ -168,6 +169,7 @@ GEM
|
|
168
169
|
railties (>= 7.0, < 8.1)
|
169
170
|
rotp (~> 6.0)
|
170
171
|
diff-lcs (1.5.1)
|
172
|
+
diffy (3.4.4)
|
171
173
|
docile (1.4.1)
|
172
174
|
drb (2.2.1)
|
173
175
|
erubi (1.13.0)
|
@@ -246,6 +248,7 @@ GEM
|
|
246
248
|
mime-types-data (3.2024.1105)
|
247
249
|
mini_magick (4.13.2)
|
248
250
|
mini_mime (1.1.5)
|
251
|
+
mini_portile2 (2.8.9)
|
249
252
|
mini_racer (0.16.0)
|
250
253
|
libv8-node (~> 18.19.0.0)
|
251
254
|
minitest (5.25.4)
|
@@ -264,17 +267,24 @@ GEM
|
|
264
267
|
net-smtp (0.5.0)
|
265
268
|
net-protocol
|
266
269
|
nio4r (2.7.3)
|
267
|
-
nokogiri (1.
|
270
|
+
nokogiri (1.18.8)
|
271
|
+
mini_portile2 (~> 2.8.2)
|
268
272
|
racc (~> 1.4)
|
269
|
-
nokogiri (1.
|
273
|
+
nokogiri (1.18.8-aarch64-linux-gnu)
|
270
274
|
racc (~> 1.4)
|
271
|
-
nokogiri (1.
|
275
|
+
nokogiri (1.18.8-aarch64-linux-musl)
|
272
276
|
racc (~> 1.4)
|
273
|
-
nokogiri (1.
|
277
|
+
nokogiri (1.18.8-arm-linux-gnu)
|
274
278
|
racc (~> 1.4)
|
275
|
-
nokogiri (1.
|
279
|
+
nokogiri (1.18.8-arm-linux-musl)
|
276
280
|
racc (~> 1.4)
|
277
|
-
nokogiri (1.
|
281
|
+
nokogiri (1.18.8-arm64-darwin)
|
282
|
+
racc (~> 1.4)
|
283
|
+
nokogiri (1.18.8-x86_64-darwin)
|
284
|
+
racc (~> 1.4)
|
285
|
+
nokogiri (1.18.8-x86_64-linux-gnu)
|
286
|
+
racc (~> 1.4)
|
287
|
+
nokogiri (1.18.8-x86_64-linux-musl)
|
278
288
|
racc (~> 1.4)
|
279
289
|
orm_adapter (0.5.0)
|
280
290
|
paper_trail (16.0.0)
|
@@ -0,0 +1,17 @@
|
|
1
|
+
document.addEventListener("DOMContentLoaded", () => {
|
2
|
+
document.querySelectorAll(".toggle-diff").forEach(link => {
|
3
|
+
link.addEventListener("click", event => {
|
4
|
+
event.preventDefault();
|
5
|
+
|
6
|
+
const targetId = link.dataset.toggle;
|
7
|
+
const row = document.getElementById(targetId);
|
8
|
+
if (!row) return;
|
9
|
+
|
10
|
+
const isHidden = window.getComputedStyle(row).display === "none";
|
11
|
+
row.style.display = isHidden ? "table-row" : "none";
|
12
|
+
|
13
|
+
link.textContent = isHidden ? "Hide Diff" : "Show Diff";
|
14
|
+
link.setAttribute("aria-expanded", isHidden.toString());
|
15
|
+
});
|
16
|
+
});
|
17
|
+
});
|
@@ -0,0 +1,80 @@
|
|
1
|
+
.diff {
|
2
|
+
overflow: visible;
|
3
|
+
}
|
4
|
+
|
5
|
+
.diff ul {
|
6
|
+
background: #fff;
|
7
|
+
display: table;
|
8
|
+
font-size: 13px;
|
9
|
+
list-style: none;
|
10
|
+
margin: 0;
|
11
|
+
overflow: auto;
|
12
|
+
padding: 0;
|
13
|
+
width: 100%;
|
14
|
+
}
|
15
|
+
|
16
|
+
.diff li {
|
17
|
+
display: table-row;
|
18
|
+
height: 1em;
|
19
|
+
margin: 0;
|
20
|
+
padding: 0;
|
21
|
+
}
|
22
|
+
|
23
|
+
.diff li.ins {
|
24
|
+
background: #dfd;
|
25
|
+
color: #080;
|
26
|
+
}
|
27
|
+
|
28
|
+
.diff li.del {
|
29
|
+
background: #fee;
|
30
|
+
color: #b00;
|
31
|
+
}
|
32
|
+
|
33
|
+
.diff del,
|
34
|
+
.diff ins,
|
35
|
+
.diff span {
|
36
|
+
display: block;
|
37
|
+
font-family: courier;
|
38
|
+
text-decoration: none;
|
39
|
+
white-space: pre-wrap;
|
40
|
+
}
|
41
|
+
|
42
|
+
.diff del strong {
|
43
|
+
background: #fcc;
|
44
|
+
font-weight: normal;
|
45
|
+
}
|
46
|
+
|
47
|
+
.diff ins strong {
|
48
|
+
background: #9f9;
|
49
|
+
font-weight: normal;
|
50
|
+
}
|
51
|
+
|
52
|
+
.diff li.diff-comment {
|
53
|
+
display: none;
|
54
|
+
}
|
55
|
+
|
56
|
+
.diff li.diff-block-info {
|
57
|
+
background: gray;
|
58
|
+
}
|
59
|
+
|
60
|
+
.dynamic-diff-row {
|
61
|
+
display: none;
|
62
|
+
}
|
63
|
+
|
64
|
+
table#recent-changes {
|
65
|
+
width: 100%;
|
66
|
+
}
|
67
|
+
|
68
|
+
table#recent-changes td {
|
69
|
+
overflow-wrap: break-word;
|
70
|
+
padding: 12px;
|
71
|
+
word-break: break-word;
|
72
|
+
}
|
73
|
+
|
74
|
+
table#recent-changes tr:hover.diff-row td {
|
75
|
+
background: none !important;
|
76
|
+
}
|
77
|
+
|
78
|
+
table#recent-changes tr:hover.dynamic-diff-row td {
|
79
|
+
background: none !important;
|
80
|
+
}
|
@@ -7,7 +7,6 @@
|
|
7
7
|
width: $width;
|
8
8
|
}
|
9
9
|
|
10
|
-
|
11
10
|
table {
|
12
11
|
th {
|
13
12
|
background-color: $light-gray;
|
@@ -51,23 +50,23 @@ table {
|
|
51
50
|
color: $dark-gray;
|
52
51
|
text-decoration: none;
|
53
52
|
|
53
|
+
&.selected,
|
54
54
|
&:hover {
|
55
55
|
background: $light-gray;
|
56
56
|
border: 1px solid darken($light-gray, 10%);
|
57
57
|
margin: 0 24px 0 0;
|
58
58
|
}
|
59
|
-
|
60
|
-
&.selected {
|
61
|
-
background: $light-gray;
|
62
|
-
border: 1px solid darken($light-gray, 10%);
|
63
|
-
margin: 0 24px 0 0;
|
64
|
-
}
|
65
59
|
}
|
66
60
|
|
67
61
|
span.action.disabled {
|
68
62
|
color: #cccccc;
|
69
63
|
}
|
70
64
|
|
65
|
+
&.actions {
|
66
|
+
font-size: 85%;
|
67
|
+
white-space: nowrap;
|
68
|
+
}
|
69
|
+
|
71
70
|
&.empty {
|
72
71
|
color: silver;
|
73
72
|
font-style: italic;
|
@@ -83,10 +82,12 @@ table {
|
|
83
82
|
text-decoration: none;
|
84
83
|
}
|
85
84
|
}
|
85
|
+
}
|
86
86
|
|
87
|
-
|
88
|
-
|
89
|
-
|
87
|
+
thead {
|
88
|
+
tr,
|
89
|
+
tr:first-child {
|
90
|
+
border-top: none;
|
90
91
|
}
|
91
92
|
}
|
92
93
|
|
@@ -104,17 +105,17 @@ table {
|
|
104
105
|
}
|
105
106
|
}
|
106
107
|
}
|
107
|
-
|
108
|
-
thead {
|
109
|
-
tr,
|
110
|
-
tr:first-child {
|
111
|
-
border-top: none;
|
112
|
-
}
|
113
|
-
}
|
114
108
|
}
|
115
109
|
|
116
110
|
table.index#pages {
|
117
111
|
td.name {
|
112
|
+
.info {
|
113
|
+
color: #9eb3bf;
|
114
|
+
font-size: 0.90em;
|
115
|
+
font-style: italic;
|
116
|
+
font-weight: normal;
|
117
|
+
}
|
118
|
+
|
118
119
|
.w1 {
|
119
120
|
position: relative;
|
120
121
|
|
@@ -124,24 +125,35 @@ table.index#pages {
|
|
124
125
|
position: absolute;
|
125
126
|
}
|
126
127
|
}
|
128
|
+
}
|
127
129
|
|
128
|
-
|
129
|
-
|
130
|
-
font-size: 0.90em;
|
131
|
-
font-style: italic;
|
132
|
-
font-weight: normal;
|
133
|
-
}
|
130
|
+
td.status {
|
131
|
+
font-size: 0.80em;
|
134
132
|
}
|
135
133
|
|
136
134
|
tr.page.virtual td.name a .title {
|
137
135
|
color: #9eb3bf;
|
138
136
|
}
|
137
|
+
}
|
139
138
|
|
140
|
-
|
141
|
-
|
139
|
+
table.index#users {
|
140
|
+
td.name {
|
141
|
+
padding-bottom: 8px;
|
142
|
+
padding-top: 8px;
|
143
|
+
|
144
|
+
.login {
|
145
|
+
color: #9eb3bf;
|
146
|
+
font-size: 90%;
|
147
|
+
font-style: italic;
|
148
|
+
font-weight: normal;
|
149
|
+
}
|
142
150
|
}
|
143
151
|
}
|
144
152
|
|
153
|
+
table#versions-table td {
|
154
|
+
padding: 12px;
|
155
|
+
}
|
156
|
+
|
145
157
|
.status {
|
146
158
|
a {
|
147
159
|
@include plain-link;
|
@@ -155,17 +167,3 @@ table.index#pages {
|
|
155
167
|
.hidden_status {
|
156
168
|
@include status-badge(#9eb3bf);
|
157
169
|
}
|
158
|
-
|
159
|
-
table.index#users {
|
160
|
-
td.name {
|
161
|
-
padding-bottom: 8px;
|
162
|
-
padding-top: 8px;
|
163
|
-
|
164
|
-
.login {
|
165
|
-
color: #9eb3bf;
|
166
|
-
font-size: 90%;
|
167
|
-
font-style: italic;
|
168
|
-
font-weight: normal;
|
169
|
-
}
|
170
|
-
}
|
171
|
-
}
|
@@ -0,0 +1,118 @@
|
|
1
|
+
require 'diffy'
|
2
|
+
|
3
|
+
class Admin::ChangesController < Admin::ResourceController
|
4
|
+
before_action :initialize_variables
|
5
|
+
|
6
|
+
def show
|
7
|
+
@changes = load_changes
|
8
|
+
@change_error = 'Version ID not found.' if params[:version_id].present? && @changes.empty?
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def load_changes
|
14
|
+
return load_single_change if params[:version_id].present?
|
15
|
+
|
16
|
+
load_recent_changes
|
17
|
+
end
|
18
|
+
|
19
|
+
def load_single_change
|
20
|
+
version = PaperTrail::Version.find_by(id: params[:version_id])
|
21
|
+
version ? [build_change_entry(version)] : []
|
22
|
+
end
|
23
|
+
|
24
|
+
def load_recent_changes
|
25
|
+
fetch_recent_page_versions.map { |version| build_change_entry(version) }
|
26
|
+
end
|
27
|
+
|
28
|
+
def fetch_recent_page_versions
|
29
|
+
PaperTrail::Version.
|
30
|
+
where(item_type: 'Page').
|
31
|
+
joins('INNER JOIN pages ON pages.id = versions.item_id').
|
32
|
+
where(pages: { site_id: current_site.id }).
|
33
|
+
where('versions.created_at >= ?', 1.month.ago).
|
34
|
+
order(created_at: :desc).
|
35
|
+
limit(25)
|
36
|
+
end
|
37
|
+
|
38
|
+
def build_change_entry(version)
|
39
|
+
page = Page.find_by(id: version.item_id)
|
40
|
+
return {} unless page
|
41
|
+
|
42
|
+
{
|
43
|
+
action: version.event.titleize,
|
44
|
+
diff: build_diff(version),
|
45
|
+
id: version.id,
|
46
|
+
page_title: page.title,
|
47
|
+
page_url: admin_page_url(page),
|
48
|
+
updated_at: format_timestamp(version.created_at),
|
49
|
+
user_name: user_name(version.whodunnit),
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
def build_diff(version)
|
54
|
+
related_versions = PaperTrail::Version.where(transaction_id: version.transaction_id)
|
55
|
+
diffs = related_versions.flat_map { |v| diff_fields(v) }.compact
|
56
|
+
diffs.any? ? diffs.join('<br />') : nil
|
57
|
+
end
|
58
|
+
|
59
|
+
def diff_fields(version)
|
60
|
+
version.changeset.map do |field, (old_val, new_val)|
|
61
|
+
next unless renderable_diff?(field, old_val, new_val)
|
62
|
+
|
63
|
+
render_field_diff(version, field, old_val, new_val)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def renderable_diff?(field, old_val, new_val)
|
68
|
+
!ignored_fields.include?(field) && !(old_val.nil? && new_val == '')
|
69
|
+
end
|
70
|
+
|
71
|
+
def render_field_diff(version, field, old_val, new_val)
|
72
|
+
diff_html = Diffy::Diff.new(old_val, new_val, context: 1).to_s(:html)
|
73
|
+
|
74
|
+
label = version.item_type == 'Page' ? field : label_for_version(version)
|
75
|
+
"<h2>#{label.humanize.titleize}</h2>#{diff_html}"
|
76
|
+
end
|
77
|
+
|
78
|
+
def ignored_fields
|
79
|
+
%w[
|
80
|
+
created_at
|
81
|
+
created_by_id
|
82
|
+
id
|
83
|
+
lock_version
|
84
|
+
name
|
85
|
+
page_id
|
86
|
+
published_at
|
87
|
+
updated_at
|
88
|
+
updated_by_id
|
89
|
+
].freeze
|
90
|
+
end
|
91
|
+
|
92
|
+
def user_name(whodunnit)
|
93
|
+
user_id = Integer(whodunnit, exception: false)
|
94
|
+
User.find_by(id: user_id)&.name || 'Unknown User'
|
95
|
+
end
|
96
|
+
|
97
|
+
def label_for_version(version)
|
98
|
+
case version.item_type
|
99
|
+
when 'PagePart' then PagePart.find_by(id: version.item_id)&.name || 'Unknown PagePart'
|
100
|
+
when 'PageField' then PageField.find_by(id: version.item_id)&.name || 'Unknown PageField'
|
101
|
+
else version.item_type
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def format_timestamp(timestamp)
|
106
|
+
timestamp.strftime('%A, %B %d, %I:%M %p')
|
107
|
+
end
|
108
|
+
|
109
|
+
def admin_page_url(page)
|
110
|
+
"/admin/pages/#{page.id}"
|
111
|
+
end
|
112
|
+
|
113
|
+
def initialize_variables
|
114
|
+
@user = current_user
|
115
|
+
@controller_name = 'changes'
|
116
|
+
@template_name = 'show'
|
117
|
+
end
|
118
|
+
end
|
@@ -134,6 +134,7 @@ class Admin::PagesController < Admin::ResourceController
|
|
134
134
|
.sort_by(&:created_at).reverse
|
135
135
|
.map do |version|
|
136
136
|
{
|
137
|
+
id: version&.id,
|
137
138
|
index: version&.index,
|
138
139
|
update_date: version&.created_at&.strftime('%B %d, %Y'),
|
139
140
|
update_time: version&.created_at&.strftime('%I:%M %p'),
|
@@ -9,6 +9,7 @@ class Admin::ResourceController < ApplicationController
|
|
9
9
|
before_action :load_models, only: :index
|
10
10
|
before_action :load_model, only: %i[new create edit update remove destroy]
|
11
11
|
before_action :set_owner_or_editor, only: %i[new create update]
|
12
|
+
before_action :set_page_updated_at, only: :update
|
12
13
|
after_action :clear_model_cache, only: %i[create update destroy]
|
13
14
|
|
14
15
|
cattr_reader :paginated
|
@@ -145,6 +146,12 @@ class Admin::ResourceController < ApplicationController
|
|
145
146
|
end
|
146
147
|
end
|
147
148
|
|
149
|
+
def set_page_updated_at
|
150
|
+
if model.class.name.include?('Page') && model.has_attribute?(:updated_at)
|
151
|
+
model.updated_at = Time.zone.now
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
148
155
|
def model
|
149
156
|
instance_variable_get("@#{model_symbol}") || load_model
|
150
157
|
end
|
@@ -25,4 +25,10 @@ module Admin::PagesHelper
|
|
25
25
|
selected_page_id = page.parent_id
|
26
26
|
options_for_select(parent_pages.map { |p| [p.title, p.id] }, selected_page_id)
|
27
27
|
end
|
28
|
+
|
29
|
+
def revert_confirmation_message(version)
|
30
|
+
date = version[:update_date]
|
31
|
+
time = version[:update_time]
|
32
|
+
"Are you sure you want to revert the page to the version before the change made on #{date} at #{time}? All changes made after that will be lost."
|
33
|
+
end
|
28
34
|
end
|
data/app/models/page.rb
CHANGED
@@ -1,8 +1,6 @@
|
|
1
1
|
require 'trusty_cms/taggable'
|
2
2
|
|
3
3
|
class Page < ActiveRecord::Base
|
4
|
-
has_paper_trail
|
5
|
-
|
6
4
|
class MissingRootPageError < StandardError
|
7
5
|
def initialize(message = 'Database missing root page')
|
8
6
|
; super
|
@@ -22,6 +20,8 @@ class Page < ActiveRecord::Base
|
|
22
20
|
belongs_to :created_by, class_name: 'User'
|
23
21
|
belongs_to :updated_by, class_name: 'User'
|
24
22
|
|
23
|
+
has_paper_trail
|
24
|
+
|
25
25
|
# Validations
|
26
26
|
validates_presence_of :title, :slug, :breadcrumb, :status_id
|
27
27
|
|
@@ -40,6 +40,7 @@ class Page < ActiveRecord::Base
|
|
40
40
|
|
41
41
|
annotate :description
|
42
42
|
attr_accessor :request, :response, :pagination_parameters
|
43
|
+
|
43
44
|
class_attribute :default_child
|
44
45
|
self.default_child = self
|
45
46
|
|
@@ -264,11 +265,11 @@ class Page < ActiveRecord::Base
|
|
264
265
|
@display_name = string
|
265
266
|
else
|
266
267
|
@display_name ||= begin
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
268
|
+
n = name.to_s
|
269
|
+
n.sub(/^(.+?)Page$/, '\1')
|
270
|
+
n.gsub(/([A-Z])/, ' \1')
|
271
|
+
n.strip
|
272
|
+
end
|
272
273
|
end
|
273
274
|
@display_name = @display_name + ' - not installed' if missing? && @display_name !~ /not installed/
|
274
275
|
@display_name
|
data/app/models/page_part.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
class PagePart < ActiveRecord::Base
|
2
|
-
has_paper_trail
|
3
|
-
|
4
2
|
# Default Order
|
5
3
|
default_scope { order('name') }
|
6
4
|
|
7
5
|
# Associations
|
8
6
|
belongs_to :page
|
9
7
|
|
8
|
+
has_paper_trail
|
9
|
+
|
10
10
|
# Validations
|
11
11
|
validates_presence_of :name
|
12
12
|
validates_length_of :name, maximum: 100
|
@@ -0,0 +1,57 @@
|
|
1
|
+
- @page_title = 'Changes - ' + default_page_title
|
2
|
+
- single_change = params[:version_id].present?
|
3
|
+
|
4
|
+
.outset
|
5
|
+
= render_region :top
|
6
|
+
|
7
|
+
%table#recent-changes
|
8
|
+
%thead
|
9
|
+
%tr
|
10
|
+
%th Version ID
|
11
|
+
%th Title
|
12
|
+
%th Action
|
13
|
+
%th User
|
14
|
+
%th Updated At
|
15
|
+
|
16
|
+
%tbody
|
17
|
+
- if @change_error
|
18
|
+
%tr
|
19
|
+
%td{ colspan: 5 }
|
20
|
+
%span.text-danger= @change_error
|
21
|
+
|
22
|
+
- elsif @changes.present?
|
23
|
+
- @changes.each_with_index do |change, index|
|
24
|
+
%tr.change-row{ data: { toggle_target: "diff-#{index}" } }
|
25
|
+
%td= change[:id]
|
26
|
+
%td= link_to change[:page_title], change[:page_url]
|
27
|
+
%td= change[:action]
|
28
|
+
%td= change[:user_name]
|
29
|
+
%td
|
30
|
+
= change[:updated_at]
|
31
|
+
- unless single_change
|
32
|
+
%br
|
33
|
+
%a.toggle-diff{
|
34
|
+
href: "#",
|
35
|
+
role: "button",
|
36
|
+
tabindex: "0",
|
37
|
+
aria: {
|
38
|
+
expanded: "false",
|
39
|
+
controls: "diff-#{index}"
|
40
|
+
},
|
41
|
+
data: { toggle: "diff-#{index}" }
|
42
|
+
} Show Diff
|
43
|
+
|
44
|
+
- diff_row_id = single_change ? nil : "diff-#{index}"
|
45
|
+
- diff_row_class = single_change ? 'diff-row' : 'dynamic-diff-row'
|
46
|
+
%tr{ id: diff_row_id, class: diff_row_class, role: "region", "aria-live" => "polite" }
|
47
|
+
%td{ colspan: 5 }
|
48
|
+
- if change[:diff].present?
|
49
|
+
!= change[:diff]
|
50
|
+
- else
|
51
|
+
%span.text-muted No differences found.
|
52
|
+
%span.sr-only Diff details for version ID #{change[:id]}.
|
53
|
+
|
54
|
+
- else
|
55
|
+
%tr
|
56
|
+
%td{ colspan: 5 }
|
57
|
+
%span No recent changes.
|
@@ -3,31 +3,40 @@
|
|
3
3
|
%h4
|
4
4
|
%i.fas.fa-clock-rotate-left
|
5
5
|
Previous Versions
|
6
|
+
|
6
7
|
.drawer_contents#versions
|
7
8
|
- if @versions.present?
|
8
9
|
%section
|
9
|
-
%table
|
10
|
+
%table#versions-table
|
10
11
|
%thead
|
11
12
|
%tr
|
13
|
+
%th Version ID
|
12
14
|
%th Date Updated
|
13
15
|
%th Time Updated
|
14
16
|
%th Updated By
|
15
17
|
%th Action
|
16
|
-
%tbody
|
18
|
+
%tbody
|
17
19
|
- @versions.each do |version|
|
18
20
|
%tr
|
21
|
+
%td= link_to version[:id], admin_changes_path(version_id: version[:id])
|
19
22
|
%td= version[:update_date]
|
20
23
|
%td= version[:update_time]
|
21
24
|
%td= version[:updated_by]
|
22
25
|
%td
|
23
|
-
= button_to '
|
26
|
+
= button_to 'Undo',
|
24
27
|
restore_version_admin_page_path(@page, version_index: version[:index]),
|
25
28
|
method: :put,
|
26
|
-
|
29
|
+
class: 'btn btn-warning',
|
30
|
+
data: { confirm: revert_confirmation_message(version) }
|
27
31
|
- else
|
28
32
|
%section#no-previous-versions
|
29
33
|
%p No previous versions are available.
|
34
|
+
|
30
35
|
.drawer_handle
|
31
|
-
%a.toggle{
|
36
|
+
%a.toggle{
|
37
|
+
href: '#versions',
|
38
|
+
rel: 'toggle[versions]',
|
39
|
+
class: (meta_errors? ? 'less' : 'more')
|
40
|
+
}
|
32
41
|
= meta_label
|
33
42
|
%i.fas.fa-angle-down
|
data/config/routes.rb
CHANGED
@@ -43,6 +43,7 @@ TrustyCms::Application.routes.draw do
|
|
43
43
|
get 'admin' => 'admin/pages#index'
|
44
44
|
|
45
45
|
namespace :admin do
|
46
|
+
resource :changes
|
46
47
|
resource :preferences
|
47
48
|
resource :two_factor, only: [:show, :create], controller: 'two_factor', path: 'two-factor'
|
48
49
|
resource :security, controller: 'security' do
|
data/lib/trusty_cms/admin_ui.rb
CHANGED
@@ -124,7 +124,7 @@ module TrustyCms
|
|
124
124
|
end
|
125
125
|
|
126
126
|
# Region sets
|
127
|
-
%w{page layout user configuration extension}.each do |controller|
|
127
|
+
%w{page layout user changes configuration extension}.each do |controller|
|
128
128
|
attr_accessor controller
|
129
129
|
alias_method "#{controller}s", controller
|
130
130
|
end
|
@@ -148,6 +148,10 @@ module TrustyCms
|
|
148
148
|
design << nav_item('Layouts', '/admin/layouts')
|
149
149
|
nav << design
|
150
150
|
|
151
|
+
changes = nav_tab('Recent Changes')
|
152
|
+
changes << nav_item('Changes', '/admin/changes')
|
153
|
+
nav << changes
|
154
|
+
|
151
155
|
settings = nav_tab('Settings')
|
152
156
|
settings << nav_item('General', '/admin/configuration')
|
153
157
|
settings << nav_item('Personal', '/admin/preferences')
|
@@ -160,6 +164,7 @@ module TrustyCms
|
|
160
164
|
def load_default_regions
|
161
165
|
@page = load_default_page_regions
|
162
166
|
@layout = load_default_layout_regions
|
167
|
+
@changes = load_default_changes_regions
|
163
168
|
@user = load_default_user_regions
|
164
169
|
@configuration = load_default_configuration_regions
|
165
170
|
@extension = load_default_extension_regions
|
@@ -233,6 +238,14 @@ module TrustyCms
|
|
233
238
|
end
|
234
239
|
end
|
235
240
|
|
241
|
+
def load_default_changes_regions
|
242
|
+
OpenStruct.new.tap do |changes|
|
243
|
+
changes.show = RegionSet.new do |show|
|
244
|
+
show.top.concat %w{}
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
236
249
|
def load_default_configuration_regions
|
237
250
|
OpenStruct.new.tap do |configuration|
|
238
251
|
configuration.show = RegionSet.new do |show|
|
data/lib/trusty_cms/version.rb
CHANGED
data/trusty_cms.gemspec
CHANGED
@@ -34,6 +34,7 @@ a general purpose content management system--not merely a blogging engine.'
|
|
34
34
|
s.add_dependency 'delocalize', '>= 0.2', '< 2.0'
|
35
35
|
s.add_dependency 'devise'
|
36
36
|
s.add_dependency 'devise-two-factor'
|
37
|
+
s.add_dependency 'diffy'
|
37
38
|
s.add_dependency 'drb'
|
38
39
|
s.add_dependency 'execjs', '~> 2.7'
|
39
40
|
s.add_dependency 'haml', '>= 5.0', '< 6.0'
|
@@ -21,10 +21,12 @@ class MultiSiteExtension < TrustyCms::Extension
|
|
21
21
|
Admin::PagesController.send :include, MultiSite::PagesControllerExtensions
|
22
22
|
Admin::ResourceController.send :helper, MultiSite::SiteChooserHelper
|
23
23
|
Admin::PagesController.send :helper, MultiSite::SiteChooserHelper
|
24
|
+
Admin::ChangesController.send :helper, MultiSite::SiteChooserHelper
|
24
25
|
admin.layouts.index.add(:before_nav, "admin/layouts/site_chooser")
|
25
26
|
admin.pages.index.add(:before_nav, "admin/layouts/site_chooser")
|
26
27
|
admin.snippets.index.add(:before_nav, "admin/layouts/site_chooser")
|
27
28
|
admin.pages.search.add(:before_nav, "admin/layouts/site_chooser")
|
29
|
+
admin.changes.show.add(:before_nav, "admin/layouts/site_chooser")
|
28
30
|
Layout.send :is_site_scoped
|
29
31
|
Snippet.send :is_site_scoped
|
30
32
|
User.send :is_site_scoped, :shareable => true
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: trusty-cms
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 7.0.
|
4
|
+
version: 7.0.32
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- TrustyCms CMS dev team
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-06-
|
11
|
+
date: 2025-06-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activestorage-validator
|
@@ -154,6 +154,20 @@ dependencies:
|
|
154
154
|
- - ">="
|
155
155
|
- !ruby/object:Gem::Version
|
156
156
|
version: '0'
|
157
|
+
- !ruby/object:Gem::Dependency
|
158
|
+
name: diffy
|
159
|
+
requirement: !ruby/object:Gem::Requirement
|
160
|
+
requirements:
|
161
|
+
- - ">="
|
162
|
+
- !ruby/object:Gem::Version
|
163
|
+
version: '0'
|
164
|
+
type: :runtime
|
165
|
+
prerelease: false
|
166
|
+
version_requirements: !ruby/object:Gem::Requirement
|
167
|
+
requirements:
|
168
|
+
- - ">="
|
169
|
+
- !ruby/object:Gem::Version
|
170
|
+
version: '0'
|
157
171
|
- !ruby/object:Gem::Dependency
|
158
172
|
name: drb
|
159
173
|
requirement: !ruby/object:Gem::Requirement
|
@@ -731,6 +745,7 @@ files:
|
|
731
745
|
- app/assets/javascripts/admin/persist.min.js
|
732
746
|
- app/assets/javascripts/admin/popup.js
|
733
747
|
- app/assets/javascripts/admin/preview.js
|
748
|
+
- app/assets/javascripts/admin/recent-changes.js
|
734
749
|
- app/assets/javascripts/admin/sortable.js
|
735
750
|
- app/assets/javascripts/admin/tabcontrol.js.erb
|
736
751
|
- app/assets/javascripts/admin/tags.js
|
@@ -765,6 +780,7 @@ files:
|
|
765
780
|
- app/assets/stylesheets/admin/partials/_popup.scss
|
766
781
|
- app/assets/stylesheets/admin/partials/_preferences.scss
|
767
782
|
- app/assets/stylesheets/admin/partials/_previous_versions.scss
|
783
|
+
- app/assets/stylesheets/admin/partials/_recent_changes.scss
|
768
784
|
- app/assets/stylesheets/admin/partials/_sidebar.scss
|
769
785
|
- app/assets/stylesheets/admin/partials/_tabcontrol.scss
|
770
786
|
- app/assets/stylesheets/admin/partials/_table.scss
|
@@ -773,6 +789,7 @@ files:
|
|
773
789
|
- app/assets/stylesheets/admin/partials/_typography.scss
|
774
790
|
- app/assets/stylesheets/admin/partials/_validations.scss
|
775
791
|
- app/controllers/admin/assets_controller.rb
|
792
|
+
- app/controllers/admin/changes_controller.rb
|
776
793
|
- app/controllers/admin/configuration_controller.rb
|
777
794
|
- app/controllers/admin/extensions_controller.rb
|
778
795
|
- app/controllers/admin/layouts_controller.rb
|
@@ -848,6 +865,7 @@ files:
|
|
848
865
|
- app/views/admin/assets/index.html.haml
|
849
866
|
- app/views/admin/assets/new.html.haml
|
850
867
|
- app/views/admin/assets/remove.html.haml
|
868
|
+
- app/views/admin/changes/show.html.haml
|
851
869
|
- app/views/admin/configuration/_clipped_edit.html.haml
|
852
870
|
- app/views/admin/configuration/_clipped_show.html.haml
|
853
871
|
- app/views/admin/configuration/edit.html.haml
|
@@ -1002,6 +1020,7 @@ files:
|
|
1002
1020
|
- db/migrate/20250103191133_create_version_associations.rb
|
1003
1021
|
- db/migrate/20250103191134_add_transaction_id_column_to_versions.rb
|
1004
1022
|
- db/migrate/20250502162215_add_devise_two_factor_to_admins.rb
|
1023
|
+
- db/migrate/20250606144908_add_object_changes_to_versions.trusty_cms.rb
|
1005
1024
|
- db/schema.rb
|
1006
1025
|
- lib/active_record_extensions/active_record_extensions.rb
|
1007
1026
|
- lib/annotatable.rb
|