lato_cms 3.0.6 → 3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cbcd0c46e947f128bf5c6334e7729fbbbe12682c3b2e89d4442bb7b1a73528a4
4
- data.tar.gz: 040ad879939068be79b8078a3a011a40f49f8a35f7539e9d791904b4148df4c2
3
+ metadata.gz: 84d12b9402630a14e022073320e2be275b41d57ae6877c25d4fa9a7be933b05f
4
+ data.tar.gz: 02536eb6c44e39de36bf0f76ea01c6736dfa9f9ed8ba87df043ae61fcd162678
5
5
  SHA512:
6
- metadata.gz: 1644c351792d4ced7526999d47f250ebb09b3fd5f9de897818465bfa37e00b7623af635309a589b5fb8001ef5d7021c11f7e854738c6054eb719398dc46f8d98
7
- data.tar.gz: 39131b5dd434621e95a147d27287c0479e06ca42f086f73906f185e0a0b64086bc134234315400dc56a6ef20dfab49a867a102eec522f4d41c5e986c9cf9c2f0
6
+ metadata.gz: f12d80e77289eed7f5de7306148171c651eb9ad6069cc3178e34c04b32913dcbee72da1f74c7f5d2fa44f4c1525ce1b1c79fdda161b185bea62510e27a3d800b
7
+ data.tar.gz: 58a79d85a6c1b18498120b82ee7c39b77cf5d97a7bd2c6866f494c6118fa85b42346246f6ff9afd74dc146aa4eb32a2f5e9e775d26fd0999c7641bead3f62ca0
@@ -1,55 +1,35 @@
1
1
  import { Controller } from "@hotwired/stimulus"
2
2
 
