Skip to content

Commit 1689b81

Browse files
committed
feat: add a protection mode for mirrored section
1 parent 2eae0f9 commit 1689b81

File tree

13 files changed

+133
-17
lines changed

13 files changed

+133
-17
lines changed

app/frontend/editor/components/section-pane/index.vue

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
</template>
1212

1313
<script>
14+
import { mapGetters } from 'vuex'
1415
import SettingList from './setting-list.vue'
1516
import BlockList from './block-list/index.vue'
1617
import BlockTree from './block-tree/index.vue'
@@ -21,26 +22,27 @@ export default {
2122
settingId: { type: String, default: undefined },
2223
},
2324
computed: {
25+
...mapGetters(['isMirroredSection', 'isMirroredSectionEditable']),
2426
unfilteredTabs() {
2527
return [
2628
{
2729
name: this.$t('sectionPane.tabs.settings'),
2830
tab: SettingList,
2931
type: 'content',
30-
condition: () => this.hasSettings,
32+
condition: () => this.displaySettings
3133
},
3234
{
3335
name: this.blocksLabel,
3436
tab: this.blocksComponent,
3537
type: 'blocks',
36-
condition: () => this.hasBlocks,
38+
condition: () => this.displayBlocks
3739
},
3840
{
3941
name: this.$t('sectionPane.tabs.advanced'),
4042
tab: SettingList,
4143
type: 'advanced',
42-
condition: () => this.hasAdvancedSettings || this.hasMirrorFeatureEnabled,
43-
props: () => ({ advanced: true, mirrorFeature: this.hasMirrorFeatureEnabled }),
44+
condition: () => this.hasAdvancedSettings || this.isMirroredSection,
45+
props: () => ({ advanced: true, mirrorFeature: this.isMirroredSection }),
4446
},
4547
]
4648
},
@@ -52,15 +54,18 @@ export default {
5254
tabIndexFromRoute() {
5355
return this.findTabIndexFromRoute()
5456
},
57+
displaySettings() {
58+
return this.hasSettings && (!this.isMirroredSection || this.isMirroredSectionEditable)
59+
},
60+
displayBlocks() {
61+
return this.hasBlocks && (!this.isMirroredSection || this.isMirroredSectionEditable)
62+
},
5563
hasSettings() {
5664
return !this.isBlank(this.currentSectionSettings)
5765
},
5866
hasAdvancedSettings() {
5967
return !this.isBlank(this.currentSectionAdvancedSettings)
6068
},
61-
hasMirrorFeatureEnabled() {
62-
return !this.isBlank(this.currentSection.mirrorOf)
63-
},
6469
hasBlocks() {
6570
return !this.isBlank(this.currentSectionDefinition.blocks)
6671
},

app/frontend/editor/components/section-pane/mirror-input.vue

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
<template>
2-
<div>
2+
<div class="space-y-6">
3+
<div v-if="!isMirroredSectionEditable" class="bg-gray-100 p-4 rounded-sm">
4+
<h3 class="font-medium text-gray-900 text-center">{{ $t('mirrorSectionSetup.protectedMessage.title') }}</h3>
5+
<p class="mt-1 text-sm text-gray-600 text-center">{{ $t('mirrorSectionSetup.protectedMessage.message') }}</p>
6+
</div>
7+
38
<uikit-checkbox-input
49
:label="$t('mirrorSectionSetup.inputLabel')"
510
:placeholder="placeholder"
@@ -10,7 +15,7 @@
1015
</template>
1116

1217
<script>
13-
import { mapActions } from 'vuex'
18+
import { mapActions, mapGetters } from 'vuex'
1419
1520
export default {
1621
name: 'MirrorSectionInput',
@@ -22,6 +27,7 @@ export default {
2227
this.mirrorSectionEnabled = this.currentSection?.mirrorOf?.enabled
2328
},
2429
computed: {
30+
...mapGetters(['isMirroredSectionEditable']),
2531
mirrorOf() {
2632
return this.currentSection?.mirrorOf
2733
},

app/frontend/editor/locales/editor.ar.json

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,5 +260,32 @@
260260
}
261261
}
262262
}
263+
},
264+
"mirrorSectionSetup": {
265+
"inputLabel": "تفعيل نسخ القسم",
266+
"addButton": "...أو أضف قسماً منعكساً",
267+
"tooltip": "هذا القسم تم نسخه من \"%{pageTitle}\".<br/>سيتم تطبيق التغييرات التي تقوم بها هنا على جميع الصفحات التي تستخدم هذا القسم.",
268+
"title": "إعداد نسخ القسم",
269+
"errorMessage": "عذرًا! لا يمكنك نسخ هذا القسم. إما أنه موجود بالفعل في هذه الصفحة أو أنه يأتي من نفس الصفحة التي تقوم بتحريرها.",
270+
"protectedMessage": {
271+
"title": "هذا القسم محمي",
272+
"message": "لتعديل محتواه، اذهب إلى الصفحة الأصلية حيث تم إنشاؤه."
273+
},
274+
"confirmButton": "إعداد",
275+
"cancelButton": "إلغاء",
276+
"page": {
277+
"name": "صفحة",
278+
"input": {
279+
"label": "صفحة",
280+
"placeholder": "اختر صفحة",
281+
"searchPlaceholder": "بحث...",
282+
"emptyLabel": "لم يتم العثور على صفحات"
283+
},
284+
"sectionInput": {
285+
"label": "قسم",
286+
"placeholder": "اختر قسماً",
287+
"emptyLabel": "لم يتم اختيار أي قسم"
288+
}
289+
}
263290
}
264291
}

