ruby_cms 0.2.0.4 → 0.2.0.8

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 (34) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +25 -0
  3. data/app/components/ruby_cms/admin/bulk_action_table/bulk_action_table.rb +9 -1
  4. data/app/components/ruby_cms/admin/bulk_action_table/bulk_action_table_actions.rb +3 -3
  5. data/app/components/ruby_cms/admin/bulk_action_table/bulk_action_table_delete_modal.rb +8 -8
  6. data/app/components/ruby_cms/admin/bulk_action_table/bulk_action_table_header_bar.rb +15 -5
  7. data/app/components/ruby_cms/admin/bulk_action_table/bulk_actions.rb +57 -12
  8. data/app/controllers/concerns/ruby_cms/page_tracking.rb +15 -0
  9. data/app/controllers/ruby_cms/admin/analytics_controller.rb +12 -0
  10. data/app/controllers/ruby_cms/admin/commands_controller.rb +6 -6
  11. data/app/javascript/controllers/ruby_cms/bulk_action_table_controller.js +65 -13
  12. data/app/services/ruby_cms/analytics/report.rb +119 -7
  13. data/app/services/ruby_cms/command_runner.rb +3 -3
  14. data/app/views/layouts/ruby_cms/admin.html.erb +1 -1
  15. data/app/views/ruby_cms/admin/analytics/index.html.erb +160 -67
  16. data/app/views/ruby_cms/admin/analytics/partials/_browser_device.html.erb +21 -15
  17. data/app/views/ruby_cms/admin/analytics/partials/_daily_activity_chart.html.erb +36 -16
  18. data/app/views/ruby_cms/admin/analytics/partials/_hourly_activity_chart.html.erb +29 -13
  19. data/app/views/ruby_cms/admin/analytics/partials/_landing_pages.html.erb +27 -15
  20. data/app/views/ruby_cms/admin/analytics/partials/_os_stats.html.erb +29 -18
  21. data/app/views/ruby_cms/admin/analytics/partials/_popular_pages.html.erb +17 -12
  22. data/app/views/ruby_cms/admin/analytics/partials/_recent_activity.html.erb +25 -14
  23. data/app/views/ruby_cms/admin/analytics/partials/_top_referrers.html.erb +27 -15
  24. data/app/views/ruby_cms/admin/analytics/partials/_top_visitors.html.erb +20 -10
  25. data/app/views/ruby_cms/admin/analytics/partials/_utm_sources.html.erb +27 -15
  26. data/app/views/ruby_cms/admin/content_blocks/index.html.erb +8 -1
  27. data/config/locales/en.yml +69 -5
  28. data/config/locales/nl.yml +98 -0
  29. data/lib/generators/ruby_cms/install_generator.rb +45 -89
  30. data/lib/generators/ruby_cms/templates/admin.html.erb +1 -1
  31. data/lib/generators/ruby_cms/templates/ruby_cms.rb +40 -3
  32. data/lib/ruby_cms/settings_registry.rb +35 -0
  33. data/lib/ruby_cms/version.rb +1 -1
  34. metadata +1 -1
@@ -57,10 +57,22 @@ en:
57
57
  settings:
58
58
  title: "Settings"
59
59
  subtitle: "Configure admin interface preferences"
60
+ categories_title: "Sections"
61
+ form_hint: "Toggles save immediately; other fields use Save below."
62
+ save_hint: "Toggles autosave; text fields need Save."
63
+ save_changes: "Save changes"
60
64
  pagination: "Pagination"
61
65
  pagination_description: "Number of items to display per page in each table"
62
66
  navigation: "Navigation"
63
67
  navigation_description: "Control which pages appear in the navigation menu"
68
+ navigation_title: "Navigation"
69
+ navigation_hint: "Reorder items or choose what appears in the sidebar."
70
+ nav_order_tab: "Order"
71
+ nav_items_tab: "Visibility"
72
+ drag_hint: "Drag to reorder"
73
+ show_in_sidebar: "Show in sidebar"
74
+ show_in_sidebar_hint: "Turn sections on or off. Changes save when you toggle."
75
+ no_nav_items: "No items to configure here."
64
76
  nav_order_label: "Menu order"
65
77
  nav_order_hint: "Drag items to reorder the sidebar menu."
66
78
  general: "General"
@@ -73,6 +85,44 @@ en:
73
85
  no_settings: "No settings in this category"
