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 +4 -4
- data/app/assets/javascripts/lato_cms/controllers/lato_cms_advanced_editor_controller.js +12 -32
- data/app/assets/javascripts/lato_cms/controllers/lato_cms_page_preview_controller.js +64 -1
- data/app/assets/stylesheets/lato_cms/application.scss +49 -2
- data/app/controllers/lato_cms/application_controller.rb +18 -3
- data/app/controllers/lato_cms/pages_controller.rb +10 -0
- data/app/views/lato_cms/pages/index.html.erb +2 -2
- data/app/views/lato_cms/pages/show.html.erb +63 -21
- data/config/locales/en.yml +15 -1
- data/config/locales/it.yml +15 -1
- data/db/migrate/20260712092241_change_lato_cms_admin_to_lato_cms_admin_role_on_lato_user.rb +18 -0
- data/lib/lato_cms/config.rb +8 -1
- data/lib/lato_cms/engine.rb +27 -0
- data/lib/lato_cms/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 84d12b9402630a14e022073320e2be275b41d57ae6877c25d4fa9a7be933b05f
|
|
4
|
+
data.tar.gz: 02536eb6c44e39de36bf0f76ea01c6736dfa9f9ed8ba87df043ae61fcd162678
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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", "
|
|
4
|
+
static targets = ["row", "editorCol", "reopenBtn"]
|
|
5
|
+
static values = { listPath: String }
|
|
5
6
|
|
|
6
|
-
isActive = false
|
|
7
7
|
isSidebarOpen = true
|
|
8
8
|
|
|
9
|
-
// ───
|
|
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
|
-
|
|
23
|
-
this.
|
|
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
|
-
|
|
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
|
-
|
|
29
|
-
|
|
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 :
|
|
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
|
-
|
|
21
|
-
|
|
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"
|
|
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-
|
|
14
|
-
<
|
|
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
|
-
|
|
24
|
-
|
|
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:
|
|
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
|
|
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
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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
|
-
|
|
63
|
-
|
|
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
|
-
|
|
70
|
-
|
|
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? %>
|
data/config/locales/en.yml
CHANGED
|
@@ -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."
|
data/config/locales/it.yml
CHANGED
|
@@ -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
|
data/lib/lato_cms/config.rb
CHANGED
|
@@ -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
|
data/lib/lato_cms/engine.rb
CHANGED
|
@@ -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
|
data/lib/lato_cms/version.rb
CHANGED
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.
|
|
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
|