app/frontend/editor/locales/editor.en.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,10 @@
186186
"tooltip": "This section is mirrored from the \"%{pageTitle}\".<br/>Changes made here will reflect across all pages using this section",
187187
"title": "Setup mirror section",
188188
"errorMessage": "Oops! You can’t mirror this section. It’s either already mirrored on this page, or it comes from the same page you're editing.",
189+
"protectedMessage": {
190+
"title": "This section is protected",
191+
"message": "To edit its content, go to the original page where it was created."
192+
},
189193
"confirmButton": "Setup",
190194
"cancelButton": "Cancel",
191195
"page": {

app/frontend/editor/locales/editor.es.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,10 @@
186186
"tooltip": "Esta sección está reflejada desde \"%{pageTitle}\".<br/>Los cambios realizados aquí se aplicarán en todas las páginas que usen esta sección",
187187
"title": "Configurar sección reflejada",
188188
"errorMessage": "¡Ups! No puedes reflejar esta sección. Ya está reflejada en esta página o proviene de la misma página que estás editando.",
189+
"protectedMessage": {
190+
"title": "Esta sección está protegida",
191+
"message": "Para editar su contenido, ve a la página original donde fue creada."
192+
},
189193
"confirmButton": "Configurar",
190194
"cancelButton": "Cancelar",
191195
"page": {

app/frontend/editor/locales/editor.fr.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,10 @@
185185
"tooltip": "Cette section est en miroir depuis \"%{pageTitle}\".<br/>Les modifications apportées ici seront répercutées sur toutes les pages utilisant cette section",
186186
"title": "Configurer la section en miroir",
187187
"errorMessage": "Oups ! Vous ne pouvez pas mettre cette section en miroir. Elle est déjà présente sur cette page ou provient de la page que vous êtes en train de modifier.",
188+
"protectedMessage": {
189+
"title": "Cette section est protégée",
190+
"message": "Pour modifier son contenu, allez sur la page d'origine où elle a été créée."
191+
},
188192
"confirmButton": "Configurer",
189193
"cancelButton": "Annuler",
190194
"page": {

app/frontend/editor/locales/editor.pt-BR.json

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,33 @@
179179
"title": "Ícones",
180180
"pickerTitle": "Escolher um ícone"
181181
},
182+
"mirrorSectionSetup": {
183+
"inputLabel": "Ativar espelhamento de seção",
184+
"addButton": "...ou adicionar uma seção espelhada",
185+
"tooltip": "Esta seção é espelhada da \"%{pageTitle}\".<br/>As alterações feitas aqui serão refletidas em todas as páginas que usam esta seção.",
186+
"title": "Configurar espelhamento de seção",
187+
"errorMessage": "Ops! Você não pode espelhar esta seção. Ela já está espelhada nesta página ou pertence à mesma página que você está editando.",
188+
"protectedMessage": {
189+
"title": "Esta seção está protegida",
190+
"message": "Para editar seu conteúdo, vá para a página original onde ela foi criada."
191+
},
192+
"confirmButton": "Configurar",
193+
"cancelButton": "Cancelar",
194+
"page": {
195+
"name": "Página",
196+
"input": {
197+
"label": "Página",
198+
"placeholder": "Selecione uma página",
199+
"searchPlaceholder": "Pesquisar...",
200+
"emptyLabel": "Nenhuma página encontrada"
201+
},
202+
"sectionInput": {
203+
"label": "Seção",
204+
"placeholder": "Selecione uma seção",
205+
"emptyLabel": "Nenhuma seção selecionada"
206+
}
207+
}
208+
},
182209
"linkInput": {
183210
"placeholder": "Clique aqui para selecionar um link",
184211
"withNestedTextLabel": "Ativar texto",

app/frontend/editor/store/getters.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,11 +183,17 @@ export default (services) => ({
183183
const categories = categoriesByLayoutGroupId(layoutGroupId)
184184
return categories.some(({ children }) => children.length > 0)
185185
},
186-
canAddMirroredSection: ({ theme, oneSinglePage }, { layoutGroupDefinition }) =>
186+
canAddMirroredSection: ({ theme, oneSinglePage }, { layoutGroupDefinition }) =>
187187
(layoutGroupId) => {
188188
const layoutGroup = layoutGroupDefinition(layoutGroupId)
189189
return theme.mirrorSection && layoutGroup.mirrorSection !== false && services.section.canAddMirroredSection({
190190
hasOneSinglePage: oneSinglePage
191191
})
192192
},
193+
isMirroredSection: ({ section }) => {
194+
return !isBlank(section.mirrorOf)
195+
},
196+
isMirroredSectionEditable: ({ theme, section, page }, {}) => {
197+
return theme.mirrorSection === true || (theme.mirrorSection === 'protected' && section.mirrorOf?.pageId === page.id)
198+
}
193199
})

app/frontend/editor/views/content-pane.vue

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
</template>
5050

5151
<script>
52+
import { mapGetters } from 'vuex'
5253
import Layout from '@/layouts/slide-pane.vue'
5354
import SectionPane from '@/components/section-pane/index.vue'
5455
import SectionBlockPane from '@/components/section-block-pane/index.vue'
@@ -62,6 +63,7 @@ export default {
6263
settingId: { type: String, default: undefined },
6364
},
6465
computed: {
66+
...mapGetters(['isMirroredSection', 'isMirroredSectionEditable']),
6567
title() {
6668
if (this.isSectionReady) return this.sectionTitle
6769
else if (this.isSectionBlockReady) return this.sectionBlockTitle
@@ -117,6 +119,11 @@ export default {
117119
if (this.sectionBlockId) await this.fetchSectionBlock(this.sectionBlockId)
118120
else if (this.sectionId) await this.fetchSection(this.sectionId)
119121
122+
if (this.isMirroredSection && !this.isMirroredSectionEditable && this.sectionBlockId) {
123+
this.$router.push({ name: 'editSection', params: { sectionId: this.currentSection.id } })
124+
return
125+
}
126+
120127
if (!this.currentSection && !this.currentSectionBlock)
121128
this.$router.push({ name: 'editPage' })
122129
},

app/services/concerns/maglev/mirrored_sections_concern.rb

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@ module MirroredSectionsConcern
99

1010
def persist_mirrored_sections(sections_content)
1111
sections_content.map { |group| group['sections'] }.flatten.compact.find do |section|
12-
next unless section.dig('mirror_of', 'enabled')
12+
next unless can_persist_mirrored_section?(section)
1313

14-
persist_mirror_section(section.except('mirror_of'), section['mirror_of'])
14+
persist_mirrored_section(section.except('mirror_of'), section['mirror_of'])
1515
end
1616
end
1717

18-
def persist_mirror_section(section, mirror_of)
18+
def persist_mirrored_section(section, mirror_of)
1919
store = find_store_from_mirrored_section(mirror_of)
2020
mirror_section = store.update_section_content(mirror_of['section_id'], section)
2121
store.save
@@ -25,7 +25,7 @@ def persist_mirror_section(section, mirror_of)
2525

2626
# No need to detect a circular dependency because this is impossible
2727
# to change the mirror_of attributes of an existing section in the editor
28-
persist_mirror_section(mirror_section.except('mirror_of'), mirror_section['mirror_of'])
28+
persist_mirrored_section(mirror_section.except('mirror_of'), mirror_section['mirror_of'])
2929
end
3030

3131
def replace_content_from_mirror_sections(store)
@@ -56,5 +56,12 @@ def find_section_from_mirrored_section(mirror_of)
5656

5757
store.find_section(mirror_of['section_id'])
5858
end
59+
60+
def can_persist_mirrored_section?(section)
61+
section.dig('mirror_of', 'enabled') && (
62+
theme.mirror_section == true ||
63+
(theme.mirror_section == 'protected' && section.dig('mirror_of', 'page_id') == page.id)
64+
)
65+
end
5966
end
6067
end

0 commit comments

Comments
 (0)