74
86
  commands_page_hint: "Registered rake tasks (Commands) are not a tab on this screen. Open “Commands” in the left sidebar under “Settings”, or use the link below."
75
87
  commands_open_link: "Open Commands"
88
+ categories:
89
+ general:
90
+ label: "General"
91
+ description: "General preferences for the admin environment."
92
+ navigation:
93
+ label: "Navigation"
94
+ description: "Control sidebar order and visibility."
95
+ pagination:
96
+ label: "Pagination"
97
+ description: "Define default table page sizes."
98
+ analytics:
99
+ label: "Analytics"
100
+ description: "Adjust analytics-related display settings."
101
+ dashboard:
102
+ label: "Dashboard"
103
+ description: "Configure dashboard widgets and defaults."
104
+ content:
105
+ label: "Content"
106
+ description: "Tune content editing and publishing preferences."
107
+ bulk_action_table:
108
+ selected: "selected"
109
+ select_all: "Select all"
110
+ clear: "Clear"
111
+ close: "Close"
112
+ confirm: "Confirm"
113
+ processing: "Processing..."
114
+ delete_selected_items: "Delete Selected Items"
115
+ delete_selected: "Delete Selected"
116
+ delete_selected_confirm: "Are you sure you want to delete the selected items? This action cannot be undone."
117
+ are_you_sure_you_want_to_delete_the_selected_items: "Are you sure you want to delete the selected items?"
118
+ this_action_cannot_be_undone: "This action cannot be undone."
119
+ cancel: "Cancel"
120
+ select_at_least_one: "Please select at least one item."
121
+ item_id_not_found: "Item ID not found for deletion."
122
+ delete_path_not_found: "Delete path not found."
123
+ action_url_not_configured: "Action URL not configured. Please configure an action URL for this page."
124
+ default_confirm: "Are you sure you want to proceed?"
125
+ generic_action_error: "An error occurred while performing %{action}."
76
126
  analytics:
77
127
  title: "Analytics"
78
128
  subtitle: "Traffic and engagement overview"
@@ -80,14 +130,28 @@ en:
80
130
  back_to_analytics: "Back to analytics"
81
131
  page_details_title: "Page details"
82
132
  visitor_details_title: "Visitor details"
83
- total_page_views: "Total page views"
84
- unique_visitors: "Unique visitors"
85
- total_sessions: "Total sessions"
86
- popular_pages: "Popular pages"
87
- top_visitors: "Top visitors"
133
+ total_page_views: "Page Views"
134
+ unique_visitors: "Unique Visitors"
135
+ total_sessions: "Sessions"
136
+ bounce_rate: "Bounce Rate"
137
+ popular_pages: "Popular Pages"
138
+ top_visitors: "Top Visitors"
88
139
  suspicious_activity: "Suspicious activity"
89
140
  none_detected: "None detected in selected range."
90
141
  no_data: "No data yet."
142
+ exit_pages: "Exit Pages"
143
+ exit_pages_subtitle: "Last page viewed per session."
144
+ conversions: "Conversions"
145
+ conversions_subtitle: "Goals tracked via ahoy.track in your app."
146
+ conversions_total: "Total"
147
+ conversions_by_goal: "By goal"
148
+ no_conversions: "No conversions recorded."
149
+ no_conversions_hint: "Track goals with ahoy.track \"%{event}\", goal: \"your_goal\" in your controllers."
150
+ period_vs_previous: "vs previous period"
151
+ no_exit_pages: "No exit page data available."
152
+ page: "Page"
153
+ no_activity: "No activity recorded"
154
+ no_referrers: "No referrers recorded"
91
155
  visitor_errors:
92
156
  title: "Visitor errors"
93
157
  item_name: "error"
@@ -44,13 +44,111 @@ nl:
44
44
  unknown: "Onbekend commando."
45
45
  right_column_label: "Commando-resultaat en applicatielog"
46
46
  settings:
