ruby_cms 0.1.9 → 0.2.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/README.md +440 -58
- data/app/controllers/ruby_cms/admin/base_controller.rb +33 -12
- data/app/controllers/ruby_cms/admin/content_block_versions_controller.rb +62 -0
- data/app/controllers/ruby_cms/admin/dashboard_controller.rb +40 -0
- data/app/helpers/ruby_cms/admin/dashboard_helper.rb +20 -0
- data/app/javascript/controllers/ruby_cms/content_block_history_controller.js +91 -0
- data/app/javascript/controllers/ruby_cms/index.js +4 -0
- data/app/javascript/controllers/ruby_cms/visual_editor_controller.js +33 -29
- data/app/models/concerns/content_block/versionable.rb +80 -0
- data/app/models/content_block.rb +1 -0
- data/app/models/content_block_version.rb +34 -0
- data/app/views/admin/content_block_versions/index.html.erb +52 -0
- data/app/views/admin/content_block_versions/show.html.erb +37 -0
- data/app/views/ruby_cms/admin/content_block_versions/index.html.erb +52 -0
- data/app/views/ruby_cms/admin/content_block_versions/show.html.erb +37 -0
- data/app/views/ruby_cms/admin/content_blocks/show.html.erb +12 -0
- data/app/views/ruby_cms/admin/dashboard/blocks/_analytics_overview.html.erb +53 -0
- data/app/views/ruby_cms/admin/dashboard/blocks/_content_blocks_stats.html.erb +17 -0
- data/app/views/ruby_cms/admin/dashboard/blocks/_permissions_stats.html.erb +17 -0
- data/app/views/ruby_cms/admin/dashboard/blocks/_quick_actions.html.erb +62 -0
- data/app/views/ruby_cms/admin/dashboard/blocks/_recent_errors.html.erb +39 -0
- data/app/views/ruby_cms/admin/dashboard/blocks/_users_stats.html.erb +17 -0
- data/app/views/ruby_cms/admin/dashboard/blocks/_visitor_errors_stats.html.erb +24 -0
- data/app/views/ruby_cms/admin/dashboard/index.html.erb +22 -180
- data/config/routes.rb +8 -0
- data/db/migrate/20260328000001_create_content_block_versions.rb +22 -0
- data/lib/generators/ruby_cms/admin_page_generator.rb +126 -0
- data/lib/generators/ruby_cms/templates/admin_page/controller.rb.tt +8 -0
- data/lib/generators/ruby_cms/templates/admin_page/index.html.erb.tt +11 -0
- data/lib/ruby_cms/dashboard_blocks.rb +91 -0
- data/lib/ruby_cms/engine/admin_permissions.rb +69 -0
- data/lib/ruby_cms/engine/content_blocks_tasks.rb +66 -0
- data/lib/ruby_cms/engine/css.rb +14 -0
- data/lib/ruby_cms/engine/dashboard_registration.rb +66 -0
- data/lib/ruby_cms/engine/navigation_registration.rb +80 -0
- data/lib/ruby_cms/engine.rb +23 -278
- data/lib/ruby_cms/icons.rb +118 -0
- data/lib/ruby_cms/version.rb +1 -1
- data/lib/ruby_cms.rb +36 -10
- metadata +28 -1
data/lib/ruby_cms/engine.rb
CHANGED
|
@@ -2,9 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative "settings_registry"
|
|
4
4
|
require_relative "settings"
|
|
5
|
+
require_relative "dashboard_blocks"
|
|
6
|
+
require_relative "engine/css"
|
|
7
|
+
require_relative "engine/dashboard_registration"
|
|
8
|
+
require_relative "engine/navigation_registration"
|
|
9
|
+
require_relative "engine/admin_permissions"
|
|
10
|
+
require_relative "engine/content_blocks_tasks"
|
|
5
11
|
|
|
6
12
|
module RubyCms
|
|
7
13
|
class Engine < ::Rails::Engine
|
|
14
|
+
extend RubyCms::EngineCss
|
|
15
|
+
extend RubyCms::EngineDashboardRegistration
|
|
16
|
+
extend RubyCms::EngineNavigationRegistration
|
|
17
|
+
extend RubyCms::EngineAdminPermissions
|
|
18
|
+
extend RubyCms::EngineContentBlocksTasks
|
|
19
|
+
|
|
8
20
|
# Do not isolate namespace so we can use /admin and explicit table names.
|
|
9
21
|
# Engine models use unprefixed table names: content_blocks, preferences, permissions, user_permissions, visitor_errors.
|
|
10
22
|
|
|
@@ -69,6 +81,7 @@ module RubyCms
|
|
|
69
81
|
helper RubyCms::BulkActionTableHelper
|
|
70
82
|
helper RubyCms::Admin::BulkActionTableHelper
|
|
71
83
|
helper RubyCms::Admin::AdminPageHelper
|
|
84
|
+
helper RubyCms::Admin::DashboardHelper
|
|
72
85
|
end
|
|
73
86
|
end
|
|
74
87
|
|
|
@@ -96,6 +109,16 @@ module RubyCms
|
|
|
96
109
|
end
|
|
97
110
|
end
|
|
98
111
|
|
|
112
|
+
initializer "ruby_cms.dashboard_blocks" do
|
|
113
|
+
RubyCms::Engine.register_default_dashboard_blocks
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
initializer "ruby_cms.versionable" do
|
|
117
|
+
Rails.application.config.to_prepare do
|
|
118
|
+
ContentBlock.include(ContentBlock::Versionable) unless ContentBlock <= ContentBlock::Versionable
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
99
122
|
initializer "ruby_cms.settings_import", after: :load_config_initializers do
|
|
100
123
|
RubyCms::Settings.import_initializer_values!
|
|
101
124
|
end
|
|
@@ -108,159 +131,6 @@ module RubyCms
|
|
|
108
131
|
Rails.logger.warn("[RubyCMS] Permission.ensure_defaults! skipped: #{e.message}")
|
|
109
132
|
end
|
|
110
133
|
|
|
111
|
-
def self.register_main_nav_items
|
|
112
|
-
RubyCms.nav_register(
|
|
113
|
-
key: :dashboard,
|
|
114
|
-
label: "Dashboard",
|
|
115
|
-
path: lambda(&:ruby_cms_admin_root_path),
|
|
116
|
-
icon: dashboard_icon_path,
|
|
117
|
-
section: RubyCms::NAV_SECTION_MAIN,
|
|
118
|
-
permission: :manage_admin,
|
|
119
|
-
order: 1
|
|
120
|
-
)
|
|
121
|
-
RubyCms.nav_register(
|
|
122
|
-
key: :visual_editor,
|
|
123
|
-
label: "Visual editor",
|
|
124
|
-
path: lambda(&:ruby_cms_admin_visual_editor_path),
|
|
125
|
-
icon: visual_editor_icon_path,
|
|
126
|
-
section: RubyCms::NAV_SECTION_MAIN,
|
|
127
|
-
permission: :manage_content_blocks,
|
|
128
|
-
order: 2
|
|
129
|
-
)
|
|
130
|
-
RubyCms.nav_register(
|
|
131
|
-
key: :content_blocks,
|
|
132
|
-
label: "Content blocks",
|
|
133
|
-
path: lambda(&:ruby_cms_admin_content_blocks_path),
|
|
134
|
-
icon: content_blocks_icon_path,
|
|
135
|
-
section: RubyCms::NAV_SECTION_MAIN,
|
|
136
|
-
permission: :manage_content_blocks,
|
|
137
|
-
order: 3
|
|
138
|
-
)
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
def self.dashboard_icon_path
|
|
142
|
-
# Heroicons HomeIcon (outline)
|
|
143
|
-
'<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" ' \
|
|
144
|
-
'd="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3' \
|
|
145
|
-
'm-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"></path>'
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
def self.content_blocks_icon_path
|
|
149
|
-
# Heroicons DocumentDuplicateIcon (outline)
|
|
150
|
-
'<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" ' \
|
|
151
|
-
'd="M8 7v8a2 2 0 002 2h6M8 7V5a2 2 0 012-2h4.586a1 1 0 01.707.293l4.414 4.414' \
|
|
152
|
-
'a1 1 0 01.293.707V15a2 2 0 01-2 2h-2M8 7H6a2 2 0 00-2 2v10a2 2 0 002 2h8a2 2 ' \
|
|
153
|
-
'0 002-2v-2"></path>'
|
|
154
|
-
end
|
|
155
|
-
|
|
156
|
-
def self.visual_editor_icon_path
|
|
157
|
-
# Heroicons PencilSquareIcon (outline)
|
|
158
|
-
'<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" ' \
|
|
159
|
-
'd="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 ' \
|
|
160
|
-
'0 012.828 2.828L11.828 15H9v-2.828l8.586-8.586z"></path>'
|
|
161
|
-
end
|
|
162
|
-
|
|
163
|
-
def self.register_settings_nav_items
|
|
164
|
-
RubyCms.nav_register(
|
|
165
|
-
key: :analytics,
|
|
166
|
-
label: "Analytics",
|
|
167
|
-
path: lambda(&:ruby_cms_admin_analytics_path),
|
|
168
|
-
section: RubyCms::NAV_SECTION_BOTTOM,
|
|
169
|
-
icon: analytics_icon_path,
|
|
170
|
-
permission: :manage_analytics,
|
|
171
|
-
order: 1
|
|
172
|
-
)
|
|
173
|
-
RubyCms.nav_register(
|
|
174
|
-
key: :permissions,
|
|
175
|
-
label: "Permissions",
|
|
176
|
-
path: lambda(&:ruby_cms_admin_permissions_path),
|
|
177
|
-
section: RubyCms::NAV_SECTION_BOTTOM,
|
|
178
|
-
icon: permissions_icon_path,
|
|
179
|
-
permission: :manage_permissions,
|
|
180
|
-
order: 2
|
|
181
|
-
)
|
|
182
|
-
RubyCms.nav_register(
|
|
183
|
-
key: :visitor_errors,
|
|
184
|
-
label: "Visitor errors",
|
|
185
|
-
path: lambda(&:ruby_cms_admin_visitor_errors_path),
|
|
186
|
-
section: RubyCms::NAV_SECTION_BOTTOM,
|
|
187
|
-
icon: visitor_errors_icon_path,
|
|
188
|
-
permission: :manage_visitor_errors,
|
|
189
|
-
order: 3
|
|
190
|
-
)
|
|
191
|
-
RubyCms.nav_register(
|
|
192
|
-
key: :users,
|
|
193
|
-
label: "Users",
|
|
194
|
-
path: lambda(&:ruby_cms_admin_users_path),
|
|
195
|
-
section: RubyCms::NAV_SECTION_BOTTOM,
|
|
196
|
-
icon: users_icon_path,
|
|
197
|
-
permission: :manage_permissions,
|
|
198
|
-
order: 4
|
|
199
|
-
)
|
|
200
|
-
RubyCms.nav_register(
|
|
201
|
-
key: :settings,
|
|
202
|
-
label: "Settings",
|
|
203
|
-
path: lambda(&:ruby_cms_admin_settings_path),
|
|
204
|
-
section: RubyCms::NAV_SECTION_BOTTOM,
|
|
205
|
-
icon: settings_icon_path,
|
|
206
|
-
permission: :manage_admin,
|
|
207
|
-
order: 5
|
|
208
|
-
)
|
|
209
|
-
end
|
|
210
|
-
|
|
211
|
-
def self.settings_icon_path
|
|
212
|
-
# Heroicons Cog6ToothIcon (outline)
|
|
213
|
-
'<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" ' \
|
|
214
|
-
'd="M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 ' \
|
|
215
|
-
'1.281c.063.374.313.686.645.87.074.04.147.083.22.127.324.196.72.257 1.075.124l1.217-.456a1.125 ' \
|
|
216
|
-
'1.125 0 011.37.49l1.296 2.247a1.125 1.125 0 01-.26 1.431l-1.003.827c-.293.24-.438.613-.431.992a6.759 ' \
|
|
217
|
-
'6.759 0 010 .255c-.007.378.138.75.43.99l1.005.828c.424.35.534.954.26 1.43l-1.298 2.247a1.125 1.125 ' \
|
|
218
|
-
'0 01-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.57 6.57 0 01-.22.128c-.331.183-.581.495-.644.869l-.213 ' \
|
|
219
|
-
'1.28c-.09.543-.56.941-1.11.941h-2.594c-.55 0-1.02-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 ' \
|
|
220
|
-
'6.52 0 01-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 01-1.369-.49l-1.297-2.247a1.125 ' \
|
|
221
|
-
'1.125 0 01.26-1.431l1.004-.827c.292-.24.437-.613.43-.992a6.932 6.932 0 010-.255c.007-.378-.138-.75-.43-.99l-1.004-.828a1.125 ' \
|
|
222
|
-
'1.125 0 01-.26-1.43l1.297-2.247a1.125 1.125 0 011.37-.491l1.216.456c.356.133.751.072 1.076-.124.072-.044.146-.087.22-.128.332-.183.582-.495.644-.869l.214-1.281z"></path>' \
|
|
223
|
-
'<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>'
|
|
224
|
-
end
|
|
225
|
-
|
|
226
|
-
def self.visitor_errors_icon_path
|
|
227
|
-
# Heroicons ExclamationTriangleIcon (outline)
|
|
228
|
-
'<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" ' \
|
|
229
|
-
'd="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 ' \
|
|
230
|
-
'4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"></path>'
|
|
231
|
-
end
|
|
232
|
-
|
|
233
|
-
def self.permissions_icon_path
|
|
234
|
-
# Heroicons ShieldCheckIcon (outline)
|
|
235
|
-
'<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" ' \
|
|
236
|
-
'd="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01' \
|
|
237
|
-
'-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 ' \
|
|
238
|
-
'9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"></path>'
|
|
239
|
-
end
|
|
240
|
-
|
|
241
|
-
def self.users_icon_path
|
|
242
|
-
# Heroicons UserGroupIcon (outline)
|
|
243
|
-
'<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" ' \
|
|
244
|
-
'd="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 ' \
|
|
245
|
-
'00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z"></path>'
|
|
246
|
-
end
|
|
247
|
-
|
|
248
|
-
def self.analytics_icon_path
|
|
249
|
-
'<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" ' \
|
|
250
|
-
'd="M3 3v18h18"></path>' \
|
|
251
|
-
'<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" ' \
|
|
252
|
-
'd="M7 13l3-3 3 2 4-5"></path>'
|
|
253
|
-
end
|
|
254
|
-
|
|
255
|
-
def self.compile_admin_css(dest_path)
|
|
256
|
-
gem_root = begin
|
|
257
|
-
root
|
|
258
|
-
rescue StandardError
|
|
259
|
-
Pathname.new(File.expand_path("../..", __dir__))
|
|
260
|
-
end
|
|
261
|
-
RubyCms::CssCompiler.compile(gem_root, dest_path)
|
|
262
|
-
end
|
|
263
|
-
|
|
264
134
|
config.paths.add "db/migrate", with: "db/migrate"
|
|
265
135
|
|
|
266
136
|
rake_tasks do # rubocop:disable Metrics/BlockLength
|
|
@@ -372,131 +242,6 @@ module RubyCms
|
|
|
372
242
|
end
|
|
373
243
|
end
|
|
374
244
|
|
|
375
|
-
def self.grant_admin_permissions_to_admin_users
|
|
376
|
-
return unless defined?(::User) && User.column_names.include?("admin")
|
|
377
|
-
|
|
378
|
-
permission_keys = RubyCms::Permission.all_keys
|
|
379
|
-
permissions = RubyCms::Permission.where(key: permission_keys).index_by(&:key)
|
|
380
|
-
User.where(admin: true).find_each do |u|
|
|
381
|
-
permission_keys.each do |key|
|
|
382
|
-
perm = permissions[key]
|
|
383
|
-
next if perm.nil?
|
|
384
|
-
|
|
385
|
-
RubyCms::UserPermission.find_or_create_by!(user: u, permission: perm)
|
|
386
|
-
end
|
|
387
|
-
end
|
|
388
|
-
end
|
|
389
|
-
|
|
390
|
-
def self.extract_email_from_args(args)
|
|
391
|
-
args[:email] || ENV["email"] || ENV.fetch("EMAIL", nil)
|
|
392
|
-
end
|
|
393
|
-
|
|
394
|
-
def self.validate_email_present(email)
|
|
395
|
-
return if email.present?
|
|
396
|
-
|
|
397
|
-
warn "Usage: rails ruby_cms:grant_manage_admin " \
|
|
398
|
-
"email=user@example.com"
|
|
399
|
-
raise "Email is required"
|
|
400
|
-
end
|
|
401
|
-
|
|
402
|
-
def self.find_user_by_email(email)
|
|
403
|
-
user_class = Rails.application.config.ruby_cms.user_class_name
|
|
404
|
-
.constantize
|
|
405
|
-
find_user_by_email_address(user_class, email) ||
|
|
406
|
-
find_user_by_email_column(user_class, email)
|
|
407
|
-
end
|
|
408
|
-
|
|
409
|
-
def self.find_user_by_email_address(user_class, email)
|
|
410
|
-
return unless user_class.column_names.include?("email_address")
|
|
411
|
-
|
|
412
|
-
user_class.find_by(email_address: email)
|
|
413
|
-
end
|
|
414
|
-
|
|
415
|
-
def self.find_user_by_email_column(user_class, email)
|
|
416
|
-
return unless user_class.column_names.include?("email")
|
|
417
|
-
|
|
418
|
-
user_class.find_by(email:)
|
|
419
|
-
end
|
|
420
|
-
|
|
421
|
-
def self.validate_user_found(user, email)
|
|
422
|
-
return if user
|
|
423
|
-
|
|
424
|
-
warn "User not found: #{email}"
|
|
425
|
-
raise "User not found: #{email}"
|
|
426
|
-
end
|
|
427
|
-
|
|
428
|
-
def self.grant_manage_admin_permission(user, email)
|
|
429
|
-
RubyCms::Permission.ensure_defaults!
|
|
430
|
-
RubyCms::Permission.all_keys.each do |key|
|
|
431
|
-
perm = RubyCms::Permission.find_by(key:)
|
|
432
|
-
next unless perm
|
|
433
|
-
|
|
434
|
-
RubyCms::UserPermission.find_or_create_by!(user: user, permission: perm)
|
|
435
|
-
end
|
|
436
|
-
puts "Granted full admin permissions to #{email}" # rubocop:disable Rails/Output
|
|
437
|
-
end
|
|
438
|
-
|
|
439
|
-
def self.parse_locales_dir(locales_dir_arg)
|
|
440
|
-
return nil unless locales_dir_arg.presence
|
|
441
|
-
|
|
442
|
-
Pathname.new(locales_dir_arg)
|
|
443
|
-
end
|
|
444
|
-
|
|
445
|
-
def self.parse_import_options
|
|
446
|
-
{
|
|
447
|
-
create_missing: ENV["create_missing"] != "false",
|
|
448
|
-
update_existing: ENV["update_existing"] != "false",
|
|
449
|
-
published: ENV["published"] == "true"
|
|
450
|
-
}
|
|
451
|
-
end
|
|
452
|
-
|
|
453
|
-
def self.display_export_summary(summary)
|
|
454
|
-
if summary.empty?
|
|
455
|
-
puts "No content blocks found to export." # rubocop:disable Rails/Output
|
|
456
|
-
else
|
|
457
|
-
puts "Exported content blocks to locale files:" # rubocop:disable Rails/Output
|
|
458
|
-
summary.each do |locale, count|
|
|
459
|
-
# rubocop:disable Rails/Output
|
|
460
|
-
puts " #{locale}: #{count} block(s) updated " \
|
|
461
|
-
"in config/locales/#{locale}.yml"
|
|
462
|
-
# rubocop:enable Rails/Output
|
|
463
|
-
end
|
|
464
|
-
end
|
|
465
|
-
end
|
|
466
|
-
|
|
467
|
-
def self.display_import_summary(summary)
|
|
468
|
-
$stdout.puts "Import summary:"
|
|
469
|
-
$stdout.puts " Created: #{summary[:created]}"
|
|
470
|
-
$stdout.puts " Updated: #{summary[:updated]}"
|
|
471
|
-
$stdout.puts " Skipped: #{summary[:skipped]}"
|
|
472
|
-
return unless summary[:errors].any?
|
|
473
|
-
|
|
474
|
-
$stdout.puts " Errors:"
|
|
475
|
-
summary[:errors].each {|e| $stdout.puts " - #{e}" }
|
|
476
|
-
end
|
|
477
|
-
|
|
478
|
-
def self.display_sync_summary(result, import_after)
|
|
479
|
-
display_export_results(result[:export])
|
|
480
|
-
display_import_results(result[:import], import_after) if import_after
|
|
481
|
-
end
|
|
482
|
-
|
|
483
|
-
def self.display_export_results(export_data)
|
|
484
|
-
$stdout.puts "Sync complete!"
|
|
485
|
-
$stdout.puts "\nExport summary:"
|
|
486
|
-
export_data.each do |locale, count|
|
|
487
|
-
$stdout.puts " #{locale}: #{count} block(s) updated"
|
|
488
|
-
end
|
|
489
|
-
end
|
|
490
|
-
|
|
491
|
-
def self.display_import_results(import_data, import_after)
|
|
492
|
-
return unless import_after && import_data.any?
|
|
493
|
-
|
|
494
|
-
$stdout.puts "\nImport summary:"
|
|
495
|
-
$stdout.puts " Created: #{import_data[:created]}"
|
|
496
|
-
$stdout.puts " Updated: #{import_data[:updated]}"
|
|
497
|
-
$stdout.puts " Skipped: #{import_data[:skipped]}"
|
|
498
|
-
end
|
|
499
|
-
|
|
500
245
|
initializer "ruby_cms.load_migrations" do |app|
|
|
501
246
|
next unless app.config.respond_to?(:paths)
|
|
502
247
|
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyCms
|
|
4
|
+
module Icons
|
|
5
|
+
# Named Heroicon SVG path fragments (outline style, 24x24 viewBox).
|
|
6
|
+
# Use symbol keys with nav_register / register_page: `icon: :home`
|
|
7
|
+
# Raw SVG strings are still accepted for custom icons.
|
|
8
|
+
REGISTRY = {
|
|
9
|
+
home: '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" ' \
|
|
10
|
+
'd="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3' \
|
|
11
|
+
'm-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"></path>',
|
|
12
|
+
|
|
13
|
+
pencil_square: '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" ' \
|
|
14
|
+
'd="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 ' \
|
|
15
|
+
'0 012.828 2.828L11.828 15H9v-2.828l8.586-8.586z"></path>',
|
|
16
|
+
|
|
17
|
+
document_duplicate: '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" ' \
|
|
18
|
+
'd="M8 7v8a2 2 0 002 2h6M8 7V5a2 2 0 012-2h4.586a1 1 0 01.707.293l4.414 4.414' \
|
|
19
|
+
'a1 1 0 01.293.707V15a2 2 0 01-2 2h-2M8 7H6a2 2 0 00-2 2v10a2 2 0 002 2h8a2 2 ' \
|
|
20
|
+
'0 002-2v-2"></path>',
|
|
21
|
+
|
|
22
|
+
chart_bar: '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" ' \
|
|
23
|
+
'd="M3 3v18h18"></path>' \
|
|
24
|
+
'<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" ' \
|
|
25
|
+
'd="M7 13l3-3 3 2 4-5"></path>',
|
|
26
|
+
|
|
27
|
+
shield_check: '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" ' \
|
|
28
|
+
'd="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01' \
|
|
29
|
+
'-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 ' \
|
|
30
|
+
'9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"></path>',
|
|
31
|
+
|
|
32
|
+
exclamation_triangle: '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" ' \
|
|
33
|
+
'd="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 ' \
|
|
34
|
+
'4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"></path>',
|
|
35
|
+
|
|
36
|
+
user_group: '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" ' \
|
|
37
|
+
'd="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 ' \
|
|
38
|
+
'00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z"></path>',
|
|
39
|
+
|
|
40
|
+
cog_6_tooth: '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" ' \
|
|
41
|
+
'd="M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 ' \
|
|
42
|
+
'1.281c.063.374.313.686.645.87.074.04.147.083.22.127.324.196.72.257 1.075.124l1.217-.456a1.125 ' \
|
|
43
|
+
'1.125 0 011.37.49l1.296 2.247a1.125 1.125 0 01-.26 1.431l-1.003.827c-.293.24-.438.613-.431.992a6.759 ' \
|
|
44
|
+
'6.759 0 010 .255c-.007.378.138.75.43.99l1.005.828c.424.35.534.954.26 1.43l-1.298 2.247a1.125 1.125 ' \
|
|
45
|
+
'0 01-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.57 6.57 0 01-.22.128c-.331.183-.581.495-.644.869l-.213 ' \
|
|
46
|
+
'1.28c-.09.543-.56.941-1.11.941h-2.594c-.55 0-1.02-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 ' \
|
|
47
|
+
'6.52 0 01-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 01-1.369-.49l-1.297-2.247a1.125 ' \
|
|
48
|
+
'1.125 0 01.26-1.431l1.004-.827c.292-.24.437-.613.43-.992a6.932 6.932 0 010-.255c.007-.378-.138-.75-.43-.99l-1.004-.828a1.125 ' \
|
|
49
|
+
'1.125 0 01-.26-1.43l1.297-2.247a1.125 1.125 0 011.37-.491l1.216.456c.356.133.751.072 1.076-.124.072-.044.146-.087.22-.128.332-.183.582-.495.644-.869l.214-1.281z"></path>' \
|
|
50
|
+
'<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>',
|
|
51
|
+
|
|
52
|
+
# Extra icons for host-app admin pages
|
|
53
|
+
archive_box: '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" ' \
|
|
54
|
+
'd="M5 8h14M5 8a2 2 0 110-4h14a2 2 0 110 4M5 8v10a2 2 0 002 2h10a2 2 0 002-2V8m-9 4h4"></path>',
|
|
55
|
+
|
|
56
|
+
folder: '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" ' \
|
|
57
|
+
'd="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z"></path>',
|
|
58
|
+
|
|
59
|
+
bell: '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" ' \
|
|
60
|
+
'd="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9"></path>',
|
|
61
|
+
|
|
62
|
+
clock: '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" ' \
|
|
63
|
+
'd="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"></path>',
|
|
64
|
+
|
|
65
|
+
tag: '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" ' \
|
|
66
|
+
'd="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z"></path>',
|
|
67
|
+
|
|
68
|
+
cube: '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" ' \
|
|
69
|
+
'd="M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4"></path>',
|
|
70
|
+
|
|
71
|
+
envelope: '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" ' \
|
|
72
|
+
'd="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"></path>',
|
|
73
|
+
|
|
74
|
+
wrench: '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" ' \
|
|
75
|
+
'd="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.066 2.573c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.573 1.066c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.066-2.573c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"></path>' \
|
|
76
|
+
'<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>',
|
|
77
|
+
|
|
78
|
+
globe: '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" ' \
|
|
79
|
+
'd="M21 12a9 9 0 01-9 9m9-9a9 9 0 00-9-9m9 9H3m9 9a9 9 0 01-9-9m9 9c1.657 0 3-4.03 3-9s-1.343-9-3-9m0 18c-1.657 0-3-4.03-3-9s1.343-9 3-9m-9 9a9 9 0 019-9"></path>',
|
|
80
|
+
|
|
81
|
+
photograph: '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" ' \
|
|
82
|
+
'd="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"></path>',
|
|
83
|
+
|
|
84
|
+
list_bullet: '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" ' \
|
|
85
|
+
'd="M4 6h16M4 10h16M4 14h16M4 18h16"></path>',
|
|
86
|
+
|
|
87
|
+
plus_circle: '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" ' \
|
|
88
|
+
'd="M12 9v3m0 0v3m0-3h3m-3 0H9m12 0a9 9 0 11-18 0 9 9 0 0118 0z"></path>',
|
|
89
|
+
|
|
90
|
+
trash: '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" ' \
|
|
91
|
+
'd="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"></path>',
|
|
92
|
+
|
|
93
|
+
eye: '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" ' \
|
|
94
|
+
'd="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>' \
|
|
95
|
+
'<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" ' \
|
|
96
|
+
'd="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"></path>',
|
|
97
|
+
|
|
98
|
+
lock_closed: '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" ' \
|
|
99
|
+
'd="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"></path>',
|
|
100
|
+
|
|
101
|
+
currency_dollar: '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" ' \
|
|
102
|
+
'd="M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>'
|
|
103
|
+
}.freeze
|
|
104
|
+
|
|
105
|
+
def self.resolve(name_or_svg)
|
|
106
|
+
return name_or_svg if name_or_svg.kind_of?(String) && name_or_svg.include?("<")
|
|
107
|
+
return nil if name_or_svg.nil?
|
|
108
|
+
|
|
109
|
+
REGISTRY.fetch(name_or_svg.to_sym) do
|
|
110
|
+
raise ArgumentError, "Unknown icon: #{name_or_svg}. Available: #{REGISTRY.keys.join(', ')}"
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def self.available
|
|
115
|
+
REGISTRY.keys
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
data/lib/ruby_cms/version.rb
CHANGED
data/lib/ruby_cms.rb
CHANGED
|
@@ -4,6 +4,8 @@ require_relative "ruby_cms/version"
|
|
|
4
4
|
require_relative "ruby_cms/css_compiler"
|
|
5
5
|
require_relative "ruby_cms/settings_registry"
|
|
6
6
|
require_relative "ruby_cms/settings"
|
|
7
|
+
require_relative "ruby_cms/icons"
|
|
8
|
+
require_relative "ruby_cms/dashboard_blocks"
|
|
7
9
|
require_relative "ruby_cms/engine"
|
|
8
10
|
require_relative "ruby_cms/app_integration"
|
|
9
11
|
require_relative "ruby_cms/content_blocks_sync"
|
|
@@ -45,11 +47,6 @@ module RubyCms
|
|
|
45
47
|
NAV_SECTION_MAIN = "main"
|
|
46
48
|
NAV_SECTION_BOTTOM = "Settings"
|
|
47
49
|
|
|
48
|
-
ANALYTICS_ICON_PATH = '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" ' \
|
|
49
|
-
'd="M3 3v18h18"></path>' \
|
|
50
|
-
'<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" ' \
|
|
51
|
-
'd="M7 13l3-3 3 2 4-5"></path>'
|
|
52
|
-
|
|
53
50
|
def self.configure
|
|
54
51
|
yield(Rails.application.config.ruby_cms)
|
|
55
52
|
end
|
|
@@ -64,8 +61,8 @@ module RubyCms
|
|
|
64
61
|
# Options:
|
|
65
62
|
# - key: required Symbol/String
|
|
66
63
|
# - label: required String
|
|
67
|
-
# - path:
|
|
68
|
-
# - icon:
|
|
64
|
+
# - path: String, Symbol (route helper name, auto-wrapped via main_app), or callable(view_context) -> path
|
|
65
|
+
# - icon: Symbol (named icon from RubyCms::Icons) or raw SVG path fragment string
|
|
69
66
|
# - section: "main" | "Settings" (or nil => main)
|
|
70
67
|
# - order: optional Integer for sorting within section
|
|
71
68
|
# - permission: optional permission key (e.g., :manage_analytics)
|
|
@@ -74,11 +71,13 @@ module RubyCms
|
|
|
74
71
|
def self.nav_register(key:, label:, path:, icon: nil, section: nil, order: nil, permission: nil, default_visible: true, **options)
|
|
75
72
|
normalized_key = key.to_sym
|
|
76
73
|
normalized_section = section.presence || NAV_SECTION_MAIN
|
|
74
|
+
resolved_path = path.kind_of?(Symbol) ? ->(v) { v.main_app.send(path) } : path
|
|
75
|
+
resolved_icon = icon.nil? ? nil : RubyCms::Icons.resolve(icon)
|
|
77
76
|
entry = {
|
|
78
77
|
key: normalized_key,
|
|
79
78
|
label: label.to_s,
|
|
80
|
-
path:
|
|
81
|
-
icon:
|
|
79
|
+
path: resolved_path,
|
|
80
|
+
icon: resolved_icon,
|
|
82
81
|
section: normalized_section,
|
|
83
82
|
order: order,
|
|
84
83
|
permission: permission&.to_s,
|
|
@@ -94,8 +93,35 @@ module RubyCms
|
|
|
94
93
|
entry
|
|
95
94
|
end
|
|
96
95
|
|
|
96
|
+
VALID_PAGE_SECTIONS = %i[main settings].freeze
|
|
97
|
+
|
|
98
|
+
# Unified API to register an admin page: nav item + permission key in one call.
|
|
99
|
+
# Accepts :main or :settings for section (resolved to NAV_SECTION_MAIN / NAV_SECTION_BOTTOM).
|
|
100
|
+
# Automatically registers the permission key if provided.
|
|
101
|
+
def self.register_page(
|
|
102
|
+
key:, label:, path:, icon: nil, section: :main, order: nil,
|
|
103
|
+
permission: nil, default_visible: true, **
|
|
104
|
+
)
|
|
105
|
+
raise ArgumentError, "register_page section must be :main or :settings, got #{section.inspect}" unless VALID_PAGE_SECTIONS.include?(section.to_s.to_sym)
|
|
106
|
+
|
|
107
|
+
register_permission_keys(permission) if permission.present?
|
|
108
|
+
resolved_section = section.to_s == "settings" ? NAV_SECTION_BOTTOM : NAV_SECTION_MAIN
|
|
109
|
+
nav_register(
|
|
110
|
+
key: key,
|
|
111
|
+
label: label,
|
|
112
|
+
path: path,
|
|
113
|
+
icon: icon,
|
|
114
|
+
section: resolved_section,
|
|
115
|
+
order: order,
|
|
116
|
+
permission: permission,
|
|
117
|
+
default_visible: default_visible,
|
|
118
|
+
**
|
|
119
|
+
)
|
|
120
|
+
end
|
|
121
|
+
|
|
97
122
|
# Returns only entries that pass settings + permissions + conditional checks,
|
|
98
123
|
# sorted by saved nav_order (Settings → Navigation drag-and-drop) when set, else by section + order.
|
|
124
|
+
# Fail-closed: returns empty array on error (never exposes unfiltered items).
|
|
99
125
|
def self.visible_nav_registry(view_context: nil, user: nil)
|
|
100
126
|
list = nav_registry
|
|
101
127
|
.select {|item| nav_entry_visible?(item, view_context:, user:) }
|
|
@@ -103,7 +129,7 @@ module RubyCms
|
|
|
103
129
|
localize_nav_labels(apply_nav_order(list))
|
|
104
130
|
rescue StandardError => e
|
|
105
131
|
Rails.logger.error("[RubyCMS] Error filtering navigation: #{e.message}") if defined?(Rails.logger)
|
|
106
|
-
|
|
132
|
+
[]
|
|
107
133
|
end
|
|
108
134
|
|
|
109
135
|
module Nav
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ruby_cms
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Codebyjob
|
|
@@ -96,6 +96,7 @@ files:
|
|
|
96
96
|
- app/controllers/concerns/ruby_cms/visitor_error_capture.rb
|
|
97
97
|
- app/controllers/ruby_cms/admin/analytics_controller.rb
|
|
98
98
|
- app/controllers/ruby_cms/admin/base_controller.rb
|
|
99
|
+
- app/controllers/ruby_cms/admin/content_block_versions_controller.rb
|
|
99
100
|
- app/controllers/ruby_cms/admin/content_blocks_controller.rb
|
|
100
101
|
- app/controllers/ruby_cms/admin/dashboard_controller.rb
|
|
101
102
|
- app/controllers/ruby_cms/admin/locale_controller.rb
|
|
@@ -108,6 +109,7 @@ files:
|
|
|
108
109
|
- app/controllers/ruby_cms/errors_controller.rb
|
|
109
110
|
- app/helpers/ruby_cms/admin/admin_page_helper.rb
|
|
110
111
|
- app/helpers/ruby_cms/admin/bulk_action_table_helper.rb
|
|
112
|
+
- app/helpers/ruby_cms/admin/dashboard_helper.rb
|
|
111
113
|
- app/helpers/ruby_cms/application_helper.rb
|
|
112
114
|
- app/helpers/ruby_cms/bulk_action_table_helper.rb
|
|
113
115
|
- app/helpers/ruby_cms/content_blocks_helper.rb
|
|
@@ -115,6 +117,7 @@ files:
|
|
|
115
117
|
- app/javascript/controllers/ruby_cms/auto_save_preference_controller.js
|
|
116
118
|
- app/javascript/controllers/ruby_cms/bulk_action_table_controller.js
|
|
117
119
|
- app/javascript/controllers/ruby_cms/clickable_row_controller.js
|
|
120
|
+
- app/javascript/controllers/ruby_cms/content_block_history_controller.js
|
|
118
121
|
- app/javascript/controllers/ruby_cms/flash_messages_controller.js
|
|
119
122
|
- app/javascript/controllers/ruby_cms/index.js
|
|
120
123
|
- app/javascript/controllers/ruby_cms/locale_tabs_controller.js
|
|
@@ -125,7 +128,9 @@ files:
|
|
|
125
128
|
- app/javascript/controllers/ruby_cms/visual_editor_controller.js
|
|
126
129
|
- app/models/concerns/content_block/publishable.rb
|
|
127
130
|
- app/models/concerns/content_block/searchable.rb
|
|
131
|
+
- app/models/concerns/content_block/versionable.rb
|
|
128
132
|
- app/models/content_block.rb
|
|
133
|
+
- app/models/content_block_version.rb
|
|
129
134
|
- app/models/ruby_cms/content_block.rb
|
|
130
135
|
- app/models/ruby_cms/permission.rb
|
|
131
136
|
- app/models/ruby_cms/permittable.rb
|
|
@@ -134,6 +139,8 @@ files:
|
|
|
134
139
|
- app/models/ruby_cms/visitor_error.rb
|
|
135
140
|
- app/services/ruby_cms/analytics/report.rb
|
|
136
141
|
- app/services/ruby_cms/security_tracker.rb
|
|
142
|
+
- app/views/admin/content_block_versions/index.html.erb
|
|
143
|
+
- app/views/admin/content_block_versions/show.html.erb
|
|
137
144
|
- app/views/layouts/ruby_cms/_admin_flash_messages.html.erb
|
|
138
145
|
- app/views/layouts/ruby_cms/_admin_sidebar.html.erb
|
|
139
146
|
- app/views/layouts/ruby_cms/admin.html.erb
|
|
@@ -153,11 +160,20 @@ files:
|
|
|
153
160
|
- app/views/ruby_cms/admin/analytics/partials/_top_visitors.html.erb
|
|
154
161
|
- app/views/ruby_cms/admin/analytics/partials/_utm_sources.html.erb
|
|
155
162
|
- app/views/ruby_cms/admin/analytics/visitor_details.html.erb
|
|
163
|
+
- app/views/ruby_cms/admin/content_block_versions/index.html.erb
|
|
164
|
+
- app/views/ruby_cms/admin/content_block_versions/show.html.erb
|
|
156
165
|
- app/views/ruby_cms/admin/content_blocks/_form.html.erb
|
|
157
166
|
- app/views/ruby_cms/admin/content_blocks/_row.html.erb
|
|
158
167
|
- app/views/ruby_cms/admin/content_blocks/index.html.erb
|
|
159
168
|
- app/views/ruby_cms/admin/content_blocks/new.html.erb
|
|
160
169
|
- app/views/ruby_cms/admin/content_blocks/show.html.erb
|
|
170
|
+
- app/views/ruby_cms/admin/dashboard/blocks/_analytics_overview.html.erb
|
|
171
|
+
- app/views/ruby_cms/admin/dashboard/blocks/_content_blocks_stats.html.erb
|
|
172
|
+
- app/views/ruby_cms/admin/dashboard/blocks/_permissions_stats.html.erb
|
|
173
|
+
- app/views/ruby_cms/admin/dashboard/blocks/_quick_actions.html.erb
|
|
174
|
+
- app/views/ruby_cms/admin/dashboard/blocks/_recent_errors.html.erb
|
|
175
|
+
- app/views/ruby_cms/admin/dashboard/blocks/_users_stats.html.erb
|
|
176
|
+
- app/views/ruby_cms/admin/dashboard/blocks/_visitor_errors_stats.html.erb
|
|
161
177
|
- app/views/ruby_cms/admin/dashboard/index.html.erb
|
|
162
178
|
- app/views/ruby_cms/admin/permissions/_row.html.erb
|
|
163
179
|
- app/views/ruby_cms/admin/permissions/index.html.erb
|
|
@@ -187,10 +203,14 @@ files:
|
|
|
187
203
|
- db/migrate/20260130000003_add_category_to_ruby_cms_preferences.rb
|
|
188
204
|
- db/migrate/20260211000001_add_ruby_cms_analytics_fields_to_ahoy_events.rb
|
|
189
205
|
- db/migrate/20260212000001_use_unprefixed_cms_tables.rb
|
|
206
|
+
- db/migrate/20260328000001_create_content_block_versions.rb
|
|
190
207
|
- docs/assets/ruby_cms_logo.png
|
|
191
208
|
- exe/ruby_cms
|
|
209
|
+
- lib/generators/ruby_cms/admin_page_generator.rb
|
|
192
210
|
- lib/generators/ruby_cms/install_generator.rb
|
|
193
211
|
- lib/generators/ruby_cms/templates/admin.html.erb
|
|
212
|
+
- lib/generators/ruby_cms/templates/admin_page/controller.rb.tt
|
|
213
|
+
- lib/generators/ruby_cms/templates/admin_page/index.html.erb.tt
|
|
194
214
|
- lib/generators/ruby_cms/templates/ruby_cms.rb
|
|
195
215
|
- lib/ruby_cms.rb
|
|
196
216
|
- lib/ruby_cms/app_integration.rb
|
|
@@ -198,7 +218,14 @@ files:
|
|
|
198
218
|
- lib/ruby_cms/content_blocks_grouping.rb
|
|
199
219
|
- lib/ruby_cms/content_blocks_sync.rb
|
|
200
220
|
- lib/ruby_cms/css_compiler.rb
|
|
221
|
+
- lib/ruby_cms/dashboard_blocks.rb
|
|
201
222
|
- lib/ruby_cms/engine.rb
|
|
223
|
+
- lib/ruby_cms/engine/admin_permissions.rb
|
|
224
|
+
- lib/ruby_cms/engine/content_blocks_tasks.rb
|
|
225
|
+
- lib/ruby_cms/engine/css.rb
|
|
226
|
+
- lib/ruby_cms/engine/dashboard_registration.rb
|
|
227
|
+
- lib/ruby_cms/engine/navigation_registration.rb
|
|
228
|
+
- lib/ruby_cms/icons.rb
|
|
202
229
|
- lib/ruby_cms/settings.rb
|
|
203
230
|
- lib/ruby_cms/settings_registry.rb
|
|
204
231
|
- lib/ruby_cms/version.rb
|