3
3
  export default class extends Controller {
4
- static targets = ["row", "previewCol", "editorCol", "toggleBtn", "collapseBtn", "reopenBtn"]
4
+ static targets = ["row", "editorCol", "reopenBtn"]
5
+ static values = { listPath: String }
5
6
 
6
- isActive = false
7
7
  isSidebarOpen = true
8
8
 
9
- // ─── Toggle advanced mode ────────────────────────────────────────────────────
10
-
11
- toggle() {
12
- this.isActive ? this.deactivate() : this.activate()
13
- }
14
-
15
- activate() {
16
- this.isActive = true
17
- this.isSidebarOpen = true
9
+ // ─── Advanced full-screen editor is the only view ────────────────────────────
18
10
 
11
+ // Activate on load: no base view exists, only back to the pages list.
12
+ connect() {
19
13
  this.rowTarget.classList.add('lato-cms-advanced-editor__row--active')
20
14
  document.body.classList.add('lato-cms-advanced-editor--open')
21
15
 
22
- this.toggleBtnTarget.title = 'Exit advanced editor'
23
- this.toggleBtnTarget.querySelector('i').className = 'bi bi-fullscreen-exit'
24
- this.collapseBtnTarget.classList.remove('d-none')
25
- this.editorColTarget.classList.remove('lato-cms-advanced-editor__editor-col--collapsed')
26
- this.reopenBtnTarget.hidden = true
27
-
28
- this._escHandler = (e) => { if (e.key === 'Escape') this.deactivate() }
16
+ // Escape returns to the pages list instead of exiting to a base view.
17
+ this._escHandler = (e) => { if (e.key === 'Escape') this.back() }
29
18
  document.addEventListener('keydown', this._escHandler)
30
19
  }
31
20
 
32
- deactivate() {
33
- this.isActive = false
34
- this.isSidebarOpen = true
35
-
36
- this.rowTarget.classList.remove('lato-cms-advanced-editor__row--active')
21
+ disconnect() {
37
22
  document.body.classList.remove('lato-cms-advanced-editor--open')
38
-
39
- this.toggleBtnTarget.title = 'Advanced editor'
40
- this.toggleBtnTarget.querySelector('i').className = 'bi bi-fullscreen'
41
- this.collapseBtnTarget.classList.add('d-none')
42
- this.editorColTarget.classList.remove('lato-cms-advanced-editor__editor-col--collapsed')
43
- this.reopenBtnTarget.hidden = true
44
-
45
23
  document.removeEventListener('keydown', this._escHandler)
46
24
  }
47
25
 
26
+ back() {
27
+ if (this.hasListPathValue) window.location.href = this.listPathValue
28
+ }
29
+
48
30
  // ─── Toggle sidebar within advanced mode ─────────────────────────────────────
49
31
 
50
32
  toggleSidebar() {
51
- if (!this.isActive) return
52
-
53
33
  this.isSidebarOpen = !this.isSidebarOpen
54
34
  this.editorColTarget.classList.toggle('lato-cms-advanced-editor__editor-col--collapsed', !this.isSidebarOpen)
55
35
  this.reopenBtnTarget.hidden = this.isSidebarOpen
@@ -1,7 +1,7 @@
1
1
  import { Controller } from '@hotwired/stimulus'
2
2
 
3
3
  export default class extends Controller {
4
- static targets = ['iframe']
4
+ static targets = ['iframe', 'viewport', 'deviceBtn', 'customWidth', 'dimensions']
5
5
 
6
6
  connect () {
7
7
  this.handleComponentChange = this.handleComponentChange.bind(this)
@@ -11,6 +11,12 @@ export default class extends Controller {
11
11
 
12
12
  if (this.hasIframeTarget) {
13
13
  this.iframeTarget.addEventListener('load', this.handleIframeLoad)
14
+
15
+ // Live viewport dimensions readout
16
+ if (window.ResizeObserver) {
17
+ this.resizeObserver = new window.ResizeObserver(() => this.updateDimensions())
18
+ this.resizeObserver.observe(this.iframeTarget)
19
+ }
14
20
  }
15
21
 
16
22
  window.requestAnimationFrame(() => {
@@ -24,6 +30,8 @@ export default class extends Controller {
24
30
  if (this.hasIframeTarget) {
25
31
  this.iframeTarget.removeEventListener('load', this.handleIframeLoad)
26
32
  }
33
+
34
+ if (this.resizeObserver) this.resizeObserver.disconnect()
27
35
  }
28
36
 
29
37
  refresh () {
@@ -37,6 +45,61 @@ export default class extends Controller {
37
45
  }
38
46
  }
39
47
 
48
+ // Constrain the preview iframe to a device viewport width.
49
+ setDevice (event) {
50
+ if (!this.hasViewportTarget) return
51
+
52
+ const device = event.currentTarget.dataset.device
53
+
54
+ this.iframeTarget.style.maxWidth = ''
55
+ this.viewportTarget.classList.remove(
56
+ 'lato-cms-page-preview__viewport--tablet',
57
+ 'lato-cms-page-preview__viewport--mobile',
58
+ 'lato-cms-page-preview__viewport--custom'
59
+ )
60
+ if (device !== 'desktop') {
61
+ this.viewportTarget.classList.add(`lato-cms-page-preview__viewport--${device}`)
62
+ }
63
+
64
+ this.deviceBtnTargets.forEach(btn => {
65
+ btn.classList.toggle('active', btn.dataset.device === device)
66
+ })
67
+
68
+ if (this.hasCustomWidthTarget) this.customWidthTarget.value = ''
69
+ }
70
+
71
+ // Constrain the preview iframe to a user-defined width (px).
72
+ setCustomWidth () {
73
+ if (!this.hasViewportTarget || !this.hasCustomWidthTarget) return
74
+
75
+ const width = parseInt(this.customWidthTarget.value, 10)
76
+
77
+ this.deviceBtnTargets.forEach(btn => btn.classList.remove('active'))
78
+ this.viewportTarget.classList.remove(
79
+ 'lato-cms-page-preview__viewport--tablet',
80
+ 'lato-cms-page-preview__viewport--mobile'
81
+ )
82
+
83
+ if (Number.isFinite(width) && width > 0) {
84
+ this.viewportTarget.classList.add('lato-cms-page-preview__viewport--custom')
85
+ this.iframeTarget.style.maxWidth = `${width}px`
86
+ } else {
87
+ // Empty/invalid input → revert to desktop
88
+ this.viewportTarget.classList.remove('lato-cms-page-preview__viewport--custom')
89
+ this.iframeTarget.style.maxWidth = ''
90
+ this.deviceBtnTargets.forEach(btn => {
91
+ btn.classList.toggle('active', btn.dataset.device === 'desktop')
92
+ })
93
+ }
94
+ }
95
+
96
+ updateDimensions () {
97
+ if (!this.hasIframeTarget || !this.hasDimensionsTarget) return
98
+
99
+ const rect = this.iframeTarget.getBoundingClientRect()
100
+ this.dimensionsTarget.textContent = `${Math.round(rect.width)} × ${Math.round(rect.height)} px`
101
+ }
102
+
40
103
  handleComponentChange (event) {
41
104
  this.activeComponent = event.detail
42
105
  this.postActiveComponent()
@@ -25,8 +25,11 @@ body.lato-cms-advanced-editor--open {
25
25
  border: none !important;
26
26
  border-radius: 0 !important;
27
27
 
28
- iframe {
29
- height: 100dvh !important;
28
+ // Preview viewport fills the space below the device toolbar
29
+ > .lato-cms-page-preview__viewport {
30
+ flex: 1 1 auto;
31
+ min-height: 0;
32
+ height: auto;
30
33
  }
31
34
 
32
35
  // No-preview placeholder fills full screen
@@ -95,6 +98,50 @@ body.lato-cms-advanced-editor--open {
95
98
  }
96
99
  }
97
100
 
101
+ // ── Page preview viewport (responsive device modes) ────────────────────────────
102
+
103
+ .lato-cms-page-preview__viewport {
104
+ display: flex;
105
+ justify-content: center;
106
+ align-items: stretch;
107
+ overflow: auto;
108
+ background: var(--bs-secondary-bg, #f1f3f5);
109
+ height: calc(100dvh - 230px);
110
+
111
+ iframe {
112
+ width: 100%;
113
+ height: 100%;
114
+ border: none;
115
+ display: block;
116
+ background: #fff;
117
+ transition: max-width 0.25s ease, max-height 0.25s ease;
118
+ }
119
+
120
+ // Device modes: constrain to realistic viewport size and center vertically
121
+ &--tablet,
122
+ &--mobile,
123
+ &--custom {
124
+ align-items: center;
125
+ padding: 1rem;
126
+
127
+ iframe {
128
+ border: 1px solid var(--bs-border-color);
129
+ border-radius: 12px;
130
+ box-shadow: 0 4px 24px rgba(0, 0, 0, 0.12);
131
+ }
132
+ }
133
+
134
+ &--tablet iframe {
135
+ max-width: 768px;
136
+ max-height: 1024px;
137
+ }
138
+
139
+ &--mobile iframe {
140
+ max-width: 375px;
141
+ max-height: 812px;
142
+ }
143
+ }
144
+
98
145
  // ── Component form status ──────────────────────────────────────────────────────
99
146
 
100
147
  .lato-cms-component-form__status {
@@ -4,9 +4,11 @@ module LatoCms
4
4
  layout 'lato/application'
5
5
  before_action :authenticate_session
6
6
  before_action :authenticate_group
7
- before_action :authenticate_lato_cms_admin
7
+ before_action :authenticate_lato_cms_access
8
8
  before_action { active_sidebar(:lato_cms); active_navbar(:lato_cms) }
9
9
 
10
+ helper_method :lato_cms_admin?
11
+
10
12
  def index
11
13
  redirect_to lato_cms.pages_path
12
14
  end
@@ -17,10 +19,23 @@ module LatoCms
17
19
  @query_pages ||= LatoCms::Page.for_lato_spaces_group(@session.get(:spaces_group_id))
18
20
  end
19
21
 
20
- def authenticate_lato_cms_admin
21
- return true if @session.user&.lato_cms_admin
22
+ # Section-level guard: any CMS role (operator or admin) may enter.
23
+ def authenticate_lato_cms_access
24
+ return true if @session.user&.lato_cms_access?
22
25
 
23
26
  redirect_to lato.root_path, alert: t('lato_cms.unauthorized_section')
24
27
  end
28
+
29
+ # Action-level guard for page management and translation links: admin only.
30
+ def authenticate_lato_cms_admin
31
+ return true if lato_cms_admin?
32
+
33
+ redirect_to lato_cms.pages_path, alert: t('lato_cms.unauthorized_action')
34
+ end
35
+
36
+ # Exposed to views to conditionally render admin-only controls.
37
+ def lato_cms_admin?
38
+ @session.user&.lato_cms_admin? || false
39
+ end
25
40
  end
26
41
  end
@@ -1,6 +1,16 @@
1
1
  module LatoCms
2
2
  class PagesController < ApplicationController
3
+ # Page management and translation links are reserved to the admin role.
4
+ # Operators keep read access plus field editing and component toggles.
5
+ ADMIN_ONLY_ACTIONS = %i[
6
+ create create_action
7
+ update update_action
8
+ destroy_action
9
+ translations link_translation_action unlink_translation_action
10
+ ].freeze
11
+
3
12
  before_action { active_sidebar(:lato_cms_pages) }
13
+ before_action :authenticate_lato_cms_admin, only: ADMIN_ONLY_ACTIONS
4
14
 
5
15
  def index
6
16
  pages = query_pages
@@ -13,7 +13,7 @@
13
13
  </div>
14
14
  <div class="card-body">
15
15
  <%= lato_index @pages,
16
- custom_actions: {
16
+ custom_actions: lato_cms_admin? ? {
17
17
  create: {
18
18
  path: lato_cms.pages_create_path,
19
19
  icon: 'bi bi-plus',
@@ -25,7 +25,7 @@
25
25
  action_title: t('lato_cms.page_create_title')
26
26
  }
27
27
  }
28
- },
28
+ } : {},
29
29
  pagination_options: [10, 20, 50, 100]
30
30
  %>
31
31
  </div>
@@ -3,15 +3,55 @@
3
3
  { label: @page.title }
4
4
  ] %>
5
5
 
6
- <div data-controller="lato-cms-advanced-editor">
6
+ <div data-controller="lato-cms-advanced-editor" data-lato-cms-advanced-editor-list-path-value="<%= lato_cms.pages_path %>">
7
7
  <div class="row align-items-stretch lato-cms-advanced-editor__row" data-lato-cms-advanced-editor-target="row">
8
8
 
9
9
  <%# ── Preview column ─────────────────────────────────────────────────── %>
10
- <div class="col-12 col-lg-6 mb-4 lato-cms-advanced-editor__preview-col" data-lato-cms-advanced-editor-target="previewCol">
10
+ <div class="col-12 col-lg-6 mb-4 lato-cms-advanced-editor__preview-col">
11
11
  <% if @page.frontend_url.present? %>
12
12
  <div class="card h-100" style="overflow: hidden;" data-controller="lato-cms-page-preview">
13
- <div class="card-body p-0">
14
- <iframe src="<%= @page.frontend_url %>" data-lato-cms-page-preview-target="iframe" style="width: 100%; height: calc(100dvh - 180px); border: none; display: block;"></iframe>
13
+ <div class="card-header d-flex justify-content-between align-items-center py-2 gap-2">
14
+ <div class="btn-group btn-group-sm" role="group">
15
+ <button type="button" class="btn btn-outline-secondary active"
16
+ title="<%= t('lato_cms.show_preview_desktop_tooltip') %>"
17
+ data-controller="lato-tooltip"
18
+ data-action="click->lato-cms-page-preview#setDevice"
19
+ data-device="desktop"
20
+ data-lato-cms-page-preview-target="deviceBtn">
21
+ <i class="bi bi-display"></i>
22
+ </button>
23
+ <button type="button" class="btn btn-outline-secondary"
24
+ title="<%= t('lato_cms.show_preview_tablet_tooltip') %>"
25
+ data-controller="lato-tooltip"
26
+ data-action="click->lato-cms-page-preview#setDevice"
27
+ data-device="tablet"
28
+ data-lato-cms-page-preview-target="deviceBtn">
29
+ <i class="bi bi-tablet"></i>
30
+ </button>
31
+ <button type="button" class="btn btn-outline-secondary"
32
+ title="<%= t('lato_cms.show_preview_mobile_tooltip') %>"
33
+ data-controller="lato-tooltip"
34
+ data-action="click->lato-cms-page-preview#setDevice"
35
+ data-device="mobile"
36
+ data-lato-cms-page-preview-target="deviceBtn">
37
+ <i class="bi bi-phone"></i>
38
+ </button>
39
+ </div>
40
+ <div class="d-flex align-items-center gap-2">
41
+ <div class="input-group input-group-sm" style="width: 130px;">
42
+ <input type="number" class="form-control" min="320" max="3840" step="1"
43
+ placeholder="<%= t('lato_cms.show_preview_custom_width_placeholder') %>"
44
+ title="<%= t('lato_cms.show_preview_custom_width_tooltip') %>"
45
+ data-controller="lato-tooltip"
46
+ data-action="input->lato-cms-page-preview#setCustomWidth"
47
+ data-lato-cms-page-preview-target="customWidth">
48
+ <span class="input-group-text">px</span>
49
+ </div>
50
+ <span class="badge text-bg-light font-monospace" data-lato-cms-page-preview-target="dimensions">—</span>
51
+ </div>
52
+ </div>
53
+ <div class="lato-cms-page-preview__viewport" data-lato-cms-page-preview-target="viewport">
54
+ <iframe src="<%= @page.frontend_url %>" data-lato-cms-page-preview-target="iframe"></iframe>
15
55
  </div>
16
56
  </div>
17
57
  <% else %>
@@ -20,8 +60,10 @@
20
60
  <i class="bi bi-globe fs-1 mb-3"></i>
21
61
  <p class="mb-1"><%= t('lato_cms.show_no_preview_title') %></p>
22
62
  <p class="small"><%= t('lato_cms.show_no_preview_description').html_safe %></p>
23
- <%= link_to t('lato_cms.show_edit_settings_cta'), lato_cms.pages_update_path(@page), class: 'btn btn-sm btn-outline-primary mt-2',
24
- data: { lato_action_target: 'trigger', turbo_frame: dom_id(@page, 'form'), action_title: t('lato_cms.page_update_title') } %>
63
+ <% if lato_cms_admin? %>
64
+ <%= link_to t('lato_cms.show_edit_settings_cta'), lato_cms.pages_update_path(@page), class: 'btn btn-sm btn-outline-primary mt-2',
65
+ data: { lato_action_target: 'trigger', turbo_frame: dom_id(@page, 'form'), action_title: t('lato_cms.page_update_title') } %>
66
+ <% end %>
25
67
  </div>
26
68
  </div>
27
69
  <% end %>
@@ -35,22 +77,18 @@
35
77
  <div class="d-flex align-items-center gap-2">
36
78
  <%= lato_cms_page_locale_dropdown(@page) %>
37
79
  <span class="vr"></span>
38
- <%= lato_cms_page_actions_dropdown(@page, show_edit: true, show_translations: true, show_delete: true, hide_show: true) %>
80
+ <%= lato_cms_page_actions_dropdown(@page, show_edit: lato_cms_admin?, show_translations: lato_cms_admin?, show_delete: lato_cms_admin?, hide_show: true) %>
39
81
  <span class="vr"></span>
40
- <button class="btn btn-sm btn-outline-primary d-none"
82
+ <button class="btn btn-sm btn-outline-primary"
41
83
  title="<%= t('lato_cms.show_hide_panel_tooltip') %>"
42
84
  data-controller="lato-tooltip"
43
- data-action="click->lato-cms-advanced-editor#toggleSidebar"
44
- data-lato-cms-advanced-editor-target="collapseBtn">
85
+ data-action="click->lato-cms-advanced-editor#toggleSidebar">
45
86
  <i class="bi bi-layout-sidebar-reverse"></i>
46
87
  </button>
47
- <button class="btn btn-sm btn-outline-primary"
48
- title="<%= t('lato_cms.show_advanced_editor_tooltip') %>"
49
- data-controller="lato-tooltip"
50
- data-action="click->lato-cms-advanced-editor#toggle"
51
- data-lato-cms-advanced-editor-target="toggleBtn">
52
- <i class="bi bi-fullscreen"></i>
53
- </button>
88
+ <%= link_to lato_cms.pages_path, class: 'btn btn-sm btn-outline-danger',
89
+ title: t('lato_cms.show_back_to_list_tooltip'), data: { controller: 'lato-tooltip' } do %>
90
+ <i class="bi bi-box-arrow-left"></i>
91
+ <% end %>
54
92
  </div>
55
93
  </div>
56
94
  <div class="card-body" style="overflow-y: auto; max-height: calc(100dvh - 230px);">
@@ -59,15 +97,19 @@
59
97
  <i class="bi bi-file-earmark-code fs-1 mb-3 d-block"></i>
60
98
  <p class="mb-1"><%= t('lato_cms.show_no_template_title') %></p>
61
99
  <p class="small"><%= t('lato_cms.show_no_template_description') %></p>
62
- <%= link_to t('lato_cms.show_edit_settings_cta'), lato_cms.pages_update_path(@page), class: 'btn btn-sm btn-outline-primary mt-2',
63
- data: { lato_action_target: 'trigger', turbo_frame: dom_id(@page, 'form'), action_title: t('lato_cms.page_update_title') } %>
100
+ <% if lato_cms_admin? %>
101
+ <%= link_to t('lato_cms.show_edit_settings_cta'), lato_cms.pages_update_path(@page), class: 'btn btn-sm btn-outline-primary mt-2',
102
+ data: { lato_action_target: 'trigger', turbo_frame: dom_id(@page, 'form'), action_title: t('lato_cms.page_update_title') } %>
103
+ <% end %>
64
104
  </div>
65
105
  <% elsif !@page.template_available? %>
66
106
  <div class="alert alert-warning">
67
107
  <i class="bi bi-exclamation-triangle me-1"></i>
68
108
  <%= t('lato_cms.show_template_unavailable', template_id: @page.template_id) %>
69
- <%= link_to t('lato_cms.show_edit_settings_cta'), lato_cms.pages_update_path(@page), class: 'btn btn-sm btn-outline-warning ms-2',
70
- data: { lato_action_target: 'trigger', turbo_frame: dom_id(@page, 'form'), action_title: t('lato_cms.page_update_title') } %>
109
+ <% if lato_cms_admin? %>
110
+ <%= link_to t('lato_cms.show_edit_settings_cta'), lato_cms.pages_update_path(@page), class: 'btn btn-sm btn-outline-warning ms-2',
111
+ data: { lato_action_target: 'trigger', turbo_frame: dom_id(@page, 'form'), action_title: t('lato_cms.page_update_title') } %>
112
+ <% end %>
71
113
  </div>
72
114
  <% existing_fields = @page.fields.group_by(&:template_component_id) %>
73
115
  <% if existing_fields.any? %>
@@ -1,5 +1,13 @@
1
1
  en:
2
+ activerecord:
3
+ attributes:
4
+ lato/user:
5
+ lato_cms_admin_role: Lato CMS role
2
6
  lato_cms:
7
+ admin_roles:
8
+ none: No access
9
+ operator: Operator
10
+ admin: Administrator
3
11
  cta_show: Show
4
12
  cta_edit: Edit
5
13
  cta_update: Update
@@ -11,6 +19,7 @@ en:
11
19
  fields_saved: Fields saved successfully
12
20
  page_deleted: Page deleted successfully
13
21
  unauthorized_section: You do not have access to this section.
22
+ unauthorized_action: You do not have permission to perform this action.
14
23
  page_delete_failed: Failed to delete page
15
24
  api_page_not_found: Page not found
16
25
  pages_index_title: Pages
@@ -38,9 +47,14 @@ en:
38
47
  show_no_preview_description: Set the <strong>Frontend URL</strong> to see the page preview.
39
48
  show_edit_settings_cta: Edit page settings
40
49
  show_editor_title: Editor
41
- show_advanced_editor_tooltip: Advanced editor
42
50
  show_hide_panel_tooltip: Hide panel
43
51
  show_show_editor_panel_tooltip: Show editor panel
52
+ show_back_to_list_tooltip: Back to pages
53
+ show_preview_desktop_tooltip: Desktop
54
+ show_preview_tablet_tooltip: Tablet
55
+ show_preview_mobile_tooltip: Mobile
56
+ show_preview_custom_width_tooltip: Custom width
57
+ show_preview_custom_width_placeholder: Width
44
58
  show_no_template_title: No template assigned
45
59
  show_no_template_description: Assign a template to start editing fields.
46
60
  show_template_unavailable: "The template <strong>%{template_id}</strong> is no longer available. Please assign a different template."
@@ -1,5 +1,13 @@
1
1
  it:
2
+ activerecord:
3
+ attributes:
4
+ lato/user:
5
+ lato_cms_admin_role: Ruolo Lato CMS
2
6
  lato_cms:
7
+ admin_roles:
8
+ none: Nessun accesso
9
+ operator: Operatore
10
+ admin: Amministratore
3
11
  cta_show: Visualizza
4
12
  cta_edit: Modifica
5
13
  cta_update: Aggiorna
@@ -11,6 +19,7 @@ it:
11
19
  fields_saved: Campi salvati con successo
12
20
  page_deleted: Pagina eliminata con successo
13
21
  unauthorized_section: Non hai accesso a questa sezione.
22
+ unauthorized_action: Non hai i permessi per eseguire questa azione.
14
23
  page_delete_failed: Impossibile eliminare la pagina
15
24
  api_page_not_found: Pagina non trovata
16
25
  pages_index_title: Pagine
@@ -38,9 +47,14 @@ it:
38
47
  show_no_preview_description: Imposta il <strong>URL Frontend</strong> per visualizzare l'anteprima della pagina.
39
48
  show_edit_settings_cta: Modifica impostazioni pagina
40
49
  show_editor_title: Editor
41
- show_advanced_editor_tooltip: Editor avanzato
42
50
  show_hide_panel_tooltip: Nascondi pannello
43
51
  show_show_editor_panel_tooltip: Mostra pannello editor
52
+ show_back_to_list_tooltip: Torna alle pagine
53
+ show_preview_desktop_tooltip: Desktop
54
+ show_preview_tablet_tooltip: Tablet
55
+ show_preview_mobile_tooltip: Mobile
56
+ show_preview_custom_width_tooltip: Larghezza personalizzata
57
+ show_preview_custom_width_placeholder: Larghezza
44
58
  show_no_template_title: Nessun template assegnato
45
59
  show_no_template_description: Assegna un template per iniziare a modificare i campi.
46
60
  show_template_unavailable: "Il template <strong>%{template_id}</strong> non e piu disponibile. Assegna un template diverso."
@@ -0,0 +1,18 @@
1
+ class ChangeLatoCmsAdminToLatoCmsAdminRoleOnLatoUser < ActiveRecord::Migration[8.1]
2
+ def up
3
+ add_column :lato_users, :lato_cms_admin_role, :integer, default: 0, null: false
4
+
5
+ # Backfill: true -> 1, false/nil -> 0 (already the column default)
6
+ execute 'UPDATE lato_users SET lato_cms_admin_role = 1 WHERE lato_cms_admin = 1'
7
+
8
+ remove_column :lato_users, :lato_cms_admin
9
+ end
10
+
11
+ def down
12
+ add_column :lato_users, :lato_cms_admin, :boolean, default: false
13
+
14
+ execute 'UPDATE lato_users SET lato_cms_admin = 1 WHERE lato_cms_admin_role = 1'
15
+
16
+ remove_column :lato_users, :lato_cms_admin_role
17
+ end
18
+ end
@@ -3,11 +3,18 @@ module LatoCms
3
3
  # This class contains the default configuration of the engine.
4
4
  ##
5
5
  class Config
6
- attr_accessor :locales, :templates_path
6
+ attr_accessor :locales, :templates_path, :admin_roles
7
7
 
8
8
  def initialize
9
9
  @locales = [:en]
10
10
  @templates_path = 'config/lato_cms'
11
+
12
+ # Admin roles exposed on Lato::User#lato_cms_admin_role and rendered
13
+ # as a select by lato_users. Ordered map of role key => integer value;
14
+ # labels are resolved via i18n (lato_cms.admin_roles.<key>).
15
+ # `operator` has read/edit access; `admin` also manages pages
16
+ # (create, update, delete) and translation links.
17
+ @admin_roles = { none: 0, operator: 1, admin: 2 }
11
18
  end
12
19
  end
13
20
  end
@@ -9,5 +9,32 @@ module LatoCms
9
9
  initializer "lato_cms.precompile" do |app|
10
10
  app.config.assets.precompile << "lato_cms_manifest.js"
11
11
  end
12
+
13
+ # Expose the CMS admin role options on the shared Lato::User model.
14
+ # lato_users (when mounted) discovers the `lato_cms_admin_role` column by
15
+ # convention and calls this method to build the role selector. Defined
16
+ # here so it works regardless of whether lato_users is installed.
17
+ config.to_prepare do
18
+ Lato::User.class_eval do
19
+ # Role options for the lato_cms_admin_role permission.
20
+ # Returns [[label, value], ...] with labels resolved at call time.
21
+ def self.lato_cms_admin_role_options
22
+ LatoCms.config.admin_roles.map do |key, value|
23
+ [I18n.t("lato_cms.admin_roles.#{key}"), value]
24
+ end
25
+ end
26
+
27
+ # True when the user can access the CMS section (operator or admin).
28
+ def lato_cms_access?
29
+ lato_cms_admin_role.to_i.positive?
30
+ end
31
+
32
+ # True when the user has the admin role: full page management
33
+ # (create, update, delete) and translation links.
34
+ def lato_cms_admin?
35
+ lato_cms_admin_role.to_i >= LatoCms.config.admin_roles.fetch(:admin, 0)
36
+ end
37
+ end
38
+ end
12
39
  end
13
40
  end
@@ -1,3 +1,3 @@
1
1
  module LatoCms
2
- VERSION = "3.0.6"
2
+ VERSION = "3.0.8"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lato_cms
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.6
4
+ version: 3.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gregorio Galante
@@ -148,6 +148,7 @@ files:
148
148
  - db/migrate/20260320070819_create_lato_cms_pages.rb
149
149
  - db/migrate/20260323171241_create_lato_cms_page_fields.rb
150
150
  - db/migrate/20260705000000_add_translation_group_id_to_lato_cms_pages.rb
151
+ - db/migrate/20260712092241_change_lato_cms_admin_to_lato_cms_admin_role_on_lato_user.rb
151
152
  - lib/lato_cms.rb
152
153
  - lib/lato_cms/config.rb
153
154
  - lib/lato_cms/engine.rb