47
+ title: "Instellingen"
48
+ subtitle: "Beheerinterface-voorkeuren configureren"
49
+ categories_title: "Secties"
50
+ form_hint: "Schakelaars slaan direct op; andere velden gebruik je met Opslaan."
51
+ save_hint: "Schakelaars slaan automatisch op; tekstvelden vereisen Opslaan."
52
+ save_changes: "Wijzigingen opslaan"
53
+ pagination: "Paginering"
54
+ pagination_description: "Aantal items per pagina in elke tabel"
55
+ navigation: "Navigatie"
56
+ navigation_description: "Bepaal welke pagina's in het navigatiemenu verschijnen"
57
+ navigation_title: "Navigatie"
58
+ navigation_hint: "Herschik items of kies wat in de zijbalk verschijnt."
59
+ nav_order_tab: "Volgorde"
60
+ nav_items_tab: "Zichtbaarheid"
61
+ drag_hint: "Sleep om te herschikken"
62
+ show_in_sidebar: "Toon in zijbalk"
63
+ show_in_sidebar_hint: "Zet secties aan of uit. Wijzigingen slaan op bij toggelen."
64
+ no_nav_items: "Geen items om hier in te stellen."
65
+ nav_order_label: "Menuvolgorde"
66
+ nav_order_hint: "Wijzigingen worden automatisch opgeslagen als je een item verplaatst."
67
+ general: "Algemeen"
68
+ updated: "Instelling '%{key}' is bijgewerkt."
69
+ defaults_reset: "Alle instellingen zijn teruggezet naar de standaardwaarden."
70
+ reset_defaults: "Standaardwaarden herstellen"
71
+ reset_defaults_short: "Herstel standaard"
72
+ reset_inline_hint: "Herstel fabrieksinstellingen voor de hele admin (alle secties)."
73
+ reset_confirm: "Alle instellingen terugzetten naar standaardwaarden?"
74
+ no_settings: "Geen instellingen in deze categorie"
47
75
  commands_page_hint: "Geregistreerde Rake-taken (Commando's) staan niet als tab op dit scherm. Open «Commando's» in de linkerzijbalk onder het kopje Instellingen, of gebruik de link hieronder."
48
76
  commands_open_link: "Commando's openen"
77
+ categories:
78
+ general:
79
+ label: "Algemeen"
80
+ description: "Algemene voorkeuren voor de beheeromgeving."
81
+ navigation:
82
+ label: "Navigatie"
83
+ description: "Beheer de volgorde en zichtbaarheid van de zijbalk."
84
+ pagination:
85
+ label: "Paginering"
86
+ description: "Stel standaard paginagroottes voor tabellen in."
87
+ analytics:
88
+ label: "Analytics"
89
+ description: "Pas analytics-gerelateerde weergave-instellingen aan."
90
+ dashboard:
91
+ label: "Dashboard"
92
+ description: "Configureer dashboard-widgets en standaardwaarden."
93
+ content:
94
+ label: "Inhoud"
95
+ description: "Stel voorkeuren voor bewerken en publiceren in."
96
+ bulk_action_table:
97
+ selected: "geselecteerd"
98
+ select_all: "Alles selecteren"
99
+ clear: "Wissen"
100
+ close: "Sluiten"
101
+ confirm: "Bevestigen"
102
+ processing: "Verwerken..."
103
+ delete_selected_items: "Geselecteerde items verwijderen"
104
+ delete_selected: "Geselecteerde verwijderen"
105
+ delete_selected_confirm: "Weet je zeker dat je de geselecteerde items wilt verwijderen? Deze actie kan niet ongedaan worden gemaakt."
106
+ are_you_sure_you_want_to_delete_the_selected_items: "Weet je zeker dat je de geselecteerde items wilt verwijderen?"
107
+ this_action_cannot_be_undone: "Deze actie kan niet ongedaan worden gemaakt."
108
+ cancel: "Annuleren"
109
+ select_at_least_one: "Selecteer minimaal een item."
110
+ item_id_not_found: "Item-ID voor verwijderen niet gevonden."
111
+ delete_path_not_found: "Verwijderpad niet gevonden."
112
+ action_url_not_configured: "Actie-URL is niet ingesteld. Configureer een actie-URL voor deze pagina."
113
+ default_confirm: "Weet je zeker dat je wilt doorgaan?"
114
+ generic_action_error: "Er is een fout opgetreden tijdens het uitvoeren van %{action}."
115
+ analytics:
116
+ title: "Analytics"
117
+ subtitle: "Verkeer- en betrokkenheidoverzicht"
118
+ apply_filters: "Toepassen"
119
+ back_to_analytics: "Terug naar analytics"
120
+ page_details_title: "Paginadetails"
121
+ visitor_details_title: "Bezoekersdetails"
122
+ total_page_views: "Paginaweergaven"
123
+ unique_visitors: "Unieke bezoekers"
124
+ total_sessions: "Sessies"
125
+ bounce_rate: "Bouncepercentage"
126
+ popular_pages: "Populaire pagina's"
127
+ top_visitors: "Top bezoekers"
128
+ suspicious_activity: "Verdachte activiteit"
129
+ none_detected: "Niets gedetecteerd in de geselecteerde periode."
130
+ no_data: "Nog geen gegevens."
131
+ exit_pages: "Uitstappagina's"
132
+ exit_pages_subtitle: "Laatste bekeken pagina per sessie."
133
+ conversions: "Conversies"
134
+ conversions_subtitle: "Doelen bijgehouden via ahoy.track in je app."
135
+ conversions_total: "Totaal"
136
+ conversions_by_goal: "Per doel"
137
+ no_conversions: "Geen conversies geregistreerd."
138
+ no_conversions_hint: "Houd doelen bij met ahoy.track \"%{event}\", goal: \"jouw_doel\" in je controllers."
139
+ period_vs_previous: "t.o.v. vorige periode"
140
+ no_exit_pages: "Geen uitstappagina-gegevens beschikbaar."
141
+ page: "Pagina"
142
+ no_activity: "Geen activiteit geregistreerd"
143
+ no_referrers: "Geen verwijzers geregistreerd"
49
144
  content_blocks:
