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
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
<h1>Versiegeschiedenis: <%= @content_block.key %></h1>
|
|
2
|
+
|
|
3
|
+
<%= link_to "Terug naar content block", ruby_cms_admin_content_block_path(@content_block),
|
|
4
|
+
class: "inline-flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground mb-4" %>
|
|
5
|
+
|
|
6
|
+
<div class="space-y-4">
|
|
7
|
+
<% @versions.each do |version| %>
|
|
8
|
+
<div class="rounded-lg border border-border/60 bg-card p-4">
|
|
9
|
+
<div class="flex items-center justify-between">
|
|
10
|
+
<div class="flex items-center gap-3">
|
|
11
|
+
<span class="inline-flex items-center rounded-md px-2 py-0.5 text-xs font-medium
|
|
12
|
+
<%= case version.event
|
|
13
|
+
when 'create' then 'bg-blue-50 text-blue-700 ring-1 ring-blue-200'
|
|
14
|
+
when 'update' then 'bg-amber-50 text-amber-700 ring-1 ring-amber-200'
|
|
15
|
+
when 'rollback' then 'bg-purple-50 text-purple-700 ring-1 ring-purple-200'
|
|
16
|
+
when 'publish' then 'bg-emerald-50 text-emerald-700 ring-1 ring-emerald-200'
|
|
17
|
+
when 'unpublish' then 'bg-red-50 text-red-700 ring-1 ring-red-200'
|
|
18
|
+
when 'visual_editor' then 'bg-cyan-50 text-cyan-700 ring-1 ring-cyan-200'
|
|
19
|
+
else 'bg-muted text-muted-foreground ring-1 ring-border/60'
|
|
20
|
+
end %>">
|
|
21
|
+
v<%= version.version_number %> - <%= version.event %>
|
|
22
|
+
</span>
|
|
23
|
+
<span class="text-sm text-muted-foreground">
|
|
24
|
+
<%= ruby_cms_user_display(version.user) %>
|
|
25
|
+
</span>
|
|
26
|
+
<span class="text-xs text-muted-foreground">
|
|
27
|
+
<%= version.created_at.strftime("%b %d, %Y %H:%M") %>
|
|
28
|
+
</span>
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
<div class="flex items-center gap-2">
|
|
32
|
+
<%= link_to "Bekijk diff", ruby_cms_admin_content_block_version_path(@content_block, version),
|
|
33
|
+
class: "text-xs text-primary hover:underline" %>
|
|
34
|
+
|
|
35
|
+
<% unless version == @versions.first %>
|
|
36
|
+
<%= button_to "Rollback",
|
|
37
|
+
rollback_ruby_cms_admin_content_block_version_path(@content_block, version),
|
|
38
|
+
method: :post,
|
|
39
|
+
data: { turbo_confirm: "Weet je zeker dat je wilt terugdraaien naar versie #{version.version_number}?" },
|
|
40
|
+
class: "text-xs text-destructive hover:underline" %>
|
|
41
|
+
<% end %>
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
<% if version.metadata&.dig("changed_fields").present? %>
|
|
46
|
+
<p class="mt-2 text-xs text-muted-foreground">
|
|
47
|
+
Gewijzigde velden: <%= version.metadata["changed_fields"].join(", ") %>
|
|
48
|
+
</p>
|
|
49
|
+
<% end %>
|
|
50
|
+
</div>
|
|
51
|
+
<% end %>
|
|
52
|
+
</div>
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
<h1>Versie <%= @version.version_number %> - <%= @content_block.key %></h1>
|
|
2
|
+
|
|
3
|
+
<%= link_to "Terug naar versiegeschiedenis",
|
|
4
|
+
ruby_cms_admin_content_block_versions_path(@content_block),
|
|
5
|
+
class: "inline-flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground mb-4" %>
|
|
6
|
+
|
|
7
|
+
<% diff = @version.diff_from(@previous_version) %>
|
|
8
|
+
|
|
9
|
+
<% if diff.empty? %>
|
|
10
|
+
<p class="text-sm text-muted-foreground">Geen wijzigingen ten opzichte van de vorige versie.</p>
|
|
11
|
+
<% else %>
|
|
12
|
+
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
13
|
+
<% diff.each do |field, changes| %>
|
|
14
|
+
<div class="col-span-2 rounded-lg border border-border/60 bg-card p-4">
|
|
15
|
+
<h3 class="text-sm font-semibold text-foreground mb-2"><%= field.to_s.humanize %></h3>
|
|
16
|
+
<div class="grid grid-cols-2 gap-4">
|
|
17
|
+
<div>
|
|
18
|
+
<span class="text-xs font-medium text-muted-foreground">Vorige versie</span>
|
|
19
|
+
<div class="mt-1 rounded-md bg-red-50 p-3 text-sm text-red-800 whitespace-pre-wrap"><%= changes[:old] || "(leeg)" %></div>
|
|
20
|
+
</div>
|
|
21
|
+
<div>
|
|
22
|
+
<span class="text-xs font-medium text-muted-foreground">Deze versie</span>
|
|
23
|
+
<div class="mt-1 rounded-md bg-emerald-50 p-3 text-sm text-emerald-800 whitespace-pre-wrap"><%= changes[:new] || "(leeg)" %></div>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
</div>
|
|
27
|
+
<% end %>
|
|
28
|
+
</div>
|
|
29
|
+
<% end %>
|
|
30
|
+
|
|
31
|
+
<div class="mt-6">
|
|
32
|
+
<%= button_to "Rollback naar deze versie",
|
|
33
|
+
rollback_ruby_cms_admin_content_block_version_path(@content_block, @version),
|
|
34
|
+
method: :post,
|
|
35
|
+
data: { turbo_confirm: "Weet je zeker dat je wilt terugdraaien naar versie #{@version.version_number}?" },
|
|
36
|
+
class: "inline-flex items-center px-4 py-2 rounded-md bg-primary text-primary-foreground text-sm font-medium hover:bg-primary/90" %>
|
|
37
|
+
</div>
|
|
@@ -197,6 +197,18 @@
|
|
|
197
197
|
</dl>
|
|
198
198
|
</div>
|
|
199
199
|
|
|
200
|
+
<div class="border-t border-border/60 pt-5">
|
|
201
|
+
<h3 class="<%= RubyCms::Admin::AdminResourceCard::SECTION_TITLE_CLASS %> mb-3">Versiegeschiedenis</h3>
|
|
202
|
+
<%= link_to "Bekijk alle versies",
|
|
203
|
+
ruby_cms_admin_content_block_versions_path(@content_block),
|
|
204
|
+
class: "inline-flex items-center gap-2 text-sm text-primary hover:underline" %>
|
|
205
|
+
<% if @content_block.respond_to?(:versions) && @content_block.versions.any? %>
|
|
206
|
+
<p class="text-xs text-muted-foreground mt-2">
|
|
207
|
+
<%= @content_block.versions.count %> versie(s) beschikbaar
|
|
208
|
+
</p>
|
|
209
|
+
<% end %>
|
|
210
|
+
</div>
|
|
211
|
+
|
|
200
212
|
<%# ── Preview per locale ── %>
|
|
201
213
|
<% if @blocks_by_locale.present? && @blocks_by_locale.values.any? { |b| b.title.present? || b.content_body.present? } %>
|
|
202
214
|
<div class="border-t border-border/60 pt-5">
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
<div class="flex h-full flex-col rounded-lg border border-gray-200/80 bg-white shadow-sm">
|
|
2
|
+
<div class="flex items-center justify-between gap-3 border-b border-gray-100 px-5 py-3">
|
|
3
|
+
<div>
|
|
4
|
+
<p class="text-sm font-semibold text-gray-900">Analytics</p>
|
|
5
|
+
<p class="text-xs text-gray-500">Last 7 days.</p>
|
|
6
|
+
</div>
|
|
7
|
+
<%= link_to "View all", ruby_cms_admin_analytics_path, class: "text-sm font-medium text-gray-600 hover:text-gray-900 transition-colors" %>
|
|
8
|
+
</div>
|
|
9
|
+
|
|
10
|
+
<% if @dashboard_analytics_stats.present? %>
|
|
11
|
+
<div class="grid grid-cols-2 gap-x-4 gap-y-3 px-5 py-4">
|
|
12
|
+
<div>
|
|
13
|
+
<p class="text-xs font-medium text-gray-500">Page views</p>
|
|
14
|
+
<p class="mt-1 text-2xl font-semibold tracking-tight text-gray-900 tabular-nums"><%= number_with_delimiter(@dashboard_analytics_stats[:total_page_views].to_i) %></p>
|
|
15
|
+
</div>
|
|
16
|
+
<div>
|
|
17
|
+
<p class="text-xs font-medium text-gray-500">Unique visitors</p>
|
|
18
|
+
<p class="mt-1 text-2xl font-semibold tracking-tight text-gray-900 tabular-nums"><%= number_with_delimiter(@dashboard_analytics_stats[:unique_visitors].to_i) %></p>
|
|
19
|
+
</div>
|
|
20
|
+
<div>
|
|
21
|
+
<p class="text-xs font-medium text-gray-500">Sessions</p>
|
|
22
|
+
<p class="mt-1 text-2xl font-semibold tracking-tight text-gray-900 tabular-nums"><%= number_with_delimiter(@dashboard_analytics_stats[:total_sessions].to_i) %></p>
|
|
23
|
+
</div>
|
|
24
|
+
<div>
|
|
25
|
+
<p class="text-xs font-medium text-gray-500">Avg / day</p>
|
|
26
|
+
<p class="mt-1 text-2xl font-semibold tracking-tight text-gray-900 tabular-nums"><%= number_with_delimiter(@dashboard_analytics_stats[:avg_daily_views].to_i) %></p>
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
<% top = @dashboard_analytics_stats[:popular_pages] %>
|
|
31
|
+
<% if top.present? %>
|
|
32
|
+
<div class="flex-1 border-t border-gray-100">
|
|
33
|
+
<p class="px-5 pt-3 text-xs text-gray-500">Popular pages</p>
|
|
34
|
+
<div class="divide-y divide-gray-100">
|
|
35
|
+
<% top.to_a.first(4).each do |page_name, count| %>
|
|
36
|
+
<div class="flex items-center justify-between gap-2 px-5 py-2">
|
|
37
|
+
<span class="min-w-0 truncate text-sm font-medium text-gray-900" title="<%= page_name %>"><%= page_name.presence || "(empty)" %></span>
|
|
38
|
+
<span class="shrink-0 text-sm tabular-nums text-gray-500"><%= number_with_delimiter(count.to_i) %></span>
|
|
39
|
+
</div>
|
|
40
|
+
<% end %>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
<% end %>
|
|
44
|
+
<% else %>
|
|
45
|
+
<div class="flex flex-1 flex-col items-center justify-center px-5 py-8 text-center">
|
|
46
|
+
<div class="mb-2 inline-flex h-10 w-10 items-center justify-center rounded-lg bg-gray-100 text-gray-600 ring-1 ring-inset ring-gray-200">
|
|
47
|
+
<svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"/></svg>
|
|
48
|
+
</div>
|
|
49
|
+
<p class="text-sm font-medium text-gray-900">Analytics unavailable</p>
|
|
50
|
+
<p class="mt-1 text-xs text-gray-500">Could not load data.</p>
|
|
51
|
+
</div>
|
|
52
|
+
<% end %>
|
|
53
|
+
</div>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<div class="flex h-full flex-col rounded-lg border border-gray-200/80 bg-white p-4 shadow-sm">
|
|
2
|
+
<div class="flex flex-1 items-start justify-between gap-2">
|
|
3
|
+
<div class="min-w-0">
|
|
4
|
+
<p class="text-xs font-medium text-gray-500">Content blocks</p>
|
|
5
|
+
<p class="mt-1 text-2xl font-semibold tracking-tight text-gray-900 tabular-nums"><%= @content_blocks_count %></p>
|
|
6
|
+
<p class="mt-0.5 text-xs text-gray-500"><%= @content_blocks_published_count %> published</p>
|
|
7
|
+
</div>
|
|
8
|
+
<div class="inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-teal-50 text-teal-700 ring-1 ring-inset ring-teal-100">
|
|
9
|
+
<svg class="h-3.5 w-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 10h16M4 14h8"/></svg>
|
|
10
|
+
</div>
|
|
11
|
+
</div>
|
|
12
|
+
<div class="mt-3 border-t border-gray-100 pt-2">
|
|
13
|
+
<%= link_to ruby_cms_admin_content_blocks_path, class: "inline-flex items-center gap-1 text-xs font-medium text-gray-600 hover:text-gray-900 transition-colors" do %>
|
|
14
|
+
Manage <svg class="h-3 w-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M9 5l7 7-7 7"/></svg>
|
|
15
|
+
<% end %>
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<div class="flex h-full flex-col rounded-lg border border-gray-200/80 bg-white p-4 shadow-sm">
|
|
2
|
+
<div class="flex flex-1 items-start justify-between gap-2">
|
|
3
|
+
<div class="min-w-0">
|
|
4
|
+
<p class="text-xs font-medium text-gray-500">Permissions</p>
|
|
5
|
+
<p class="mt-1 text-2xl font-semibold tracking-tight text-gray-900 tabular-nums"><%= @permissions_count %></p>
|
|
6
|
+
<p class="mt-0.5 text-xs text-gray-500"><%= @user_permissions_count %> grants</p>
|
|
7
|
+
</div>
|
|
8
|
+
<div class="inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-violet-50 text-violet-700 ring-1 ring-inset ring-violet-100">
|
|
9
|
+
<svg class="h-3.5 w-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" 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"/></svg>
|
|
10
|
+
</div>
|
|
11
|
+
</div>
|
|
12
|
+
<div class="mt-3 border-t border-gray-100 pt-2">
|
|
13
|
+
<%= link_to ruby_cms_admin_permissions_path, class: "inline-flex items-center gap-1 text-xs font-medium text-gray-600 hover:text-gray-900 transition-colors" do %>
|
|
14
|
+
Manage <svg class="h-3 w-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M9 5l7 7-7 7"/></svg>
|
|
15
|
+
<% end %>
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
<div class="flex h-full flex-col rounded-lg border border-gray-200/80 bg-white shadow-sm">
|
|
2
|
+
<div class="flex items-center justify-between gap-3 border-b border-gray-100 px-5 py-3">
|
|
3
|
+
<div>
|
|
4
|
+
<p class="text-sm font-semibold text-gray-900">Quick actions</p>
|
|
5
|
+
<p class="text-xs text-gray-500">Jump to common admin tasks.</p>
|
|
6
|
+
</div>
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
<div class="flex flex-col divide-y divide-gray-100">
|
|
10
|
+
<%= link_to new_ruby_cms_admin_content_block_path, class: "group flex items-center justify-between gap-2 px-5 py-3 hover:bg-gray-50 transition-colors" do %>
|
|
11
|
+
<div class="flex min-w-0 items-center gap-2.5">
|
|
12
|
+
<div class="inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-teal-50 text-teal-700 ring-1 ring-inset ring-teal-100 mr-2">
|
|
13
|
+
<svg class="h-3.5 w-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"/></svg>
|
|
14
|
+
</div>
|
|
15
|
+
<div class="min-w-0">
|
|
16
|
+
<p class="text-sm font-medium text-gray-900">New content block</p>
|
|
17
|
+
<p class="text-xs text-gray-500">Create a new block</p>
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
<svg class="h-4 w-4 shrink-0 text-gray-300 transition-colors group-hover:text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/></svg>
|
|
21
|
+
<% end %>
|
|
22
|
+
|
|
23
|
+
<%= link_to ruby_cms_admin_visual_editor_path, class: "group flex items-center justify-between gap-2 px-5 py-3 hover:bg-gray-50 transition-colors" do %>
|
|
24
|
+
<div class="flex min-w-0 items-center gap-2.5">
|
|
25
|
+
<div class="inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-indigo-50 text-indigo-700 ring-1 ring-inset ring-indigo-100 mr-2">
|
|
26
|
+
<svg class="h-3.5 w-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.232 5.232l3.536 3.536M9 11l6 6M3 21h18"/></svg>
|
|
27
|
+
</div>
|
|
28
|
+
<div class="min-w-0">
|
|
29
|
+
<p class="text-sm font-medium text-gray-900">Visual editor</p>
|
|
30
|
+
<p class="text-xs text-gray-500">Edit content visually</p>
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
<svg class="h-4 w-4 shrink-0 text-gray-300 transition-colors group-hover:text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/></svg>
|
|
34
|
+
<% end %>
|
|
35
|
+
|
|
36
|
+
<%= link_to ruby_cms_admin_visitor_errors_path, class: "group flex items-center justify-between gap-2 px-5 py-3 hover:bg-gray-50 transition-colors" do %>
|
|
37
|
+
<div class="flex min-w-0 items-center gap-2.5">
|
|
38
|
+
<div class="inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-rose-50 text-rose-700 ring-1 ring-inset ring-rose-100 mr-2">
|
|
39
|
+
<svg class="h-3.5 w-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>
|
|
40
|
+
</div>
|
|
41
|
+
<div class="min-w-0">
|
|
42
|
+
<p class="text-sm font-medium text-gray-900">Visitor errors</p>
|
|
43
|
+
<p class="text-xs text-gray-500">Review recent issues</p>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
<svg class="h-4 w-4 shrink-0 text-gray-300 transition-colors group-hover:text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/></svg>
|
|
47
|
+
<% end %>
|
|
48
|
+
|
|
49
|
+
<%= link_to ruby_cms_admin_settings_path, class: "group flex items-center justify-between gap-2 px-5 py-3 hover:bg-gray-50 transition-colors" do %>
|
|
50
|
+
<div class="flex min-w-0 items-center gap-2.5">
|
|
51
|
+
<div class="inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-gray-100 text-gray-700 ring-1 ring-inset ring-gray-200 mr-2">
|
|
52
|
+
<svg class="h-3.5 w-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" 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.065 2.572c1.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.572 1.065c-.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.065-2.572c-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 stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/></svg>
|
|
53
|
+
</div>
|
|
54
|
+
<div class="min-w-0">
|
|
55
|
+
<p class="text-sm font-medium text-gray-900">Settings</p>
|
|
56
|
+
<p class="text-xs text-gray-500">Configure RubyCMS</p>
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
<svg class="h-4 w-4 shrink-0 text-gray-300 transition-colors group-hover:text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/></svg>
|
|
60
|
+
<% end %>
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<div class="flex h-full flex-col rounded-lg border border-gray-200/80 bg-white shadow-sm">
|
|
2
|
+
<div class="flex items-center justify-between gap-3 border-b border-gray-100 px-5 py-3">
|
|
3
|
+
<div>
|
|
4
|
+
<p class="text-sm font-semibold text-gray-900">Recent errors</p>
|
|
5
|
+
<p class="text-xs text-gray-500">Latest visitor errors.</p>
|
|
6
|
+
</div>
|
|
7
|
+
<%= link_to "View all", ruby_cms_admin_visitor_errors_path, class: "text-sm font-medium text-gray-600 hover:text-gray-900 transition-colors" %>
|
|
8
|
+
</div>
|
|
9
|
+
|
|
10
|
+
<% if @recent_errors.any? %>
|
|
11
|
+
<div class="flex-1 divide-y divide-gray-100">
|
|
12
|
+
<% @recent_errors.first(4).each do |error| %>
|
|
13
|
+
<div class="px-5 py-3">
|
|
14
|
+
<p class="truncate text-sm font-medium text-gray-900">
|
|
15
|
+
<span class="font-normal text-gray-500"><%= error.error_class %>:</span>
|
|
16
|
+
<%= error.error_message.truncate(56) %>
|
|
17
|
+
</p>
|
|
18
|
+
<div class="mt-1.5 flex items-center justify-between gap-2">
|
|
19
|
+
<div class="flex min-w-0 flex-wrap items-center gap-2">
|
|
20
|
+
<span class="inline-flex items-center rounded-md px-2 py-0.5 text-xs font-medium ring-1 ring-inset <%= error.resolved? ? 'bg-emerald-50 text-emerald-700 ring-emerald-200' : 'bg-rose-50 text-rose-700 ring-rose-200' %>">
|
|
21
|
+
<%= error.resolved? ? 'Resolved' : 'Unresolved' %>
|
|
22
|
+
</span>
|
|
23
|
+
<span class="text-xs text-gray-500"><%= time_ago_in_words(error.created_at) %> ago</span>
|
|
24
|
+
</div>
|
|
25
|
+
<%= link_to "Open", ruby_cms_admin_visitor_error_path(error), class: "shrink-0 text-xs font-medium text-gray-600 hover:text-gray-900 transition-colors" %>
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
<% end %>
|
|
29
|
+
</div>
|
|
30
|
+
<% else %>
|
|
31
|
+
<div class="flex flex-1 flex-col items-center justify-center px-5 py-8 text-center">
|
|
32
|
+
<div class="mb-2 inline-flex h-10 w-10 items-center justify-center rounded-lg bg-emerald-50 ring-1 ring-inset ring-emerald-100">
|
|
33
|
+
<svg class="h-5 w-5 text-emerald-600" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>
|
|
34
|
+
</div>
|
|
35
|
+
<p class="text-sm font-medium text-gray-900">No errors recorded</p>
|
|
36
|
+
<p class="mt-1 text-xs text-gray-500">Everything is running smoothly.</p>
|
|
37
|
+
</div>
|
|
38
|
+
<% end %>
|
|
39
|
+
</div>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<div class="flex h-full flex-col rounded-lg border border-gray-200/80 bg-white p-4 shadow-sm">
|
|
2
|
+
<div class="flex flex-1 items-start justify-between gap-2">
|
|
3
|
+
<div class="min-w-0">
|
|
4
|
+
<p class="text-xs font-medium text-gray-500">Users</p>
|
|
5
|
+
<p class="mt-1 text-2xl font-semibold tracking-tight text-gray-900 tabular-nums"><%= @users_count %></p>
|
|
6
|
+
<p class="mt-0.5 text-xs text-gray-500">registered</p>
|
|
7
|
+
</div>
|
|
8
|
+
<div class="inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-blue-50 text-blue-700 ring-1 ring-inset ring-blue-100">
|
|
9
|
+
<svg class="h-3.5 w-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a4 4 0 00-4-4h-1M9 20H4v-2a4 4 0 014-4h1m4-4a4 4 0 110-8 4 4 0 010 8z"/></svg>
|
|
10
|
+
</div>
|
|
11
|
+
</div>
|
|
12
|
+
<div class="mt-3 border-t border-gray-100 pt-2">
|
|
13
|
+
<%= link_to ruby_cms_admin_users_path, class: "inline-flex items-center gap-1 text-xs font-medium text-gray-600 hover:text-gray-900 transition-colors" do %>
|
|
14
|
+
Manage <svg class="h-3 w-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M9 5l7 7-7 7"/></svg>
|
|
15
|
+
<% end %>
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<div class="flex h-full flex-col rounded-lg border border-gray-200/80 bg-white p-4 shadow-sm">
|
|
2
|
+
<div class="flex flex-1 items-start justify-between gap-2">
|
|
3
|
+
<div class="min-w-0">
|
|
4
|
+
<p class="text-xs font-medium text-gray-500">Visitor errors</p>
|
|
5
|
+
<p class="mt-1 text-2xl font-semibold tracking-tight text-gray-900 tabular-nums"><%= @visitor_errors_count %></p>
|
|
6
|
+
<p class="mt-0.5 text-xs font-medium">
|
|
7
|
+
<% if @unresolved_errors_count.to_i > 0 %>
|
|
8
|
+
<span class="text-rose-600"><%= @unresolved_errors_count %> unresolved</span>
|
|
9
|
+
<% else %>
|
|
10
|
+
<span class="text-emerald-600">all clear</span>
|
|
11
|
+
<% end %>
|
|
12
|
+
</p>
|
|
13
|
+
</div>
|
|
14
|
+
<% icon_bg = @unresolved_errors_count.to_i > 0 ? "bg-rose-50 text-rose-700 ring-rose-100" : "bg-emerald-50 text-emerald-700 ring-emerald-100" %>
|
|
15
|
+
<div class="inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-lg ring-1 ring-inset <%= icon_bg %>">
|
|
16
|
+
<svg class="h-3.5 w-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z"/></svg>
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
19
|
+
<div class="mt-3 border-t border-gray-100 pt-2">
|
|
20
|
+
<%= link_to ruby_cms_admin_visitor_errors_path, class: "inline-flex items-center gap-1 text-xs font-medium text-gray-600 hover:text-gray-900 transition-colors" do %>
|
|
21
|
+
View all <svg class="h-3 w-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M9 5l7 7-7 7"/></svg>
|
|
22
|
+
<% end %>
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
@@ -3,196 +3,38 @@
|
|
|
3
3
|
subtitle: "Welcome back! Here's an overview of your CMS.",
|
|
4
4
|
content_card: false
|
|
5
5
|
) do %>
|
|
6
|
-
<div class="space-y-
|
|
6
|
+
<div class="space-y-5">
|
|
7
7
|
|
|
8
|
-
<%# Stats %>
|
|
9
|
-
<div class="grid grid-cols-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
<div class="min-w-0">
|
|
14
|
-
<p class="text-sm font-medium text-gray-500">Content blocks</p>
|
|
15
|
-
<p class="mt-2 text-3xl font-semibold tracking-tight text-gray-900 tabular-nums"><%= @content_blocks_count %></p>
|
|
16
|
-
<p class="mt-1 text-xs text-gray-500"><%= @content_blocks_published_count %> published</p>
|
|
17
|
-
</div>
|
|
18
|
-
<div class="mt-0.5 inline-flex h-9 w-9 items-center justify-center rounded-lg bg-teal-50 text-teal-700 ring-1 ring-inset ring-teal-100">
|
|
19
|
-
<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 10h16M4 14h8"/></svg>
|
|
20
|
-
</div>
|
|
21
|
-
</div>
|
|
22
|
-
<div class="mt-4 border-t border-gray-100 pt-3">
|
|
23
|
-
<%= link_to ruby_cms_admin_content_blocks_path, class: "inline-flex items-center gap-1 text-xs font-medium text-gray-600 hover:text-gray-900 transition-colors" do %>
|
|
24
|
-
Manage <svg class="h-3 w-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M9 5l7 7-7 7"/></svg>
|
|
25
|
-
<% end %>
|
|
26
|
-
</div>
|
|
27
|
-
</div>
|
|
28
|
-
|
|
29
|
-
<div class="rounded-lg border border-gray-200/80 bg-white p-5 shadow-sm">
|
|
30
|
-
<div class="flex items-start justify-between gap-3">
|
|
31
|
-
<div class="min-w-0">
|
|
32
|
-
<p class="text-sm font-medium text-gray-500">Users</p>
|
|
33
|
-
<p class="mt-2 text-3xl font-semibold tracking-tight text-gray-900 tabular-nums"><%= @users_count %></p>
|
|
34
|
-
<p class="mt-1 text-xs text-gray-500">registered</p>
|
|
35
|
-
</div>
|
|
36
|
-
<div class="mt-0.5 inline-flex h-9 w-9 items-center justify-center rounded-lg bg-blue-50 text-blue-700 ring-1 ring-inset ring-blue-100">
|
|
37
|
-
<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a4 4 0 00-4-4h-1M9 20H4v-2a4 4 0 014-4h1m4-4a4 4 0 110-8 4 4 0 010 8z"/></svg>
|
|
38
|
-
</div>
|
|
39
|
-
</div>
|
|
40
|
-
<div class="mt-4 border-t border-gray-100 pt-3">
|
|
41
|
-
<%= link_to ruby_cms_admin_users_path, class: "inline-flex items-center gap-1 text-xs font-medium text-gray-600 hover:text-gray-900 transition-colors" do %>
|
|
42
|
-
Manage <svg class="h-3 w-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M9 5l7 7-7 7"/></svg>
|
|
43
|
-
<% end %>
|
|
44
|
-
</div>
|
|
45
|
-
</div>
|
|
46
|
-
|
|
47
|
-
<div class="rounded-lg border border-gray-200/80 bg-white p-5 shadow-sm">
|
|
48
|
-
<div class="flex items-start justify-between gap-3">
|
|
49
|
-
<div class="min-w-0">
|
|
50
|
-
<p class="text-sm font-medium text-gray-500">Permissions</p>
|
|
51
|
-
<p class="mt-2 text-3xl font-semibold tracking-tight text-gray-900 tabular-nums"><%= @permissions_count %></p>
|
|
52
|
-
<p class="mt-1 text-xs text-gray-500"><%= @user_permissions_count %> grants</p>
|
|
53
|
-
</div>
|
|
54
|
-
<div class="mt-0.5 inline-flex h-9 w-9 items-center justify-center rounded-lg bg-violet-50 text-violet-700 ring-1 ring-inset ring-violet-100">
|
|
55
|
-
<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" 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"/></svg>
|
|
56
|
-
</div>
|
|
57
|
-
</div>
|
|
58
|
-
<div class="mt-4 border-t border-gray-100 pt-3">
|
|
59
|
-
<%= link_to ruby_cms_admin_permissions_path, class: "inline-flex items-center gap-1 text-xs font-medium text-gray-600 hover:text-gray-900 transition-colors" do %>
|
|
60
|
-
Manage <svg class="h-3 w-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M9 5l7 7-7 7"/></svg>
|
|
61
|
-
<% end %>
|
|
62
|
-
</div>
|
|
63
|
-
</div>
|
|
64
|
-
|
|
65
|
-
<div class="rounded-lg border border-gray-200/80 bg-white p-5 shadow-sm">
|
|
66
|
-
<div class="flex items-start justify-between gap-3">
|
|
67
|
-
<div class="min-w-0">
|
|
68
|
-
<p class="text-sm font-medium text-gray-500">Visitor errors</p>
|
|
69
|
-
<p class="mt-2 text-3xl font-semibold tracking-tight text-gray-900 tabular-nums"><%= @visitor_errors_count %></p>
|
|
70
|
-
<p class="mt-1 text-xs font-medium">
|
|
71
|
-
<% if @unresolved_errors_count.to_i > 0 %>
|
|
72
|
-
<span class="text-rose-600"><%= @unresolved_errors_count %> unresolved</span>
|
|
73
|
-
<% else %>
|
|
74
|
-
<span class="text-emerald-600">all clear</span>
|
|
75
|
-
<% end %>
|
|
76
|
-
</p>
|
|
77
|
-
</div>
|
|
78
|
-
<% icon_bg = @unresolved_errors_count.to_i > 0 ? "bg-rose-50 text-rose-700 ring-rose-100" : "bg-emerald-50 text-emerald-700 ring-emerald-100" %>
|
|
79
|
-
<div class="mt-0.5 inline-flex h-9 w-9 items-center justify-center rounded-lg ring-1 ring-inset <%= icon_bg %>">
|
|
80
|
-
<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z"/></svg>
|
|
81
|
-
</div>
|
|
8
|
+
<%# Stats — compact, all four on one row from md upward %>
|
|
9
|
+
<div class="grid grid-cols-2 gap-3 md:grid-cols-4">
|
|
10
|
+
<% @stats_blocks.each do |block| %>
|
|
11
|
+
<div class="flex flex-col">
|
|
12
|
+
<%= render_dashboard_block(block) %>
|
|
82
13
|
</div>
|
|
83
|
-
|
|
84
|
-
<%= link_to ruby_cms_admin_visitor_errors_path, class: "inline-flex items-center gap-1 text-xs font-medium text-gray-600 hover:text-gray-900 transition-colors" do %>
|
|
85
|
-
View all <svg class="h-3 w-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M9 5l7 7-7 7"/></svg>
|
|
86
|
-
<% end %>
|
|
87
|
-
</div>
|
|
88
|
-
</div>
|
|
89
|
-
|
|
14
|
+
<% end %>
|
|
90
15
|
</div>
|
|
91
16
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
17
|
+
<%# Built-in row: quick actions | recent errors | analytics — always equal-width columns %>
|
|
18
|
+
<% if @primary_main_blocks.any? %>
|
|
19
|
+
<div class="grid grid-cols-1 items-stretch gap-4 lg:grid-cols-3 my-4">
|
|
20
|
+
<% @primary_main_blocks.each do |block| %>
|
|
21
|
+
<div class="flex min-w-0 flex-col">
|
|
22
|
+
<%= render_dashboard_block(block) %>
|
|
98
23
|
</div>
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
<div class="divide-y divide-gray-100">
|
|
102
|
-
<%= link_to new_ruby_cms_admin_content_block_path, class: "group flex items-center justify-between px-6 py-4 hover:bg-gray-50 transition-colors" do %>
|
|
103
|
-
<div class="flex items-center gap-3">
|
|
104
|
-
<div class="inline-flex h-9 w-9 items-center justify-center rounded-lg bg-teal-50 text-teal-700 ring-1 ring-inset ring-teal-100">
|
|
105
|
-
<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"/></svg>
|
|
106
|
-
</div>
|
|
107
|
-
<div>
|
|
108
|
-
<p class="text-sm font-medium text-gray-900">New content block</p>
|
|
109
|
-
<p class="text-sm text-gray-500">Create a new block</p>
|
|
110
|
-
</div>
|
|
111
|
-
</div>
|
|
112
|
-
<svg class="h-4 w-4 text-gray-300 group-hover:text-gray-500 transition-colors" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/></svg>
|
|
113
|
-
<% end %>
|
|
114
|
-
|
|
115
|
-
<%= link_to ruby_cms_admin_visual_editor_path, class: "group flex items-center justify-between px-6 py-4 hover:bg-gray-50 transition-colors" do %>
|
|
116
|
-
<div class="flex items-center gap-3">
|
|
117
|
-
<div class="inline-flex h-9 w-9 items-center justify-center rounded-lg bg-indigo-50 text-indigo-700 ring-1 ring-inset ring-indigo-100">
|
|
118
|
-
<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.232 5.232l3.536 3.536M9 11l6 6M3 21h18"/></svg>
|
|
119
|
-
</div>
|
|
120
|
-
<div>
|
|
121
|
-
<p class="text-sm font-medium text-gray-900">Visual editor</p>
|
|
122
|
-
<p class="text-sm text-gray-500">Edit content visually</p>
|
|
123
|
-
</div>
|
|
124
|
-
</div>
|
|
125
|
-
<svg class="h-4 w-4 text-gray-300 group-hover:text-gray-500 transition-colors" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/></svg>
|
|
126
|
-
<% end %>
|
|
127
|
-
|
|
128
|
-
<%= link_to ruby_cms_admin_visitor_errors_path, class: "group flex items-center justify-between px-6 py-4 hover:bg-gray-50 transition-colors" do %>
|
|
129
|
-
<div class="flex items-center gap-3">
|
|
130
|
-
<div class="inline-flex h-9 w-9 items-center justify-center rounded-lg bg-rose-50 text-rose-700 ring-1 ring-inset ring-rose-100">
|
|
131
|
-
<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>
|
|
132
|
-
</div>
|
|
133
|
-
<div>
|
|
134
|
-
<p class="text-sm font-medium text-gray-900">Visitor errors</p>
|
|
135
|
-
<p class="text-sm text-gray-500">Review recent issues</p>
|
|
136
|
-
</div>
|
|
137
|
-
</div>
|
|
138
|
-
<svg class="h-4 w-4 text-gray-300 group-hover:text-gray-500 transition-colors" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/></svg>
|
|
139
|
-
<% end %>
|
|
140
|
-
|
|
141
|
-
<%= link_to ruby_cms_admin_settings_path, class: "group flex items-center justify-between px-6 py-4 hover:bg-gray-50 transition-colors" do %>
|
|
142
|
-
<div class="flex items-center gap-3">
|
|
143
|
-
<div class="inline-flex h-9 w-9 items-center justify-center rounded-lg bg-gray-100 text-gray-700 ring-1 ring-inset ring-gray-200">
|
|
144
|
-
<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" 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.065 2.572c1.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.572 1.065c-.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.065-2.572c-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 stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/></svg>
|
|
145
|
-
</div>
|
|
146
|
-
<div>
|
|
147
|
-
<p class="text-sm font-medium text-gray-900">Settings</p>
|
|
148
|
-
<p class="text-sm text-gray-500">Configure RubyCMS</p>
|
|
149
|
-
</div>
|
|
150
|
-
</div>
|
|
151
|
-
<svg class="h-4 w-4 text-gray-300 group-hover:text-gray-500 transition-colors" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/></svg>
|
|
152
|
-
<% end %>
|
|
153
|
-
</div>
|
|
24
|
+
<% end %>
|
|
154
25
|
</div>
|
|
26
|
+
<% end %>
|
|
155
27
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
<%= link_to "View all", ruby_cms_admin_visitor_errors_path, class: "text-sm font-medium text-gray-600 hover:text-gray-900 transition-colors" %>
|
|
163
|
-
</div>
|
|
164
|
-
|
|
165
|
-
<% if @recent_errors.any? %>
|
|
166
|
-
<div class="divide-y divide-gray-100">
|
|
167
|
-
<% @recent_errors.first(5).each do |error| %>
|
|
168
|
-
<div class="px-6 py-4">
|
|
169
|
-
<p class="text-sm font-medium text-gray-900 truncate">
|
|
170
|
-
<span class="text-gray-500 font-normal"><%= error.error_class %>:</span>
|
|
171
|
-
<%= error.error_message.truncate(70) %>
|
|
172
|
-
</p>
|
|
173
|
-
<div class="mt-2 flex items-center justify-between gap-3">
|
|
174
|
-
<div class="flex items-center gap-2">
|
|
175
|
-
<span class="inline-flex items-center rounded-md px-2 py-0.5 text-xs font-medium ring-1 ring-inset <%= error.resolved? ? 'bg-emerald-50 text-emerald-700 ring-emerald-200' : 'bg-rose-50 text-rose-700 ring-rose-200' %>">
|
|
176
|
-
<%= error.resolved? ? 'Resolved' : 'Unresolved' %>
|
|
177
|
-
</span>
|
|
178
|
-
<span class="text-xs text-gray-500"><%= time_ago_in_words(error.created_at) %> ago</span>
|
|
179
|
-
</div>
|
|
180
|
-
<%= link_to "Open", ruby_cms_admin_visitor_error_path(error), class: "text-sm font-medium text-gray-600 hover:text-gray-900 transition-colors" %>
|
|
181
|
-
</div>
|
|
182
|
-
</div>
|
|
183
|
-
<% end %>
|
|
184
|
-
</div>
|
|
185
|
-
<% else %>
|
|
186
|
-
<div class="px-6 py-12 text-center">
|
|
187
|
-
<div class="mx-auto mb-3 inline-flex h-11 w-11 items-center justify-center rounded-lg bg-emerald-50 ring-1 ring-inset ring-emerald-100">
|
|
188
|
-
<svg class="h-5 w-5 text-emerald-600" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>
|
|
189
|
-
</div>
|
|
190
|
-
<p class="text-sm font-medium text-gray-900">No errors recorded</p>
|
|
191
|
-
<p class="mt-1 text-sm text-gray-500">Everything is running smoothly.</p>
|
|
28
|
+
<%# Host / custom dashboard blocks %>
|
|
29
|
+
<% if @extra_main_blocks.any? %>
|
|
30
|
+
<div class="grid grid-cols-1 items-stretch gap-4 lg:grid-cols-3">
|
|
31
|
+
<% @extra_main_blocks.each do |block| %>
|
|
32
|
+
<div class="flex min-w-0 flex-col <%= block[:span] == :double ? 'lg:col-span-2' : '' %>">
|
|
33
|
+
<%= render_dashboard_block(block) %>
|
|
192
34
|
</div>
|
|
193
35
|
<% end %>
|
|
194
36
|
</div>
|
|
195
|
-
|
|
37
|
+
<% end %>
|
|
196
38
|
|
|
197
39
|
</div>
|
|
198
40
|
<% end %>
|
data/config/routes.rb
CHANGED
|
@@ -12,6 +12,14 @@ RubyCms::Engine.routes.draw do # rubocop:disable Metrics/BlockLength
|
|
|
12
12
|
end
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
+
resources :content_blocks, only: [] do
|
|
16
|
+
resources :versions, controller: "content_block_versions", only: %i[index show] do
|
|
17
|
+
member do
|
|
18
|
+
post :rollback
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
15
23
|
resources :permissions, only: %i[index create destroy] do
|
|
16
24
|
collection do
|
|
17
25
|
delete "bulk_delete", to: "permissions#bulk_delete"
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class CreateContentBlockVersions < ActiveRecord::Migration[7.1]
|
|
4
|
+
def change
|
|
5
|
+
create_table :content_block_versions do |t|
|
|
6
|
+
t.references :content_block, null: false, foreign_key: true, index: true
|
|
7
|
+
t.references :user, null: true, foreign_key: true
|
|
8
|
+
t.integer :version_number, null: false
|
|
9
|
+
t.string :title, null: false
|
|
10
|
+
t.text :content
|
|
11
|
+
t.text :rich_content_html
|
|
12
|
+
t.string :content_type, null: false
|
|
13
|
+
t.boolean :published, null: false, default: true
|
|
14
|
+
t.string :event, null: false, default: "update"
|
|
15
|
+
t.jsonb :metadata, default: {}
|
|
16
|
+
t.datetime :created_at, null: false
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
add_index :content_block_versions, %i[content_block_id version_number],
|
|
20
|
+
unique: true, name: "idx_cb_versions_on_block_and_number"
|
|
21
|
+
end
|
|
22
|
+
end
|