maglevcms 3.0.0.beta3 → 3.0.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/README.md +16 -53
- data/Rakefile +3 -1
- data/app/assets/builds/maglev/tailwind.css +424 -84
- data/app/assets/config/maglev_manifest.js +3 -2
- data/app/assets/javascripts/maglev/client/dom-operations.js +5 -5
- data/app/assets/javascripts/maglev/client/iframe-decorator.js +24 -0
- data/app/assets/javascripts/maglev/client/incoming-messages.js +13 -3
- data/app/assets/javascripts/maglev/client/index.js +3 -2
- data/app/assets/javascripts/maglev/client/utils.js +22 -0
- data/app/assets/javascripts/maglev/editor/controllers/app/forms/section_form_controller.js +4 -3
- data/app/assets/javascripts/maglev/editor/controllers/app/forms/style_form_controller.js +2 -1
- data/app/assets/javascripts/maglev/editor/controllers/app/page_preview_controller.js +96 -5
- data/app/assets/javascripts/maglev/editor/controllers/app/preview_notification_center_controller.js +105 -23
- data/app/assets/javascripts/maglev/editor/controllers/app/setting_controller.js +3 -2
- data/app/assets/javascripts/maglev/editor/controllers/shared/copy_to_clipboard_controller.js +2 -1
- data/app/assets/javascripts/maglev/editor/controllers/utils.js +22 -0
- data/app/assets/javascripts/maglev/editor/index.js +2 -1
- data/app/assets/javascripts/maglev/editor/patches/turbo_stream_patch.js +3 -3
- data/app/assets/stylesheets/maglev/tailwind.css.erb +8 -1
- data/app/components/maglev/content/link.rb +1 -1
- data/app/components/maglev/editor/settings/link/link_component.rb +7 -1
- data/app/components/maglev/section_component.rb +11 -1
- data/app/components/maglev/uikit/app_layout/sidebar/link_component.html.erb +1 -1
- data/app/components/maglev/uikit/app_layout/sidebar/link_component.rb +35 -5
- data/app/components/maglev/uikit/app_layout/sidebar_component.html.erb +3 -4
- data/app/components/maglev/uikit/app_layout/topbar_component.html.erb +1 -1
- data/app/components/maglev/uikit/app_layout/topbar_component.rb +1 -1
- data/app/components/maglev/uikit/button_group_component/button_group_component.html.erb +5 -0
- data/app/components/maglev/uikit/button_group_component.rb +70 -0
- data/app/components/maglev/uikit/device_toggler_component.rb +10 -1
- data/app/components/maglev/uikit/dropdown_component/dropdown_component.html.erb +2 -2
- data/app/components/maglev/uikit/dropdown_component.rb +6 -1
- data/app/components/maglev/uikit/form/color_field_component.html.erb +1 -1
- data/app/components/maglev/uikit/form/combobox_component.html.erb +1 -0
- data/app/components/maglev/uikit/form/link_component.rb +5 -1
- data/app/components/maglev/uikit/form/richtext_controller.js +5 -4
- data/app/components/maglev/uikit/form/search_form_component.html.erb +1 -0
- data/app/components/maglev/uikit/icon_component.rb +3 -0
- data/app/components/maglev/uikit/image_library/uploader_controller.js +3 -2
- data/app/components/maglev/uikit/list/list_item_component.html.erb +36 -19
- data/app/components/maglev/uikit/list/list_item_component.rb +19 -5
- data/app/components/maglev/uikit/locale_switcher_component/locale_switcher_component.html.erb +6 -10
- data/app/components/maglev/uikit/menu_dropdown_component/menu_dropdown_component.html.erb +6 -2
- data/app/components/maglev/uikit/menu_dropdown_component.rb +244 -7
- data/app/components/maglev/uikit/page_actions_dropdown_component/page_actions_dropdown_component.html.erb +39 -46
- data/app/components/maglev/uikit/pagination_component/pagination_component.html.erb +9 -12
- data/app/components/maglev/uikit/pagination_component.rb +6 -1
- data/app/components/maglev/uikit/section_toolbar/bottom_component.html.erb +1 -1
- data/app/components/maglev/uikit/tabs_component/tabs_component.html.erb +7 -4
- data/app/components/maglev/uikit/tabs_component.rb +23 -4
- data/app/components/maglev/uikit/well/simple_well_component.html.erb +15 -0
- data/app/components/maglev/uikit/well/simple_well_component.rb +13 -0
- data/app/controllers/concerns/maglev/editor/preview_urls_concern.rb +32 -0
- data/app/controllers/concerns/maglev/editor/turbo_concern.rb +29 -0
- data/app/controllers/concerns/maglev/flash_i18n_concern.rb +1 -0
- data/app/controllers/maglev/application_controller.rb +1 -1
- data/app/controllers/maglev/assets/active_storage_proxy_controller.rb +2 -1
- data/app/controllers/maglev/editor/assets_controller.rb +1 -1
- data/app/controllers/maglev/editor/base_controller.rb +6 -32
- data/app/controllers/maglev/editor/pages/clone_controller.rb +22 -0
- data/app/controllers/maglev/editor/pages/discard_draft_controller.rb +17 -0
- data/app/controllers/maglev/editor/pages_controller.rb +26 -7
- data/app/controllers/maglev/editor/section_blocks_controller.rb +13 -9
- data/app/controllers/maglev/editor/sections_controller.rb +26 -7
- data/app/controllers/maglev/published_page_preview_controller.rb +4 -0
- data/app/helpers/maglev/application_helper.rb +6 -6
- data/app/helpers/maglev/editor/section_blocks_helper.rb +2 -2
- data/app/models/maglev/page/publishable_concern.rb +69 -0
- data/app/models/maglev/page.rb +2 -13
- data/app/models/maglev/section/block.rb +4 -0
- data/app/models/maglev/section/content_concern.rb +3 -1
- data/app/models/maglev/section.rb +21 -1
- data/app/models/maglev/sections_content_store.rb +1 -3
- data/app/services/concerns/maglev/content/helpers_concern.rb +5 -8
- data/app/services/maglev/app_container.rb +4 -2
- data/app/services/maglev/discard_page_draft_service.rb +45 -0
- data/app/services/maglev/fetch_section_screenshot_url.rb +12 -1
- data/app/services/maglev/has_unpublished_changes.rb +21 -0
- data/app/services/maglev/publish_service.rb +15 -2
- data/app/views/layouts/maglev/editor/_sidebar.html.erb +6 -1
- data/app/views/layouts/maglev/editor/application.html.erb +5 -0
- data/app/views/layouts/maglev/editor/topbar/_page_info.html.erb +1 -1
- data/app/views/layouts/maglev/editor/topbar/_publish_button.html.erb +32 -10
- data/app/views/maglev/editor/assets/index.html.erb +1 -0
- data/app/views/maglev/editor/home/index.html.erb +1 -1
- data/app/views/maglev/editor/links/edit/_email.html.erb +1 -1
- data/app/views/maglev/editor/links/edit/_url.html.erb +1 -1
- data/app/views/maglev/editor/pages/_list.html.erb +25 -21
- data/app/views/maglev/editor/pages/_preview.html.erb +6 -6
- data/app/views/maglev/editor/pages/_preview_empty_message.html.erb +13 -10
- data/app/views/maglev/editor/pages/discard_draft/create.turbo_stream.erb +16 -0
- data/app/views/maglev/editor/pages/index.html.erb +8 -1
- data/app/views/maglev/editor/section_blocks/_form.html.erb +5 -13
- data/app/views/maglev/editor/section_blocks/_form_with_tabs.html.erb +15 -0
- data/app/views/maglev/editor/section_blocks/_new.html.erb +1 -1
- data/app/views/maglev/editor/section_blocks/edit.html.erb +2 -2
- data/app/views/maglev/editor/section_blocks/index/_list.html.erb +2 -2
- data/app/views/maglev/editor/section_blocks/index/_tree.html.erb +1 -1
- data/app/views/maglev/editor/section_blocks/update.turbo_stream.erb +1 -1
- data/app/views/maglev/editor/sections/_form.html.erb +6 -20
- data/app/views/maglev/editor/sections/_form_with_tabs.html.erb +21 -0
- data/app/views/maglev/editor/sections/_list.html.erb +1 -1
- data/app/views/maglev/editor/sections/edit.html.erb +3 -3
- data/app/views/maglev/editor/sections/index.html.erb +1 -1
- data/app/views/maglev/editor/sections/new.html.erb +18 -1
- data/app/views/maglev/editor/sections/theme/_empty_list.html.erb +3 -0
- data/app/views/maglev/editor/sections/theme/_list.html.erb +35 -0
- data/app/views/maglev/editor/sections/theme/_screenshot_placeholder.html.erb +6 -0
- data/app/views/maglev/editor/sections/theme/_search.html.erb +22 -0
- data/app/views/maglev/editor/sections/update.turbo_stream.erb +1 -1
- data/app/views/maglev/editor/shared/_button_label.html.erb +4 -4
- data/app/views/maglev/editor/style/edit.html.erb +1 -0
- data/config/editor_importmap.rb +13 -13
- data/config/locales/editor.ar.yml +12 -4
- data/config/locales/editor.en.yml +31 -23
- data/config/locales/editor.es.yml +12 -4
- data/config/locales/editor.fr.yml +12 -4
- data/config/locales/editor.pt-BR.yml +12 -4
- data/config/routes/maglev/assets.rb +4 -0
- data/config/routes/maglev/editor.rb +38 -0
- data/config/routes/maglev/preview.rb +8 -0
- data/config/routes/maglev/public_preview.rb +6 -0
- data/config/routes.rb +8 -47
- data/db/migrate/20211013210954_translate_section_content.rb +1 -0
- data/db/migrate/20260114112058_add_published_payload_to_pages.rb +14 -0
- data/exe/tailwind-cli +1 -1
- data/lib/generators/maglev/install_generator.rb +9 -7
- data/lib/generators/maglev/templates/install/config/initializers/maglev.rb +10 -3
- data/lib/maglev/active_storage/serving_blob.rb +29 -0
- data/lib/maglev/active_storage.rb +2 -0
- data/lib/maglev/config.rb +22 -3
- data/lib/maglev/engine.rb +14 -10
- data/lib/maglev/version.rb +1 -1
- data/lib/maglev.rb +18 -3
- data/lib/tasks/db_test_all.rake +290 -0
- metadata +46 -19
- data/app/controllers/maglev/editor/page_clone_controller.rb +0 -20
- data/app/views/maglev/editor/sections/_theme_list.html.erb +0 -32
- /data/vendor/javascript/{@floating-ui--core.js → maglev/@floating-ui--core.js} +0 -0
- /data/vendor/javascript/{@floating-ui--dom.js → maglev/@floating-ui--dom.js} +0 -0
- /data/vendor/javascript/{@floating-ui--utils--dom.js → maglev/@floating-ui--utils--dom.js} +0 -0
- /data/vendor/javascript/{@floating-ui--utils.js → maglev/@floating-ui--utils.js} +0 -0
- /data/vendor/javascript/{@hotwired--stimulus.js → maglev/@hotwired--stimulus.js} +0 -0
- /data/vendor/javascript/{@hotwired--turbo-rails.js → maglev/@hotwired--turbo-rails.js} +0 -0
- /data/vendor/javascript/{@hotwired--turbo.js → maglev/@hotwired--turbo.js} +0 -0
- /data/vendor/javascript/{@rails--actioncable--src.js → maglev/@rails--actioncable--src.js} +0 -0
- /data/vendor/javascript/{@rails--request.js.js → maglev/@rails--request.js.js} +0 -0
- /data/vendor/javascript/{@shopify--draggable.js → maglev/@shopify--draggable.js} +0 -0
- /data/vendor/javascript/{el-transition.js → maglev/el-transition.js} +0 -0
- /data/vendor/javascript/{stimulus-use.js → maglev/stimulus-use.js} +0 -0
- /data/vendor/javascript/{tiptap.bundle.js → maglev/tiptap.bundle.js} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Maglev
|
|
4
|
-
class ApplicationController <
|
|
4
|
+
class ApplicationController < Maglev.parent_controller_class
|
|
5
5
|
include Maglev::ServicesConcern
|
|
6
6
|
include Maglev::ResourceIdConcern
|
|
7
7
|
include Maglev::ErrorsConcern
|
|
@@ -8,7 +8,8 @@ module Maglev
|
|
|
8
8
|
private
|
|
9
9
|
|
|
10
10
|
def set_blob
|
|
11
|
-
|
|
11
|
+
blob = Maglev::Asset.find(resource_id).file.blob
|
|
12
|
+
@blob = Maglev::ActiveStorage::ServingBlob.new(blob)
|
|
12
13
|
rescue ActiveRecord::RecordNotFound
|
|
13
14
|
head :not_found
|
|
14
15
|
end
|
|
@@ -13,6 +13,8 @@ module Maglev
|
|
|
13
13
|
include Maglev::ServicesConcern
|
|
14
14
|
include Maglev::FlashI18nConcern
|
|
15
15
|
include Maglev::Editor::ErrorsConcern
|
|
16
|
+
include Maglev::Editor::TurboConcern
|
|
17
|
+
include Maglev::Editor::PreviewUrlsConcern
|
|
16
18
|
|
|
17
19
|
before_action :fetch_maglev_site
|
|
18
20
|
before_action :fetch_maglev_page
|
|
@@ -20,9 +22,8 @@ module Maglev
|
|
|
20
22
|
|
|
21
23
|
helper Maglev::ApplicationHelper
|
|
22
24
|
helper_method :maglev_site, :maglev_theme,
|
|
23
|
-
:current_maglev_page, :current_maglev_sections,
|
|
24
|
-
:maglev_editing_route_context, :
|
|
25
|
-
:maglev_page_live_url, :maglev_page_preview_url
|
|
25
|
+
:current_maglev_page, :current_maglev_sections,
|
|
26
|
+
:maglev_editing_route_context, :unpublished_changes?
|
|
26
27
|
|
|
27
28
|
private
|
|
28
29
|
|
|
@@ -61,21 +62,8 @@ module Maglev
|
|
|
61
62
|
)
|
|
62
63
|
end
|
|
63
64
|
|
|
64
|
-
def
|
|
65
|
-
|
|
66
|
-
path: maglev_services.get_page_fullpath.call(page: current_maglev_page, preview_mode: false,
|
|
67
|
-
locale: content_locale),
|
|
68
|
-
preview: maglev_page_preview_url(current_maglev_page),
|
|
69
|
-
live: maglev_page_live_url(current_maglev_page)
|
|
70
|
-
}
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
def maglev_page_live_url(page)
|
|
74
|
-
maglev_services.get_page_fullpath.call(page: page, preview_mode: false, locale: content_locale)
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
def maglev_page_preview_url(page)
|
|
78
|
-
maglev_services.get_page_fullpath.call(page: page, preview_mode: true, locale: content_locale)
|
|
65
|
+
def unpublished_changes?
|
|
66
|
+
maglev_services.has_unpublished_changes.call(site: maglev_site, page: current_maglev_page, theme: maglev_theme)
|
|
79
67
|
end
|
|
80
68
|
|
|
81
69
|
def maglev_theme
|
|
@@ -89,20 +77,6 @@ module Maglev
|
|
|
89
77
|
}.compact_blank
|
|
90
78
|
end
|
|
91
79
|
|
|
92
|
-
def maglev_disable_turbo_cache
|
|
93
|
-
@maglev_disable_turbo_cache = true
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
def maglev_disable_turbo_cache?
|
|
97
|
-
!!@maglev_disable_turbo_cache
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
def ensure_turbo_frame_request
|
|
101
|
-
return if turbo_frame_request?
|
|
102
|
-
|
|
103
|
-
redirect_to editor_root_path
|
|
104
|
-
end
|
|
105
|
-
|
|
106
80
|
def redirect_to_real_root
|
|
107
81
|
redirect_to editor_real_root_path(maglev_editing_route_context)
|
|
108
82
|
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Maglev
|
|
4
|
+
module Editor
|
|
5
|
+
module Pages
|
|
6
|
+
class CloneController < Maglev::Editor::BaseController
|
|
7
|
+
def create
|
|
8
|
+
@source_page = maglev_page_resources.find(params[:id])
|
|
9
|
+
@page = clone_page(@source_page)
|
|
10
|
+
edit_cloned_page_path = edit_editor_page_path(@page, maglev_editing_route_context(page: @page))
|
|
11
|
+
redirect_to edit_cloned_page_path, notice: flash_t(:success), status: :see_other
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
private
|
|
15
|
+
|
|
16
|
+
def clone_page(page)
|
|
17
|
+
services.clone_page.call(page: page)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Maglev
|
|
4
|
+
module Editor
|
|
5
|
+
module Pages
|
|
6
|
+
class DiscardDraftController < Maglev::Editor::BaseController
|
|
7
|
+
def create
|
|
8
|
+
page = maglev_page_resources.find(params[:id])
|
|
9
|
+
services.discard_page_draft.call(
|
|
10
|
+
site: maglev_site,
|
|
11
|
+
page: page
|
|
12
|
+
)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -3,16 +3,16 @@
|
|
|
3
3
|
module Maglev
|
|
4
4
|
module Editor
|
|
5
5
|
class PagesController < Maglev::Editor::BaseController
|
|
6
|
+
include ::Pagy::Backend
|
|
7
|
+
|
|
6
8
|
before_action :set_page, only: %i[edit update destroy]
|
|
7
9
|
before_action :maglev_disable_turbo_cache, only: %i[edit update new create]
|
|
8
10
|
|
|
9
11
|
helper_method :query_params
|
|
10
12
|
|
|
11
13
|
def index
|
|
12
|
-
@pages =
|
|
13
|
-
|
|
14
|
-
with_static_pages: false,
|
|
15
|
-
index_first: true)
|
|
14
|
+
@pages = fetch_pages
|
|
15
|
+
@pagy, @pages = pagy(@pages, limit: per_page, page_param: 'offset') if pagination_enabled?
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
def new
|
|
@@ -58,6 +58,10 @@ module Maglev
|
|
|
58
58
|
@page = maglev_page_resources.find(params[:id])
|
|
59
59
|
end
|
|
60
60
|
|
|
61
|
+
def build_page_resource
|
|
62
|
+
maglev_page_resources.build(page_params)
|
|
63
|
+
end
|
|
64
|
+
|
|
61
65
|
def page_params
|
|
62
66
|
params.require(:page).permit(:title, :path,
|
|
63
67
|
:seo_title, :meta_description,
|
|
@@ -66,11 +70,26 @@ module Maglev
|
|
|
66
70
|
end
|
|
67
71
|
|
|
68
72
|
def query_params(from_list: false)
|
|
69
|
-
{ q: params[:q], from_list: params[:from_list] || from_list }
|
|
73
|
+
base = { q: params[:q], from_list: params[:from_list] || from_list }
|
|
74
|
+
(pagination_enabled? ? base.merge(offset: params[:offset]) : base).compact_blank
|
|
70
75
|
end
|
|
71
76
|
|
|
72
|
-
def
|
|
73
|
-
|
|
77
|
+
def fetch_pages
|
|
78
|
+
services.search_pages.call(
|
|
79
|
+
q: params[:q],
|
|
80
|
+
content_locale: content_locale,
|
|
81
|
+
default_locale: default_content_locale,
|
|
82
|
+
with_static_pages: false,
|
|
83
|
+
index_first: true
|
|
84
|
+
)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def pagination_enabled?
|
|
88
|
+
maglev_config.pagination?(:pages)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def per_page
|
|
92
|
+
maglev_config.per_page(:pages)
|
|
74
93
|
end
|
|
75
94
|
end
|
|
76
95
|
end
|
|
@@ -4,6 +4,7 @@ module Maglev
|
|
|
4
4
|
module Editor
|
|
5
5
|
class SectionBlocksController < Maglev::Editor::BaseController
|
|
6
6
|
helper Maglev::Editor::SettingsHelper
|
|
7
|
+
helper_method :source_lock_version
|
|
7
8
|
|
|
8
9
|
before_action :set_section
|
|
9
10
|
before_action :set_section_block, only: %i[edit update destroy]
|
|
@@ -31,7 +32,6 @@ module Maglev
|
|
|
31
32
|
|
|
32
33
|
def update
|
|
33
34
|
update_section_block
|
|
34
|
-
refresh_lock_version
|
|
35
35
|
flash.now[:notice] = flash_t(:success)
|
|
36
36
|
end
|
|
37
37
|
|
|
@@ -59,12 +59,12 @@ module Maglev
|
|
|
59
59
|
|
|
60
60
|
def set_section
|
|
61
61
|
@section = current_maglev_sections.find { |section| section.id == params[:section_id] }
|
|
62
|
-
|
|
62
|
+
redirect_to editor_sections_path_with_context unless @section
|
|
63
63
|
end
|
|
64
64
|
|
|
65
65
|
def set_section_block
|
|
66
66
|
@section_block = @section.blocks.find(params[:id])
|
|
67
|
-
|
|
67
|
+
redirect_to editor_sections_path_with_context unless @section_block
|
|
68
68
|
end
|
|
69
69
|
|
|
70
70
|
def update_section_block
|
|
@@ -77,12 +77,12 @@ module Maglev
|
|
|
77
77
|
)
|
|
78
78
|
end
|
|
79
79
|
|
|
80
|
-
def
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
80
|
+
def lock_source
|
|
81
|
+
@section.site_scoped? ? maglev_site : current_maglev_page
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def source_lock_version
|
|
85
|
+
lock_source.lock_version || 0
|
|
86
86
|
end
|
|
87
87
|
|
|
88
88
|
def redirect_to_section_blocks_path(success: true)
|
|
@@ -96,6 +96,10 @@ module Maglev
|
|
|
96
96
|
|
|
97
97
|
redirect_to path, status: :see_other, **flash
|
|
98
98
|
end
|
|
99
|
+
|
|
100
|
+
def editor_sections_path_with_context
|
|
101
|
+
editor_sections_path(maglev_editing_route_context)
|
|
102
|
+
end
|
|
99
103
|
end
|
|
100
104
|
end
|
|
101
105
|
end
|
|
@@ -4,7 +4,9 @@ module Maglev
|
|
|
4
4
|
module Editor
|
|
5
5
|
class SectionsController < Maglev::Editor::BaseController
|
|
6
6
|
helper Maglev::Editor::SettingsHelper
|
|
7
|
+
helper_method :source_lock_version
|
|
7
8
|
|
|
9
|
+
before_action :ensure_turbo_frame_request, only: [:new]
|
|
8
10
|
before_action :set_section, only: %i[edit update]
|
|
9
11
|
|
|
10
12
|
def show
|
|
@@ -12,8 +14,11 @@ module Maglev
|
|
|
12
14
|
end
|
|
13
15
|
|
|
14
16
|
def new
|
|
15
|
-
|
|
17
|
+
set_query_and_category_id
|
|
16
18
|
@position = (params[:position] || -1).to_i
|
|
19
|
+
@theme_sections = maglev_theme.sections.filter(current_maglev_sections, keyword: @query,
|
|
20
|
+
category_id: @category_id)
|
|
21
|
+
render layout: false
|
|
17
22
|
end
|
|
18
23
|
|
|
19
24
|
def create
|
|
@@ -34,7 +39,6 @@ module Maglev
|
|
|
34
39
|
|
|
35
40
|
def update
|
|
36
41
|
update_section
|
|
37
|
-
refresh_lock_version
|
|
38
42
|
flash.now[:notice] = flash_t(:success)
|
|
39
43
|
end
|
|
40
44
|
|
|
@@ -56,7 +60,7 @@ module Maglev
|
|
|
56
60
|
|
|
57
61
|
def set_section
|
|
58
62
|
@section = current_maglev_sections.find { |section| section.id == params[:id] }
|
|
59
|
-
|
|
63
|
+
redirect_to editor_sections_path_with_context unless @section
|
|
60
64
|
end
|
|
61
65
|
|
|
62
66
|
def update_section
|
|
@@ -73,6 +77,14 @@ module Maglev
|
|
|
73
77
|
render 'index', status: :unprocessable_content
|
|
74
78
|
end
|
|
75
79
|
|
|
80
|
+
def set_query_and_category_id
|
|
81
|
+
# we can't filter by both query and category_id in the same time
|
|
82
|
+
@query = params[:category_id].present? ? nil : params[:query]
|
|
83
|
+
# if no category_id is provided AND we don't have a query, we take the first category
|
|
84
|
+
@category_id = params[:category_id] || maglev_theme.section_categories.first.id
|
|
85
|
+
@category_id = nil if @query.present?
|
|
86
|
+
end
|
|
87
|
+
|
|
76
88
|
def newly_added_section_to_flash
|
|
77
89
|
# use flash because we can't pass directly the information to the redirect
|
|
78
90
|
{ section_id: @section[:id], position: current_maglev_page.position_of_section(@section[:id]) }
|
|
@@ -83,13 +95,20 @@ module Maglev
|
|
|
83
95
|
headers['X-Section-Position'] = flash[:position]
|
|
84
96
|
end
|
|
85
97
|
|
|
86
|
-
def
|
|
87
|
-
|
|
88
|
-
|
|
98
|
+
def lock_source
|
|
99
|
+
@section.site_scoped? ? maglev_site : current_maglev_page
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def source_lock_version
|
|
103
|
+
lock_source.lock_version || 0
|
|
89
104
|
end
|
|
90
105
|
|
|
91
106
|
def redirect_to_sections_path
|
|
92
|
-
redirect_to
|
|
107
|
+
redirect_to editor_sections_path_with_context, notice: flash_t(:success), status: :see_other
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def editor_sections_path_with_context
|
|
111
|
+
editor_sections_path(maglev_editing_route_context)
|
|
93
112
|
end
|
|
94
113
|
end
|
|
95
114
|
end
|
|
@@ -13,6 +13,10 @@ module Maglev
|
|
|
13
13
|
helper Maglev::PagePreviewHelper
|
|
14
14
|
|
|
15
15
|
def index
|
|
16
|
+
# use the title + SEO informations from the published payload
|
|
17
|
+
# Warning: the page may not exist even in draft
|
|
18
|
+
maglev_page&.apply_published_payload
|
|
19
|
+
|
|
16
20
|
render_maglev_page
|
|
17
21
|
end
|
|
18
22
|
|
|
@@ -105,20 +105,20 @@ module Maglev
|
|
|
105
105
|
def maglev_button_classes(...)
|
|
106
106
|
ClassVariants.build(
|
|
107
107
|
base: %(
|
|
108
|
-
rounded-
|
|
109
|
-
group-[.is-success]/form:bg-green-500
|
|
108
|
+
rounded-sm transition-colors transition-background duration-200 text-center cursor-pointer
|
|
109
|
+
group-[.is-success]/form:bg-green-500 group-[.is-success]/form:hover:bg-green-500/90
|
|
110
110
|
group-[.is-success]/form:disabled:bg-green-500/75
|
|
111
|
-
group-[.is-error]/form:bg-red-500
|
|
111
|
+
group-[.is-error]/form:bg-red-500 group-[.is-error]/form:hover:bg-red-500/90
|
|
112
112
|
group-[.is-error]/form:disabled:bg-red-500/75
|
|
113
113
|
),
|
|
114
114
|
variants: {
|
|
115
115
|
color: {
|
|
116
|
-
primary: 'text-white bg-editor-primary
|
|
116
|
+
primary: 'text-white bg-editor-primary hover:bg-editor-primary/90 disabled:bg-editor-primary/75',
|
|
117
117
|
secondary: 'text-gray-800 hover:bg-gray-100'
|
|
118
118
|
},
|
|
119
119
|
size: {
|
|
120
|
-
big: 'flex items-center justify-center w-full px-6
|
|
121
|
-
medium: 'inline-flex items-center justify-center px-4
|
|
120
|
+
big: 'flex items-center justify-center w-full px-6 h-14',
|
|
121
|
+
medium: 'inline-flex items-center justify-center px-4 h-10'
|
|
122
122
|
}
|
|
123
123
|
},
|
|
124
124
|
defaults: {
|
|
@@ -39,7 +39,7 @@ module Maglev
|
|
|
39
39
|
def add_section_block_no_dropdown_button(section, block_type)
|
|
40
40
|
button_to(
|
|
41
41
|
t('maglev.editor.section_blocks.index.add_button'),
|
|
42
|
-
editor_section_blocks_path(section, block_type: block_type, lock_version:
|
|
42
|
+
editor_section_blocks_path(section, block_type: block_type, lock_version: source_lock_version,
|
|
43
43
|
**maglev_editing_route_context),
|
|
44
44
|
class: maglev_button_classes(size: :big),
|
|
45
45
|
**section_block_button_common_attributes(section)
|
|
@@ -72,7 +72,7 @@ module Maglev
|
|
|
72
72
|
def add_child_section_block_no_dropdown_button(section, parent_id, block_type)
|
|
73
73
|
button_to(
|
|
74
74
|
editor_section_blocks_path(section, block_type: block_type, parent_id: parent_id,
|
|
75
|
-
lock_version:
|
|
75
|
+
lock_version: source_lock_version,
|
|
76
76
|
**maglev_editing_route_context),
|
|
77
77
|
class: maglev_icon_button_classes,
|
|
78
78
|
name: 'add_child_section_block',
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# rubocop:disable Style/ClassAndModuleChildren
|
|
4
|
+
module Maglev::Page::PublishableConcern
|
|
5
|
+
extend ActiveSupport::Concern
|
|
6
|
+
|
|
7
|
+
included do
|
|
8
|
+
# force JSON column for MariaDB
|
|
9
|
+
attribute :published_payload, :json
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def published?
|
|
13
|
+
published_at.present?
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def need_to_be_published?
|
|
17
|
+
!published? || updated_at.blank? || updated_at > published_at
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# opposite of #need_to_be_published?
|
|
21
|
+
def published_and_up_to_date?
|
|
22
|
+
published? && updated_at <= published_at
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def discard_draft?
|
|
26
|
+
published? && updated_at > published_at
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# called when a publishedpage is being previewed
|
|
30
|
+
def apply_published_payload
|
|
31
|
+
return if !published? || published_payload.blank?
|
|
32
|
+
|
|
33
|
+
published_payload_attributes.each do |attribute|
|
|
34
|
+
send("#{attribute}=", published_payload[attribute])
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# called when a page is being published
|
|
39
|
+
def update_published_payload
|
|
40
|
+
# in MySQL, default values for json columns are not supported, so we need to set an empty hash if the value is nil
|
|
41
|
+
self.published_payload ||= {}
|
|
42
|
+
|
|
43
|
+
published_payload_attributes.each do |attribute|
|
|
44
|
+
value = send(attribute.to_sym)
|
|
45
|
+
|
|
46
|
+
# in MySQL, default values for json columns are not supported, so we need to set an empty hash if the value is nil
|
|
47
|
+
value = {} if attribute.ends_with?('_translations') && value.nil?
|
|
48
|
+
|
|
49
|
+
self.published_payload[attribute] = value
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
private
|
|
54
|
+
|
|
55
|
+
def published_payload_attributes
|
|
56
|
+
published_payload_core_attributes + published_payload_additional_attributes
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def published_payload_additional_attributes
|
|
60
|
+
# override this method to add additional attributes to the published payload
|
|
61
|
+
[]
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def published_payload_core_attributes
|
|
65
|
+
%w[title_translations seo_title_translations meta_description_translations og_title_translations
|
|
66
|
+
og_description_translations og_image_url_translations]
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
# rubocop:enable Style/ClassAndModuleChildren
|
data/app/models/maglev/page.rb
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
# og_image_url_translations :jsonb
|
|
12
12
|
# og_title_translations :jsonb
|
|
13
13
|
# published_at :datetime
|
|
14
|
+
# published_payload :jsonb
|
|
14
15
|
# sections_translations :jsonb
|
|
15
16
|
# seo_title_translations :jsonb
|
|
16
17
|
# title_translations :jsonb
|
|
@@ -25,6 +26,7 @@ module Maglev
|
|
|
25
26
|
include Maglev::SectionsConcern
|
|
26
27
|
include Maglev::Page::PathConcern
|
|
27
28
|
include Maglev::Page::SearchConcern
|
|
29
|
+
include Maglev::Page::PublishableConcern
|
|
28
30
|
|
|
29
31
|
## associations ##
|
|
30
32
|
has_many :sections_content_stores, as: :container, dependent: :destroy
|
|
@@ -56,19 +58,6 @@ module Maglev
|
|
|
56
58
|
false
|
|
57
59
|
end
|
|
58
60
|
|
|
59
|
-
def published?
|
|
60
|
-
published_at.present?
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def need_to_be_published?
|
|
64
|
-
!published? || updated_at.blank? || updated_at > published_at
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
# opposite of #need_to_be_published?
|
|
68
|
-
def published_and_up_to_date?
|
|
69
|
-
published? && updated_at <= published_at
|
|
70
|
-
end
|
|
71
|
-
|
|
72
61
|
def translate_in(locale, source_locale)
|
|
73
62
|
%i[title sections seo_title meta_description og_title og_description og_image_url].each do |attr|
|
|
74
63
|
translate_attr_in(attr, locale, source_locale)
|
|
@@ -85,13 +85,15 @@ module Maglev::Section::ContentConcern
|
|
|
85
85
|
return [] if blocks.blank?
|
|
86
86
|
|
|
87
87
|
blocks.map do |block|
|
|
88
|
+
next unless block.root?
|
|
89
|
+
|
|
88
90
|
3.times.to_a.map do
|
|
89
91
|
{
|
|
90
92
|
type: block.type,
|
|
91
93
|
settings: fallback_build_default_settings_content(block.settings)
|
|
92
94
|
}
|
|
93
95
|
end
|
|
94
|
-
end.flatten
|
|
96
|
+
end.compact.flatten
|
|
95
97
|
end
|
|
96
98
|
end
|
|
97
99
|
# rubocop:enable Style/ClassAndModuleChildren
|
|
@@ -78,6 +78,14 @@ module Maglev
|
|
|
78
78
|
"maglev.themes.#{theme.id}.sections.#{id}"
|
|
79
79
|
end
|
|
80
80
|
|
|
81
|
+
def empty?
|
|
82
|
+
settings.none? && blocks.none?
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def local_screenshot?
|
|
86
|
+
screenshot_timestamp.present?
|
|
87
|
+
end
|
|
88
|
+
|
|
81
89
|
## class methods ##
|
|
82
90
|
|
|
83
91
|
def self.build(hash)
|
|
@@ -104,7 +112,7 @@ module Maglev
|
|
|
104
112
|
|
|
105
113
|
class Store
|
|
106
114
|
extend Forwardable
|
|
107
|
-
def_delegators :@array, :all, :first, :last, :count, :each, :each_with_index, :map, :group_by
|
|
115
|
+
def_delegators :@array, :all, :first, :last, :count, :each, :each_with_index, :map, :group_by, :any?
|
|
108
116
|
|
|
109
117
|
attr_reader :array
|
|
110
118
|
|
|
@@ -134,6 +142,18 @@ module Maglev
|
|
|
134
142
|
self.class.new(new_array)
|
|
135
143
|
end
|
|
136
144
|
|
|
145
|
+
def filter(sections_content, keyword: nil, category_id: nil)
|
|
146
|
+
new_array = if keyword.present?
|
|
147
|
+
@array.select { |section| section.name.downcase.include?(keyword.downcase) }
|
|
148
|
+
elsif category_id.present?
|
|
149
|
+
@array.select { |section| section.category == category_id }
|
|
150
|
+
else
|
|
151
|
+
@array
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
self.class.new(new_array).available_for(sections_content)
|
|
155
|
+
end
|
|
156
|
+
|
|
137
157
|
def as_json(**_options)
|
|
138
158
|
@array.as_json
|
|
139
159
|
end
|
|
@@ -14,9 +14,7 @@
|
|
|
14
14
|
#
|
|
15
15
|
# Indexes
|
|
16
16
|
#
|
|
17
|
-
#
|
|
18
|
-
# maglev_sections_content_stores_container (container_id,container_type)
|
|
19
|
-
# maglev_sections_content_stores_container_and_published (container_id,container_type,published)
|
|
17
|
+
# maglev_sections_content_stores_container_and_published (container_id,container_type,published) UNIQUE
|
|
20
18
|
#
|
|
21
19
|
module Maglev
|
|
22
20
|
class SectionsContentStore < ApplicationRecord
|
|
@@ -68,22 +68,19 @@ module Maglev
|
|
|
68
68
|
end
|
|
69
69
|
|
|
70
70
|
def check_section_lock_version!(source)
|
|
71
|
-
check_lock_version!(source,
|
|
71
|
+
check_lock_version!(source, 'update_section')
|
|
72
72
|
end
|
|
73
73
|
|
|
74
74
|
def check_block_lock_version!(source)
|
|
75
|
-
check_lock_version!(source,
|
|
75
|
+
check_lock_version!(source, 'update_block')
|
|
76
76
|
end
|
|
77
77
|
|
|
78
|
-
def check_lock_version!(source,
|
|
78
|
+
def check_lock_version!(source, action_name)
|
|
79
79
|
return if lock_version.blank? # without a lock version, we disable the lock version check
|
|
80
80
|
|
|
81
|
-
current_lock_version =
|
|
81
|
+
current_lock_version = source.lock_version.to_i
|
|
82
|
+
source.lock_version = lock_version.to_i
|
|
82
83
|
|
|
83
|
-
# always increment the lock version
|
|
84
|
-
section_or_block['lock_version'] = lock_version.to_i + 1
|
|
85
|
-
|
|
86
|
-
# if the lock version is the same, we don't need to raise an error
|
|
87
84
|
return if current_lock_version == lock_version.to_i
|
|
88
85
|
|
|
89
86
|
raise ActiveRecord::StaleObjectError.new(source, action_name)
|
|
@@ -8,7 +8,7 @@ module Maglev
|
|
|
8
8
|
Maglev.config
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
-
# hold the Rails request context
|
|
11
|
+
# hold the Rails HTTP request context
|
|
12
12
|
dependency :context
|
|
13
13
|
|
|
14
14
|
dependency :fetch_site, class: Maglev::FetchSite, depends_on: %i[config context]
|
|
@@ -19,7 +19,7 @@ module Maglev
|
|
|
19
19
|
dependency :fetch_section_screenshot_path, class: Maglev::FetchSectionScreenshotPath,
|
|
20
20
|
depends_on: :fetch_sections_path
|
|
21
21
|
dependency :fetch_section_screenshot_url, class: Maglev::FetchSectionScreenshotUrl,
|
|
22
|
-
depends_on:
|
|
22
|
+
depends_on: %i[fetch_section_screenshot_path context]
|
|
23
23
|
|
|
24
24
|
dependency :fetch_collection_items, class: Maglev::FetchCollectionItems, depends_on: %i[fetch_site config]
|
|
25
25
|
dependency :fetch_static_pages, class: Maglev::FetchStaticPages, depends_on: %i[config]
|
|
@@ -67,7 +67,9 @@ module Maglev
|
|
|
67
67
|
dependency :sort_section_blocks, class: Maglev::Content::SortSectionBlocksService,
|
|
68
68
|
depends_on: %i[fetch_site fetch_theme]
|
|
69
69
|
|
|
70
|
+
dependency :has_unpublished_changes, class: Maglev::HasUnpublishedChanges
|
|
70
71
|
dependency :publish, class: Maglev::PublishService
|
|
72
|
+
dependency :discard_page_draft, class: Maglev::DiscardPageDraftService
|
|
71
73
|
|
|
72
74
|
def call
|
|
73
75
|
self
|