50
145
  created: "Contentblok aangemaakt."
51
146
  updated: "Contentblok bijgewerkt."
52
147
  deleted: "Contentblok verwijderd."
148
+ locale_read_only: "(taal kan niet worden gewijzigd voor bestaande blokken)"
53
149
  select_locale: "Selecteer taal"
150
+ edit_in_locale: "Bewerken in %{locale_name}"
151
+ other_languages: "Andere talen"
54
152
  content_type: "Inhoudstype"
55
153
  title: "Titel"
56
154
  content: "Inhoud"
@@ -21,13 +21,16 @@ module RubyCms
21
21
  - If the host uses /admin already, remove or change those routes.
22
22
  - Avoid root to: redirect("/admin") — use a real root or ruby_cms.unauthorized_redirect_path.
23
23
  - Review config/initializers/ruby_cms.rb (session, CSP).
24
- - Add 'css: bin/rails tailwindcss:watch' to Procfile.dev for Tailwind in development.
24
+ - RubyCMS admin styles are compiled once on install to app/assets/stylesheets/ruby_cms/admin.css.
25
25
  - Visit /admin (sign in as the admin you configured).
26
26
 
27
27
  Tracking:
28
28
  - Visitor errors: Automatically captured via ApplicationController (see /admin/visitor_errors)
29
29
  - Page views (Ahoy): Include RubyCms::PageTracking in your public controllers to track page views
30
30
  Example: class PagesController < ApplicationController; include RubyCms::PageTracking; end
31
+ - Conversions: Call ahoy.track RubyCms::Analytics::Report::EVENT_CONVERSION, goal: "contact_form"
32
+ from any controller action (e.g. after a successful form submit). Goal names are free-form strings.
33
+ - Bot filtering: Set config.ruby_cms.analytics_visit_scope to exclude IPs/bots (see config/initializers/ruby_cms.rb)
31
34
  - Analytics: View visit/event data in Ahoy tables (ahoy_visits, ahoy_events)
32
35
  TEXT
33
36
 
@@ -215,7 +218,18 @@ module RubyCms
215
218
  no_tasks do
216
219
  def copy_admin_css(dest_dir)
217
220
  admin_css_dest = dest_dir.join("admin.css")
221
+ precompiled_admin_css = RubyCms::Engine.root.join("app/assets/stylesheets/ruby_cms/admin.css")
222
+ if File.exist?(precompiled_admin_css) && File.size(precompiled_admin_css).to_i.positive?
223
+ FileUtils.cp(precompiled_admin_css, admin_css_dest)
224
+ return
225
+ end
226
+
218
227
  RubyCms::Engine.compile_admin_css(admin_css_dest)
228
+ return if File.size(admin_css_dest).to_i > 64
229
+
230
+ say "⚠ Task css/copy: Generated admin.css is very small. " \
231
+ "Ensure RubyCMS ships precompiled CSS at app/assets/stylesheets/ruby_cms/admin.css.",
232
+ :yellow
219
233
  end
220
234
 
221
235
  def copy_components_css(src_dir, dest_dir)
@@ -478,8 +492,8 @@ module RubyCms
478
492
  end
479
493
 
480
494
  def configure_tailwind(tailwind_css)
481
- add_ruby_cms_tailwind_source(tailwind_css)
482
- add_ruby_cms_tailwind_content_paths
495
+ remove_ruby_cms_tailwind_source(tailwind_css)
496
+ remove_ruby_cms_tailwind_content_paths
483
497
  run "bin/rails tailwindcss:build" if File.exist?(tailwind_css)
484
498
  # Importmap pins are provided by the engine via `ruby_cms/config/importmap.rb`.
485
499
  add_importmap_pins
@@ -855,114 +869,56 @@ module RubyCms
855
869
  end.join("\n")
856
870
  end
857
871
 
858
- # Helper: add @source for RubyCMS views/components so Tailwind finds utility classes.
872
+ # RubyCMS admin styles are precompiled to app/assets/stylesheets/ruby_cms/admin.css.
873
+ # Remove RubyCMS-specific Tailwind source globs to keep host-app builds fast.
859
874
  # Not a generator task.
860
- def add_ruby_cms_tailwind_source(tailwind_css_path)
861
- return unless tailwind_css_path.to_s.present? && File.exist?(tailwind_css_path)
875
+ def remove_ruby_cms_tailwind_source(tailwind_css_path)
876
+ return unless valid_tailwind_source_path?(tailwind_css_path)
862
877
 
863
878
  content = File.read(tailwind_css_path)
864
- gem_source_lines = build_gem_source_lines(tailwind_css_path)
865
- return if gem_source_lines.all? {|line| content.include?(line) }
879
+ cleaned_content = remove_legacy_ruby_cms_tailwind_sources(content)
880
+ return if cleaned_content == content
866
881
 
867
- inject_tailwind_source(tailwind_css_path, content, gem_source_lines)
882
+ File.write(tailwind_css_path, cleaned_content)
883
+ say_tailwind_source_cleaned
868
884
  rescue StandardError => e
869
- say "⚠ Task tailwind/source: Could not add @source: #{e.message}. Add manually.", :yellow
885
+ say_tailwind_source_clean_failed(e)
870
886
  end
871
887
 
872
- # Tailwind v3 support (tailwind.config.js content array)
873
- def add_ruby_cms_tailwind_content_paths # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
888
+ # Remove RubyCMS content globs from Tailwind v3 config as well.
889
+ def remove_ruby_cms_tailwind_content_paths
874
890
  config_path = Rails.root.join("config/tailwind.config.js")
875
891
  return unless File.exist?(config_path)
876
892
 
877
893
  content = File.read(config_path)
878
- patterns = ruby_cms_tailwind_content_patterns
879
- return if patterns.all? {|p| content.include?(p) }
880
-
881
- inject = "#{patterns.map {|p| " \"#{p}\"," }.join("\n")}\n"
894
+ cleaned = content.gsub(/^\s*["']?[^"'\n]*ruby_cms[^"'\n]*["']?,?\s*$\n?/i, "")
895
+ return if cleaned == content
882
896
 
883
- # Insert inside `content: [` if present; otherwise no-op.
884
- inserted = false
885
- if content.match?(/content:\s*\[/)
886
- gsub_file config_path.to_s, /content:\s*\[\s*\n/ do |match|
887
- inserted = true
888
- "#{match}#{inject}"
889
- end
890
- end
891
-
892
- return unless inserted
893
-
894
- say "✓ Task tailwind/content: Added RubyCMS paths to config/tailwind.config.js.", :green
897
+ File.write(config_path, cleaned)
898
+ say "✓ Task tailwind/content: Removed RubyCMS paths from tailwind.config.js.", :green
895
899
  rescue StandardError => e
896
- say "⚠ Task tailwind/content: Could not update tailwind.config.js: #{e.message}.", :yellow
900
+ say "⚠ Task tailwind/content: Could not clean tailwind.config.js: #{e.message}.", :yellow
897
901
  end
898
902
 
899
- def ruby_cms_tailwind_content_patterns
900
- views = RubyCms::Engine.root.join("app/views").relative_path_from(Rails.root).to_s
901
- components = RubyCms::Engine.root.join("app/components").relative_path_from(Rails.root).to_s
902
- [
903
- "#{views}/**/*.erb",
904
- "#{components}/**/*.rb"
905
- ]
903
+ def remove_legacy_ruby_cms_tailwind_sources(content)
904
+ content
905
+ .gsub(%r{^\s*/\*\s*Include RubyCMS views/components so Tailwind finds utility classes\.\s*\*/\s*$\n?}, "")
906
+ .gsub(/^\s*@source\s+"[^"\n]*ruby_cms[^"\n]*";\s*$\n?/i, "")
906
907
  end
907
908
 
908
- def build_gem_source_lines(tailwind_css_path)
909
- css_dir = Pathname.new(tailwind_css_path).dirname
910
- gem_views = path_relative_to_css_or_absolute(RubyCms::Engine.root.join("app/views"),
911
- css_dir)
912
- gem_components = path_relative_to_css_or_absolute(
913
- RubyCms::Engine.root.join("app/components"), css_dir
914
- )
915
- [
916
- %(@source "#{gem_views}/**/*.erb";),
917
- %(@source "#{gem_components}/**/*.rb";)
918
- ]
909
+ def valid_tailwind_source_path?(tailwind_css_path)
910
+ tailwind_css_path.to_s.present? && File.exist?(tailwind_css_path)
919
911
  end
920
912
 
921
- def path_relative_to_css_or_absolute(target_path, css_dir)
922
- Pathname.new(target_path).relative_path_from(css_dir).to_s
923
- rescue ArgumentError
924
- # Different mount/volume: fall back to absolute path.
925
- Pathname.new(target_path).to_s
926
- end
927
-
928
- def inject_tailwind_source(tailwind_css_path, content, gem_source_lines)
929
- to_inject = build_tailwind_source_injection(gem_source_lines)
930
- inserted = try_insert_after_patterns?(tailwind_css_path, content, to_inject)
931
- inject_at_start(tailwind_css_path, to_inject) unless inserted
932
- say "✓ Task tailwind/source: Added @source for RubyCMS views/components to " \
933
- "tailwind/application.css.",
913
+ def say_tailwind_source_cleaned
914
+ say "✓ Task tailwind/source: Removed RubyCMS @source paths from tailwind entry CSS.",
934
915
  :green
935
916
  end
936
917
 
937
- def build_tailwind_source_injection(gem_source_lines)
938
- to_inject = +"\n/* Include RubyCMS views/components so Tailwind finds utility classes. */\n"
939
- Array(gem_source_lines).each {|line| to_inject << line << "\n" }
940
- to_inject << "\n"
941
- to_inject
942
- end
943
-
944
- def try_insert_after_patterns?(tailwind_css_path, content, to_inject)
945
- patterns = [
946
- %(@import "tailwindcss";\n),
947
- %(@import "tailwindcss";),
948
- %(@import "tailwindcss"\n),
949
- %(@import "tailwindcss")
950
- ]
951
- patterns.each do |after_pattern|
952
- next unless content.include?(after_pattern)
953
-
954
- inject_into_file tailwind_css_path.to_s, after: after_pattern do
955
- to_inject
956
- end
957
- return true
958
- end
959
- false
960
- end
961
-
962
- def inject_at_start(tailwind_css_path, to_inject)
963
- inject_into_file tailwind_css_path.to_s, after: /\A/ do
964
- to_inject
965
- end
918
+ def say_tailwind_source_clean_failed(error)
919
+ say " Task tailwind/source: Could not clean @source lines: #{error.message}. " \
920
+ "Check tailwind/application.css manually.",
921
+ :yellow
966
922
  end
967
923
  end
968
924
 
@@ -15,7 +15,7 @@
15
15
  <link rel="manifest" href="<%= asset_path("site.webmanifest") %>">
16
16
 
17
17
  <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
18
- <%= stylesheet_link_tag "tailwind", "data-turbo-track": "reload" %>
18
+ <%= stylesheet_link_tag "ruby_cms/admin", "data-turbo-track": "reload" rescue nil %>
19
19
  <%= stylesheet_link_tag "actiontext", "data-turbo-track": "reload" rescue nil %>
20
20
  <%= javascript_importmap_tags "admin" %>
21
21
  </head>
@@ -49,10 +49,30 @@ RubyCms.configure do |c|
49
49
  # Preview data proc to pass instance variables.
50
50
  # c.preview_data = ->(page_key, view) { { products: Product.limit(5) } }
51
51
 
52
- # Optional hook: customize Ahoy visit scope (e.g. exclude internal traffic)
53
- # c.analytics_visit_scope = ->(scope) { scope.where.not(ip: ["127.0.0.1"]) }
52
+ # Optional hook: filter Ahoy visits before analytics queries run.
53
+ # Use this to exclude known bots, internal IPs, or staging traffic.
54
+ # Examples (combine as needed):
55
+ #
56
+ # Exclude localhost + internal subnets:
57
+ # c.analytics_visit_scope = ->(scope) {
58
+ # scope.where.not(ip: %w[127.0.0.1 ::1])
59
+ # .where("ip NOT LIKE '10.%'")
60
+ # .where("ip NOT LIKE '192.168.%'")
61
+ # }
62
+ #
63
+ # Exclude Ahoy's built-in bot detection (requires Ahoy.bot_detection_enabled = true
64
+ # in config/initializers/ahoy.rb, which sets user_agent on the visit):
65
+ # c.analytics_visit_scope = ->(scope) {
66
+ # scope.where("user_agent NOT REGEXP ?", Ahoy::BOT_AGENTS.join("|"))
67
+ # }
68
+ #
69
+ # Simple IP-based staging exclusion:
70
+ # INTERNAL_IPS = %w[127.0.0.1 ::1].freeze
71
+ # c.analytics_visit_scope = ->(scope) { scope.where.not(ip: INTERNAL_IPS) }
72
+ #
73
+ # c.analytics_visit_scope = ->(scope) { scope.where.not(ip: ["127.0.0.1", "::1"]) }
54
74
 
55
- # Optional hook: customize Ahoy event scope
75
+ # Optional hook: customize Ahoy event scope (e.g. exclude events from certain visits)
56
76
  # c.analytics_event_scope = ->(scope) { scope }
57
77
 
58
78
  # Optional hook: provide extra dashboard cards
@@ -60,6 +80,23 @@ RubyCms.configure do |c|
60
80
  # [{ title: "Custom KPI", value: visits_scope.where.not(utm_source: nil).count }]
61
81
  # end
62
82
 
83
+ # Conversion tracking: track goals from host app controllers or form handlers.
84
+ # Use the EVENT_CONVERSION constant to stay consistent with the analytics dashboard.
85
+ # Example in a controller action (after a successful form submit):
86
+ #
87
+ # def create
88
+ # if @contact.save
89
+ # ahoy.track RubyCms::Analytics::Report::EVENT_CONVERSION,
90
+ # goal: "contact_form", path: request.path
91
+ # redirect_to success_path
92
+ # else
93
+ # render :new
94
+ # end
95
+ # end
96
+ #
97
+ # Goal names are free-form strings; keep them consistent so the dashboard groups them.
98
+ # Recommended goal names: "contact_form", "newsletter_signup", "registration", "purchase"
99
+
63
100
  # -----------------------------------------------------------------------------
64
101
  # Optional bootstrap values (initializer -> DB import, once)
65
102
  #
@@ -166,6 +166,41 @@ module RubyCms
166
166
  category: :analytics,
167
167
  description: "Events shown on visitor details screen"
168
168
  )
169
+ register(
170
+ key: :analytics_max_exit_pages,
171
+ type: :integer,
172
+ default: 10,
173
+ category: :analytics,
174
+ description: "Maximum number of exit pages to show"
175
+ )
176
+ register(
177
+ key: :analytics_max_conversions,
178
+ type: :integer,
179
+ default: 10,
180
+ category: :analytics,
181
+ description: "Maximum number of conversion goals to show in breakdown"
182
+ )
183
+ register(
184
+ key: :analytics_max_referrers,
185
+ type: :integer,
186
+ default: 10,
187
+ category: :analytics,
188
+ description: "Maximum number of top referrers to show"
189
+ )
190
+ register(
191
+ key: :analytics_max_landing_pages,
192
+ type: :integer,
193
+ default: 10,
194
+ category: :analytics,
195
+ description: "Maximum number of top landing pages to show"
196
+ )
197
+ register(
198
+ key: :analytics_max_utm_sources,
199
+ type: :integer,
200
+ default: 10,
201
+ category: :analytics,
202
+ description: "Maximum number of UTM sources to show"
203
+ )
169
204
 
170
205
  # Dashboard
171
206
  register(
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RubyCms
4
- VERSION = "0.2.0.4"
4
+ VERSION = "0.2.0.8"
5
5
  end
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.2.0.4
4
+ version: 0.2.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Codebyjob