panda-cms 0.7.4 → 0.8.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 +37 -2
- data/Rakefile +2 -0
- data/app/components/panda/cms/admin/statistics_component.rb +1 -2
- data/app/components/panda/cms/admin/user_activity_component.html.erb +3 -1
- data/app/components/panda/cms/admin/user_activity_component.rb +3 -5
- data/app/components/panda/cms/admin/user_display_component.html.erb +1 -1
- data/app/components/panda/cms/admin/user_display_component.rb +2 -2
- data/app/components/panda/cms/code_component.rb +8 -4
- data/app/components/panda/cms/menu_component.rb +7 -6
- data/app/components/panda/cms/page_menu_component.rb +15 -17
- data/app/components/panda/cms/rich_text_component.rb +10 -11
- data/app/components/panda/cms/text_component.rb +6 -7
- data/app/controllers/panda/cms/admin/base_controller.rb +18 -0
- data/app/controllers/panda/cms/admin/block_contents_controller.rb +1 -2
- data/app/controllers/panda/cms/admin/dashboard_controller.rb +14 -9
- data/app/controllers/panda/cms/admin/files_controller.rb +1 -3
- data/app/controllers/panda/cms/admin/forms_controller.rb +3 -6
- data/app/controllers/panda/cms/admin/menus_controller.rb +2 -3
- data/app/controllers/panda/cms/admin/pages_controller.rb +9 -8
- data/app/controllers/panda/cms/admin/posts_controller.rb +9 -11
- data/app/controllers/panda/cms/admin/settings/bulk_editor_controller.rb +32 -25
- data/app/controllers/panda/cms/admin/settings_controller.rb +13 -10
- data/app/controllers/panda/cms/application_controller.rb +19 -6
- data/app/controllers/panda/cms/errors_controller.rb +5 -2
- data/app/controllers/panda/cms/form_submissions_controller.rb +2 -0
- data/app/controllers/panda/cms/pages_controller.rb +34 -31
- data/app/controllers/panda/cms/posts_controller.rb +2 -0
- data/app/helpers/panda/cms/admin/files_helper.rb +5 -1
- data/app/helpers/panda/cms/admin/pages_helper.rb +5 -1
- data/app/helpers/panda/cms/application_helper.rb +3 -3
- data/app/helpers/panda/cms/asset_helper.rb +195 -0
- data/app/helpers/panda/cms/pages_helper.rb +2 -0
- data/app/helpers/panda/cms/posts_helper.rb +2 -0
- data/app/helpers/panda/cms/theme_helper.rb +2 -0
- data/app/javascript/panda/cms/application_panda_cms.js +2 -34
- data/app/javascript/panda/cms/controllers/editor_form_controller.js +59 -6
- data/app/javascript/panda/cms/controllers/index.js +8 -24
- data/app/javascript/panda/cms/stimulus-loading.js +39 -0
- data/app/javascript/panda_cms/stimulus-loading.js +39 -0
- data/app/jobs/panda/cms/application_job.rb +2 -0
- data/app/jobs/panda/cms/record_visit_job.rb +2 -0
- data/app/mailers/panda/cms/application_mailer.rb +2 -0
- data/app/mailers/panda/cms/form_mailer.rb +3 -1
- data/app/models/panda/cms/application_record.rb +2 -0
- data/app/models/panda/cms/block.rb +4 -1
- data/app/models/panda/cms/block_content.rb +3 -1
- data/app/models/panda/cms/current.rb +5 -12
- data/app/models/panda/cms/form.rb +2 -0
- data/app/models/panda/cms/form_submission.rb +2 -0
- data/app/models/panda/cms/menu.rb +12 -9
- data/app/models/panda/cms/menu_item.rb +10 -6
- data/app/models/panda/cms/page.rb +14 -12
- data/app/models/panda/cms/post.rb +12 -8
- data/app/models/panda/cms/redirect.rb +6 -3
- data/app/models/panda/cms/template.rb +12 -7
- data/app/models/panda/cms/visit.rb +3 -1
- data/app/models/panda/social/instagram_post.rb +2 -0
- data/app/services/panda/social/instagram_feed_service.rb +3 -1
- data/app/views/layouts/different_page.html.erb +6 -0
- data/app/views/layouts/homepage.html.erb +37 -0
- data/app/views/layouts/page.html.erb +18 -0
- data/app/views/layouts/panda/cms/application.html.erb +2 -1
- data/app/views/panda/cms/admin/dashboard/show.html.erb +2 -2
- data/app/views/panda/cms/admin/files/index.html.erb +1 -1
- data/app/views/panda/cms/admin/forms/index.html.erb +4 -4
- data/app/views/panda/cms/admin/forms/new.html.erb +2 -2
- data/app/views/panda/cms/admin/forms/show.html.erb +1 -1
- data/app/views/panda/cms/admin/menus/index.html.erb +4 -4
- data/app/views/panda/cms/admin/pages/edit.html.erb +6 -6
- data/app/views/panda/cms/admin/pages/index.html.erb +5 -5
- data/app/views/panda/cms/admin/pages/new.html.erb +16 -10
- data/app/views/panda/cms/admin/posts/_form.html.erb +1 -1
- data/app/views/panda/cms/admin/posts/edit.html.erb +2 -2
- data/app/views/panda/cms/admin/posts/index.html.erb +5 -5
- data/app/views/panda/cms/admin/posts/new.html.erb +1 -1
- data/app/views/panda/cms/admin/settings/bulk_editor/new.html.erb +1 -1
- data/app/views/panda/cms/admin/settings/index.html.erb +4 -4
- data/app/views/panda/cms/admin/shared/_breadcrumbs.html.erb +3 -3
- data/app/views/panda/cms/admin/shared/_flash.html.erb +1 -1
- data/app/views/panda/cms/admin/shared/_sidebar.html.erb +8 -8
- data/app/views/panda/cms/shared/_header.html.erb +10 -2
- data/app/views/panda/cms/shared/_importmap.html.erb +1 -1
- data/app/views/shared/_footer.html.erb +3 -0
- data/app/views/shared/_header.html.erb +11 -0
- data/config/importmap.rb +2 -0
- data/config/initializers/inflections.rb +2 -0
- data/config/initializers/panda/cms/form_errors.rb +20 -21
- data/config/initializers/panda/cms/healthcheck_log_silencer.rb +2 -0
- data/config/initializers/panda/cms.rb +8 -3
- data/config/initializers/zeitwork.rb +2 -0
- data/config/puma/test.rb +3 -1
- data/config/routes.rb +11 -19
- data/db/migrate/20240205223709_create_panda_cms_pages.rb +2 -0
- data/db/migrate/20240219213327_create_panda_cms_page_versions.rb +2 -0
- data/db/migrate/20240303002805_create_panda_cms_templates.rb +4 -1
- data/db/migrate/20240303003434_create_panda_cms_template_versions.rb +2 -0
- data/db/migrate/20240303022441_create_panda_cms_blocks.rb +4 -1
- data/db/migrate/20240303024256_create_panda_cms_block_contents.rb +2 -0
- data/db/migrate/20240303024746_create_panda_cms_block_content_versions.rb +2 -0
- data/db/migrate/20240303233238_add_panda_cms_menu_table.rb +2 -0
- data/db/migrate/20240303234724_add_panda_cms_menu_item_table.rb +2 -0
- data/db/migrate/20240304134343_add_parent_id_to_panda_cms_pages.rb +2 -0
- data/db/migrate/20240315125411_add_status_to_panda_cms_pages.rb +7 -5
- data/db/migrate/20240315125421_add_nested_sets_to_panda_cms_pages.rb +2 -0
- data/db/migrate/20240316212822_add_kind_to_panda_cms_menus.rb +3 -1
- data/db/migrate/20240316221425_add_start_page_to_panda_cms_menus.rb +2 -0
- data/db/migrate/20240316230706_add_nested_to_panda_cms_menu_items.rb +2 -0
- data/db/migrate/20240317010532_create_panda_cms_users.rb +2 -0
- data/db/migrate/20240317161534_add_max_uses_to_panda_cms_template.rb +2 -0
- data/db/migrate/20240317163053_reset_counter_cache_on_panda_cms_template.rb +2 -0
- data/db/migrate/20240317214827_create_panda_cms_redirects.rb +2 -0
- data/db/migrate/20240317230622_create_panda_cms_visits.rb +2 -0
- data/db/migrate/20240324205703_create_active_storage_tables.active_storage.rb +5 -2
- data/db/migrate/20240408084718_default_panda_cms_users_admin_to_false.rb +2 -0
- data/db/migrate/20240701225422_add_service_name_to_active_storage_blobs.active_storage.rb +8 -6
- data/db/migrate/20240701225423_create_active_storage_variant_records.active_storage.rb +2 -0
- data/db/migrate/20240701225424_remove_not_null_on_active_storage_blobs_checksum.active_storage.rb +2 -0
- data/db/migrate/20240804235210_create_panda_cms_forms.rb +2 -0
- data/db/migrate/20240805013612_create_panda_cms_form_submissions.rb +2 -0
- data/db/migrate/20240805121123_create_panda_cms_posts.rb +3 -1
- data/db/migrate/20240805123104_create_panda_cms_post_versions.rb +2 -0
- data/db/migrate/20240806112735_fix_panda_cms_visits_column_names.rb +2 -0
- data/db/migrate/20240806204412_add_completion_path_to_panda_cms_forms.rb +2 -0
- data/db/migrate/20240820081917_change_form_submissions_to_submission_count.rb +2 -0
- data/db/migrate/20240923234535_add_depth_to_panda_cms_menus.rb +6 -4
- data/db/migrate/20241031205109_add_cached_content_to_panda_cms_block_contents.rb +2 -0
- data/db/migrate/20241119214548_convert_post_content_to_editor_js.rb +2 -0
- data/db/migrate/20241120000419_remove_post_tag_references.rb +2 -0
- data/db/migrate/20241120110943_add_editor_js_to_posts.rb +2 -0
- data/db/migrate/20241120113859_add_cached_content_to_panda_cms_posts.rb +2 -0
- data/db/migrate/20241123234140_remove_post_tag_id_from_posts.rb +2 -0
- data/db/migrate/20250106223303_add_author_id_to_panda_cms_posts.rb +5 -1
- data/db/migrate/20250120235542_remove_paper_trail.rb +5 -4
- data/db/migrate/20250126234001_create_panda_social_instagram_posts.rb +4 -0
- data/db/migrate/20250809231125_migrate_users_to_panda_core.rb +111 -0
- data/db/migrate/20250811111000_make_post_user_references_nullable.rb +11 -0
- data/db/seeds.rb +2 -0
- data/lib/generators/panda/cms/install_generator.rb +2 -0
- data/lib/panda/cms/asset_loader.rb +390 -0
- data/lib/panda/cms/bulk_editor.rb +7 -3
- data/lib/panda/cms/demo_site_generator.rb +2 -0
- data/lib/panda/cms/engine.rb +57 -116
- data/lib/panda/cms/exceptions_app.rb +2 -0
- data/lib/panda/cms/railtie.rb +2 -0
- data/lib/panda/cms/slug.rb +3 -1
- data/lib/panda-cms/version.rb +3 -1
- data/lib/panda-cms.rb +54 -42
- data/lib/tasks/assets.rake +587 -0
- data/lib/tasks/panda/cms/install.rake +2 -0
- data/lib/tasks/panda/cms/migrations.rake +13 -0
- data/lib/tasks/panda/social/instagram.rake +2 -0
- data/lib/tasks/panda_cms.rake +3 -30
- data/public/panda-cms-assets/manifest.json +20 -0
- data/public/panda-cms-assets/panda-cms-0.7.4.css +26 -0
- data/public/panda-cms-assets/panda-cms-0.7.4.js +150 -0
- metadata +186 -49
- data/app/builders/panda/cms/form_builder.rb +0 -217
- data/app/components/panda/cms/admin/button_component.rb +0 -70
- data/app/components/panda/cms/admin/container_component.rb +0 -13
- data/app/components/panda/cms/admin/flash_message_component.rb +0 -47
- data/app/components/panda/cms/admin/heading_component.rb +0 -45
- data/app/components/panda/cms/admin/panel_component.rb +0 -13
- data/app/components/panda/cms/admin/table_component.rb +0 -46
- data/app/components/panda/cms/admin/tag_component.rb +0 -35
- data/app/constraints/panda/cms/admin_constraint.rb +0 -18
- data/app/controllers/panda/cms/admin/my_profile_controller.rb +0 -43
- data/app/controllers/panda/cms/admin/sessions_controller.rb +0 -94
- data/app/javascript/panda/cms/controllers/theme_form_controller.js +0 -9
- data/app/javascript/panda/cms/editor/css_extractor.js +0 -80
- data/app/javascript/panda/cms/editor/editor_js_config.js +0 -306
- data/app/javascript/panda/cms/editor/editor_js_initializer.js +0 -334
- data/app/javascript/panda/cms/editor/plain_text_editor.js +0 -110
- data/app/javascript/panda/cms/editor/resource_loader.js +0 -204
- data/app/javascript/panda/cms/editor/rich_text_editor.js +0 -162
- data/app/models/panda/cms/breadcrumb.rb +0 -12
- data/app/models/panda/cms/user.rb +0 -31
- data/app/services/panda/cms/html_to_editor_js_converter.rb +0 -193
- data/app/views/panda/cms/admin/my_profile/edit.html.erb +0 -35
- data/app/views/panda/cms/admin/sessions/new.html.erb +0 -17
- data/db/migrate/20250504221812_add_current_theme_to_panda_cms_users.rb +0 -5
- data/lib/panda/cms/editor_js/blocks/alert.rb +0 -34
- data/lib/panda/cms/editor_js/blocks/base.rb +0 -33
- data/lib/panda/cms/editor_js/blocks/header.rb +0 -15
- data/lib/panda/cms/editor_js/blocks/image.rb +0 -36
- data/lib/panda/cms/editor_js/blocks/list.rb +0 -32
- data/lib/panda/cms/editor_js/blocks/paragraph.rb +0 -15
- data/lib/panda/cms/editor_js/blocks/quote.rb +0 -41
- data/lib/panda/cms/editor_js/blocks/table.rb +0 -50
- data/lib/panda/cms/editor_js/renderer.rb +0 -124
- data/lib/panda/cms/editor_js.rb +0 -16
- data/lib/panda/cms/editor_js_content.rb +0 -55
@@ -1,36 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Panda
|
2
4
|
module CMS
|
3
|
-
|
4
|
-
|
5
|
+
module Admin
|
6
|
+
module Settings
|
7
|
+
class BulkEditorController < ::Panda::CMS::Admin::BaseController
|
8
|
+
before_action :set_initial_breadcrumb, only: %i[new]
|
5
9
|
|
6
|
-
|
7
|
-
|
8
|
-
|
10
|
+
def new
|
11
|
+
@json_data = BulkEditor.export
|
12
|
+
end
|
9
13
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
14
|
+
def create
|
15
|
+
begin
|
16
|
+
debug_output = BulkEditor.import(params[:site_content])
|
17
|
+
rescue JSON::ParserError
|
18
|
+
redirect_to admin_cms_settings_bulk_editor_path,
|
19
|
+
flash: {error: "Error parsing content; are you sure this update is valid? Reverting..."}
|
20
|
+
return
|
21
|
+
end
|
17
22
|
|
18
|
-
|
19
|
-
|
23
|
+
# Grab the latest content back so it's all formatted properly
|
24
|
+
@json_data = BulkEditor.export
|
20
25
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
26
|
+
if debug_output[:error].empty? && debug_output[:warning].empty? && debug_output[:success].empty?
|
27
|
+
redirect_to admin_cms_settings_bulk_editor_path, flash: {success: "No changes were found!"}
|
28
|
+
else
|
29
|
+
@debug = debug_output
|
30
|
+
render :new, flash: {warning: "Please review the output below for more information."}
|
31
|
+
end
|
32
|
+
end
|
28
33
|
|
29
|
-
|
34
|
+
private
|
30
35
|
|
31
|
-
|
32
|
-
|
33
|
-
|
36
|
+
def set_initial_breadcrumb
|
37
|
+
add_breadcrumb "Settings", admin_cms_settings_path
|
38
|
+
add_breadcrumb "Bulk Editor", "#"
|
39
|
+
end
|
40
|
+
end
|
34
41
|
end
|
35
42
|
end
|
36
43
|
end
|
@@ -1,19 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Panda
|
2
4
|
module CMS
|
3
|
-
|
4
|
-
|
5
|
-
|
5
|
+
module Admin
|
6
|
+
class SettingsController < ::Panda::CMS::Admin::BaseController
|
7
|
+
before_action :set_initial_breadcrumb, only: %i[index show]
|
6
8
|
|
7
|
-
|
8
|
-
|
9
|
+
def index
|
10
|
+
end
|
9
11
|
|
10
|
-
|
11
|
-
|
12
|
+
def show
|
13
|
+
end
|
12
14
|
|
13
|
-
|
15
|
+
private
|
14
16
|
|
15
|
-
|
16
|
-
|
17
|
+
def set_initial_breadcrumb
|
18
|
+
add_breadcrumb "Settings", admin_cms_settings_path
|
19
|
+
end
|
17
20
|
end
|
18
21
|
end
|
19
22
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Panda
|
2
4
|
module CMS
|
3
5
|
class ApplicationController < ::ActionController::Base
|
@@ -26,31 +28,42 @@ module Panda
|
|
26
28
|
# Set the current request details
|
27
29
|
# @return [void]
|
28
30
|
def set_current_request_details
|
31
|
+
# Set Core current attributes
|
32
|
+
Panda::Core::Current.request_id = request.uuid
|
33
|
+
Panda::Core::Current.user_agent = request.user_agent
|
34
|
+
Panda::Core::Current.ip_address = request.ip
|
35
|
+
Panda::Core::Current.root = request.base_url
|
36
|
+
Panda::Core::Current.user ||= Panda::Core::User.find_by(id: session[:user_id]) if session[:user_id]
|
37
|
+
|
38
|
+
# Set CMS current attributes (inherits from Core so has access to all Core attributes)
|
29
39
|
Panda::CMS::Current.request_id = request.uuid
|
30
40
|
Panda::CMS::Current.user_agent = request.user_agent
|
31
41
|
Panda::CMS::Current.ip_address = request.ip
|
32
42
|
Panda::CMS::Current.root = request.base_url
|
43
|
+
Panda::CMS::Current.user = Panda::Core::Current.user
|
33
44
|
Panda::CMS::Current.page = nil
|
34
|
-
Panda::CMS::Current.user ||= User.find_by(id: session[:user_id]) if session[:user_id]
|
35
45
|
|
36
|
-
Panda::CMS.config.url ||= Panda::
|
46
|
+
Panda::CMS.config.url ||= Panda::Core::Current.root
|
37
47
|
end
|
38
48
|
|
39
49
|
def authenticate_user!
|
40
|
-
redirect_to root_path, flash: {error: "Please login to view this!"} unless user_signed_in?
|
50
|
+
redirect_to main_app.root_path, flash: {error: "Please login to view this!"} unless user_signed_in?
|
41
51
|
end
|
42
52
|
|
43
53
|
def authenticate_admin_user!
|
44
|
-
|
54
|
+
return if user_signed_in? && current_user.admin?
|
55
|
+
|
56
|
+
redirect_to panda_core.admin_login_path,
|
57
|
+
flash: {error: "Please login to view this!"}
|
45
58
|
end
|
46
59
|
|
47
60
|
# Required for paper_trail and seems as good as convention these days
|
48
61
|
def current_user
|
49
|
-
Panda::
|
62
|
+
Panda::Core::Current.user
|
50
63
|
end
|
51
64
|
|
52
65
|
def user_signed_in?
|
53
|
-
!!Panda::
|
66
|
+
!!Panda::Core::Current.user
|
54
67
|
end
|
55
68
|
end
|
56
69
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Panda
|
2
4
|
module CMS
|
3
5
|
class ErrorsController < ApplicationController
|
@@ -5,7 +7,8 @@ module Panda
|
|
5
7
|
|
6
8
|
def show
|
7
9
|
exception = request.env["action_dispatch.exception"]
|
8
|
-
status_code = exception.try(:status_code) || ActionDispatch::ExceptionWrapper.new(request.env,
|
10
|
+
status_code = exception.try(:status_code) || ActionDispatch::ExceptionWrapper.new(request.env,
|
11
|
+
exception).status_code
|
9
12
|
|
10
13
|
render view_for_code(status_code), status: status_code
|
11
14
|
end
|
@@ -17,7 +20,7 @@ module Panda
|
|
17
20
|
private
|
18
21
|
|
19
22
|
def view_for_code(code)
|
20
|
-
supported_error_codes.fetch(code
|
23
|
+
supported_error_codes.fetch(code, "404")
|
21
24
|
end
|
22
25
|
|
23
26
|
def supported_error_codes
|
@@ -1,11 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Panda
|
2
4
|
module CMS
|
3
5
|
class PagesController < ApplicationController
|
4
6
|
include ActionView::Helpers::TagHelper
|
5
7
|
|
6
|
-
before_action :check_login_required, only: [
|
7
|
-
before_action :handle_redirects, only: [
|
8
|
-
after_action :record_visit, only: [
|
8
|
+
before_action :check_login_required, only: %i[root show]
|
9
|
+
before_action :handle_redirects, only: %i[root show]
|
10
|
+
after_action :record_visit, only: %i[root show], unless: :ignore_visit?
|
9
11
|
|
10
12
|
def root
|
11
13
|
params[:path] = ""
|
@@ -14,15 +16,13 @@ module Panda
|
|
14
16
|
|
15
17
|
def show
|
16
18
|
page = if @overrides&.dig(:page_path_match)
|
17
|
-
Panda::CMS::Page.find_by(path: @overrides
|
19
|
+
Panda::CMS::Page.find_by(path: @overrides[:page_path_match])
|
18
20
|
else
|
19
|
-
Panda::CMS::Page.find_by(path: "
|
21
|
+
Panda::CMS::Page.find_by(path: "/#{params[:path]}")
|
20
22
|
end
|
21
23
|
|
22
24
|
Panda::CMS::Current.page = page || Panda::CMS::Page.find_by(path: "/404")
|
23
|
-
if @overrides
|
24
|
-
Panda::CMS::Current.page.title = @overrides&.dig(:title) || page.title
|
25
|
-
end
|
25
|
+
Panda::CMS::Current.page.title = @overrides&.dig(:title) || page.title if @overrides
|
26
26
|
|
27
27
|
layout = page&.template&.file_path
|
28
28
|
|
@@ -42,36 +42,39 @@ module Panda
|
|
42
42
|
private
|
43
43
|
|
44
44
|
def handle_redirects
|
45
|
-
current_path = "
|
45
|
+
current_path = "/#{params[:path]}"
|
46
46
|
redirect = Panda::CMS::Redirect.find_by(origin_path: current_path)
|
47
47
|
|
48
|
-
|
49
|
-
redirect.increment!(:visits)
|
48
|
+
return unless redirect
|
50
49
|
|
51
|
-
|
52
|
-
next_redirect = Panda::CMS::Redirect.find_by(origin_path: redirect.destination_path)
|
53
|
-
if next_redirect
|
54
|
-
next_redirect.increment!(:visits)
|
55
|
-
redirect_to next_redirect.destination_path, status: redirect.status_code and return
|
56
|
-
end
|
50
|
+
redirect.increment!(:visits)
|
57
51
|
|
58
|
-
|
52
|
+
# Check if the destination is also a redirect
|
53
|
+
next_redirect = Panda::CMS::Redirect.find_by(origin_path: redirect.destination_path)
|
54
|
+
if next_redirect
|
55
|
+
next_redirect.increment!(:visits)
|
56
|
+
redirect_to next_redirect.destination_path, status: redirect.status_code and return
|
59
57
|
end
|
58
|
+
|
59
|
+
redirect_to redirect.destination_path, status: redirect.status_code and return
|
60
60
|
end
|
61
61
|
|
62
62
|
def check_login_required
|
63
|
-
|
64
|
-
|
65
|
-
|
63
|
+
return unless Panda::CMS.config.require_login_to_view && !user_signed_in?
|
64
|
+
|
65
|
+
redirect_to panda_cms_maintenance_path and return
|
66
66
|
end
|
67
67
|
|
68
68
|
def ignore_visit?
|
69
69
|
# Ignore visits from bots (TODO: make this configurable)
|
70
70
|
return true if /bot/i.match?(request.user_agent)
|
71
71
|
# Ignore visits from Honeybadger
|
72
|
-
|
72
|
+
if request.headers.to_h.key?("Honeybadger-Token") || request.user_agent == "Honeybadger Uptime Check"
|
73
|
+
return true
|
74
|
+
end
|
73
75
|
# Ignore visits where we're asking for PHP files
|
74
76
|
return true if request.path.ends_with?(".php")
|
77
|
+
|
75
78
|
# Otherwise, record the visit
|
76
79
|
false
|
77
80
|
end
|
@@ -79,9 +82,9 @@ module Panda
|
|
79
82
|
def record_visit
|
80
83
|
RecordVisitJob.perform_later(
|
81
84
|
path: request.path,
|
82
|
-
user_id: Current.user&.id,
|
85
|
+
user_id: Panda::Core::Current.user&.id,
|
83
86
|
redirect_id: @redirect&.id,
|
84
|
-
page_id: Current.page&.id,
|
87
|
+
page_id: Panda::CMS::Current.page&.id,
|
85
88
|
user_agent: request.user_agent,
|
86
89
|
ip_address: request.remote_ip,
|
87
90
|
referer: request.referer, # TODO: Fix the naming of this column
|
@@ -90,13 +93,13 @@ module Panda
|
|
90
93
|
end
|
91
94
|
|
92
95
|
def create_redirect_if_path_changed
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
96
|
+
return unless path_changed? && path_was.present?
|
97
|
+
|
98
|
+
Panda::CMS::Redirect.create!(
|
99
|
+
origin_path: path_was,
|
100
|
+
destination_path: path,
|
101
|
+
status_code: 301
|
102
|
+
)
|
100
103
|
end
|
101
104
|
end
|
102
105
|
end
|
@@ -24,8 +24,8 @@ module Panda
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def panda_cms_editor
|
27
|
-
if Current.user&.admin
|
28
|
-
content_tag(:a, "🐼", href:
|
27
|
+
if Panda::Core::Current.user&.admin
|
28
|
+
content_tag(:a, "🐼", href: edit_admin_cms_page_url(Panda::CMS::Current.page), class: "text-3xl inline absolute right-2 top-2")
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
@@ -45,7 +45,7 @@ module Panda
|
|
45
45
|
end
|
46
46
|
|
47
47
|
def panda_cms_form_with(**options, &)
|
48
|
-
options[:builder] = Panda::
|
48
|
+
options[:builder] = Panda::Core::FormBuilder
|
49
49
|
options[:class] = ["block visible p-6 bg-mid/5 rounded-lg border-mid border", options[:class]].compact.join(" ")
|
50
50
|
form_with(**options, &)
|
51
51
|
end
|
@@ -0,0 +1,195 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "panda/core"
|
4
|
+
|
5
|
+
module Panda
|
6
|
+
module CMS
|
7
|
+
module AssetHelper
|
8
|
+
include Panda::Core::AssetHelper if defined?(Panda::Core::AssetHelper)
|
9
|
+
# Include Panda CMS JavaScript and CSS assets
|
10
|
+
# Automatically chooses between GitHub-hosted assets (production)
|
11
|
+
# and local development assets
|
12
|
+
def panda_cms_assets
|
13
|
+
tags = []
|
14
|
+
|
15
|
+
# Include Core assets first (if Core is available)
|
16
|
+
if defined?(Panda::Core::AssetHelper)
|
17
|
+
tags << panda_core_assets
|
18
|
+
end
|
19
|
+
|
20
|
+
# Then include CMS-specific assets
|
21
|
+
tags << Panda::CMS::AssetLoader.asset_tags
|
22
|
+
|
23
|
+
tags.join("\n").html_safe
|
24
|
+
end
|
25
|
+
|
26
|
+
# Include only Panda CMS JavaScript
|
27
|
+
def panda_cms_javascript
|
28
|
+
js_url = Panda::CMS::AssetLoader.javascript_url
|
29
|
+
return "" unless js_url
|
30
|
+
|
31
|
+
if Panda::CMS::AssetLoader.use_github_assets?
|
32
|
+
# GitHub-hosted assets with integrity check
|
33
|
+
version = Panda::CMS::AssetLoader.send(:asset_version)
|
34
|
+
integrity = asset_integrity(version, "panda-cms-#{version}.js")
|
35
|
+
|
36
|
+
tag_options = {
|
37
|
+
src: js_url
|
38
|
+
}
|
39
|
+
# In CI environment, don't use defer to ensure immediate execution
|
40
|
+
tag_options[:defer] = true unless ENV["GITHUB_ACTIONS"] == "true"
|
41
|
+
# Standalone bundles should NOT use type: "module" - they're regular scripts
|
42
|
+
# Only use type: "module" for importmap/ES module assets
|
43
|
+
if !js_url.include?("panda-cms-assets")
|
44
|
+
tag_options[:type] = "module"
|
45
|
+
end
|
46
|
+
tag_options[:integrity] = integrity if integrity
|
47
|
+
tag_options[:crossorigin] = "anonymous" if integrity
|
48
|
+
|
49
|
+
content_tag(:script, "", tag_options)
|
50
|
+
elsif js_url.include?("panda-cms-assets")
|
51
|
+
# Development assets - check if it's a standalone bundle or importmap
|
52
|
+
defer_option = (ENV["GITHUB_ACTIONS"] == "true") ? {} : {defer: true}
|
53
|
+
javascript_include_tag(js_url, **defer_option)
|
54
|
+
# Standalone bundle - don't use type: "module"
|
55
|
+
else
|
56
|
+
# Importmap asset - use type: "module"
|
57
|
+
defer_option = (ENV["GITHUB_ACTIONS"] == "true") ? {} : {defer: true}
|
58
|
+
javascript_include_tag(js_url, type: "module", **defer_option)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Include only Panda CMS CSS
|
63
|
+
def panda_cms_stylesheet
|
64
|
+
css_url = Panda::CMS::AssetLoader.css_url
|
65
|
+
return "" unless css_url
|
66
|
+
|
67
|
+
if Panda::CMS::AssetLoader.use_github_assets?
|
68
|
+
# GitHub-hosted assets with integrity check
|
69
|
+
version = Panda::CMS::VERSION
|
70
|
+
integrity = asset_integrity(version, "panda-cms-#{version}.css")
|
71
|
+
|
72
|
+
tag_options = {
|
73
|
+
rel: "stylesheet",
|
74
|
+
href: css_url
|
75
|
+
}
|
76
|
+
tag_options[:integrity] = integrity if integrity
|
77
|
+
tag_options[:crossorigin] = "anonymous" if integrity
|
78
|
+
|
79
|
+
tag(:link, tag_options)
|
80
|
+
else
|
81
|
+
# Development assets
|
82
|
+
stylesheet_link_tag(css_url)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Get the current Panda CMS version
|
87
|
+
def panda_cms_version
|
88
|
+
Panda::CMS::VERSION
|
89
|
+
end
|
90
|
+
|
91
|
+
# Check if using GitHub-hosted assets
|
92
|
+
def using_github_assets?
|
93
|
+
Panda::CMS::AssetLoader.use_github_assets?
|
94
|
+
end
|
95
|
+
|
96
|
+
# Download and cache assets if needed
|
97
|
+
# Call this in an initializer or controller to pre-cache assets
|
98
|
+
def ensure_panda_cms_assets!
|
99
|
+
Panda::CMS::AssetLoader.ensure_assets_available!
|
100
|
+
end
|
101
|
+
|
102
|
+
# Debug information about asset loading
|
103
|
+
def panda_cms_asset_debug
|
104
|
+
return "" unless Rails.env.development? || Rails.env.test?
|
105
|
+
|
106
|
+
version = Panda::CMS::VERSION
|
107
|
+
js_url = Panda::CMS::AssetLoader.javascript_url
|
108
|
+
css_url = Panda::CMS::AssetLoader.css_url
|
109
|
+
using_github = Panda::CMS::AssetLoader.use_github_assets?
|
110
|
+
compiled_available = Panda::CMS::AssetLoader.send(:compiled_assets_available?)
|
111
|
+
|
112
|
+
# Additional CI debugging
|
113
|
+
asset_file_exists = js_url && File.exist?(Rails.root.join("public#{js_url}"))
|
114
|
+
ci_env = ENV["GITHUB_ACTIONS"] == "true"
|
115
|
+
|
116
|
+
# Check what script tag will be generated
|
117
|
+
script_tag_preview = if using_github
|
118
|
+
tag_options = {src: js_url}
|
119
|
+
tag_options[:defer] = true unless ci_env
|
120
|
+
if !js_url.include?("panda-cms-assets")
|
121
|
+
tag_options[:type] = "module"
|
122
|
+
end
|
123
|
+
"Script tag: <script#{tag_options.map { |k, v| (v == true) ? " #{k}" : " #{k}=\"#{v}\"" }.join}></script>"
|
124
|
+
else
|
125
|
+
"Using development assets"
|
126
|
+
end
|
127
|
+
|
128
|
+
debug_info = [
|
129
|
+
"<!-- Panda CMS Asset Debug Info -->",
|
130
|
+
"<!-- Version: #{version} -->",
|
131
|
+
"<!-- Using GitHub assets: #{using_github} -->",
|
132
|
+
"<!-- Compiled assets available: #{compiled_available} -->",
|
133
|
+
"<!-- JavaScript URL: #{js_url} -->",
|
134
|
+
"<!-- CSS URL: #{css_url || "none"} -->",
|
135
|
+
"<!-- Rails environment: #{Rails.env} -->",
|
136
|
+
"<!-- Asset file exists: #{asset_file_exists} -->",
|
137
|
+
"<!-- Rails root: #{Rails.root} -->",
|
138
|
+
"<!-- CI environment: #{ci_env} -->",
|
139
|
+
"<!-- #{script_tag_preview} -->",
|
140
|
+
"<!-- Params embed_id: #{params[:embed_id] if respond_to?(:params)} -->",
|
141
|
+
"<!-- Compiled at: #{Time.now.utc.iso8601} -->"
|
142
|
+
]
|
143
|
+
|
144
|
+
debug_info.join("\n").html_safe
|
145
|
+
end
|
146
|
+
|
147
|
+
# Initialize Panda CMS Stimulus application
|
148
|
+
# Call this after the asset tags to ensure proper initialization
|
149
|
+
def panda_cms_stimulus_init
|
150
|
+
javascript_tag(<<~JS, type: "module")
|
151
|
+
// Initialize Panda CMS Stimulus application
|
152
|
+
document.addEventListener('DOMContentLoaded', function() {
|
153
|
+
if (window.pandaCmsStimulus) {
|
154
|
+
console.debug('[Panda CMS] Stimulus application initialized');
|
155
|
+
|
156
|
+
// Set debug mode based on Rails environment
|
157
|
+
const railsEnv = document.body?.dataset?.environment || 'production';
|
158
|
+
window.pandaCmsStimulus.debug = (railsEnv === 'development');
|
159
|
+
|
160
|
+
// Trigger a custom event to signal Panda CMS is ready
|
161
|
+
document.dispatchEvent(new CustomEvent('panda-cms:ready', {
|
162
|
+
detail: {
|
163
|
+
version: '#{Panda::CMS::VERSION}',
|
164
|
+
usingGitHubAssets: #{Panda::CMS::AssetLoader.use_github_assets?}
|
165
|
+
}
|
166
|
+
}));
|
167
|
+
} else {
|
168
|
+
console.warn('[Panda CMS] Stimulus application not found. Assets may not have loaded properly.');
|
169
|
+
}
|
170
|
+
});
|
171
|
+
JS
|
172
|
+
end
|
173
|
+
|
174
|
+
# Complete asset loading with initialization
|
175
|
+
# This is the recommended way to include all Panda CMS assets
|
176
|
+
def panda_cms_complete_assets
|
177
|
+
[
|
178
|
+
panda_cms_asset_debug,
|
179
|
+
panda_cms_assets,
|
180
|
+
panda_cms_stimulus_init,
|
181
|
+
# Add immediate JavaScript execution test for CI debugging
|
182
|
+
(Rails.env.test? ? javascript_tag("window.pandaCmsInlineTest = true; console.log('[Panda CMS] Inline script executed');") : "")
|
183
|
+
].join("\n").html_safe
|
184
|
+
end
|
185
|
+
|
186
|
+
private
|
187
|
+
|
188
|
+
def asset_integrity(version, filename)
|
189
|
+
Panda::CMS::AssetLoader.send(:asset_integrity, version, filename)
|
190
|
+
rescue
|
191
|
+
nil
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
@@ -3,37 +3,5 @@ console.debug("[Panda CMS] Controllers loading...");
|
|
3
3
|
import "controllers"
|
4
4
|
console.debug("[Panda CMS] Controllers loaded...");
|
5
5
|
|
6
|
-
//
|
7
|
-
|
8
|
-
import { ResourceLoader } from "panda/cms/editor/resource_loader"
|
9
|
-
|
10
|
-
// Function to load editor resources
|
11
|
-
async function loadEditorResources() {
|
12
|
-
console.debug("[Panda CMS] Loading editor resources...");
|
13
|
-
try {
|
14
|
-
// First load EditorJS core
|
15
|
-
const editorCore = EDITOR_JS_RESOURCES[0]
|
16
|
-
await ResourceLoader.loadScript(document, document.head, editorCore)
|
17
|
-
|
18
|
-
// Then load all tools in parallel
|
19
|
-
const toolLoads = EDITOR_JS_RESOURCES.slice(1).map(async (resource) => {
|
20
|
-
await ResourceLoader.loadScript(document, document.head, resource)
|
21
|
-
})
|
22
|
-
|
23
|
-
// Load CSS directly since it's a string, not an array
|
24
|
-
await ResourceLoader.embedCSS(document, document.head, EDITOR_JS_CSS)
|
25
|
-
|
26
|
-
// Wait for all resources to load
|
27
|
-
await Promise.all(toolLoads)
|
28
|
-
console.debug("[Panda CMS] Editor resources loaded");
|
29
|
-
|
30
|
-
// Dispatch a custom event when resources are loaded
|
31
|
-
document.dispatchEvent(new CustomEvent('editorjs:loaded'))
|
32
|
-
} catch (error) {
|
33
|
-
console.error("[Panda CMS] Error loading editor resources:", error);
|
34
|
-
}
|
35
|
-
}
|
36
|
-
|
37
|
-
// Load resources on both initial page load and Turbo cache restore
|
38
|
-
document.addEventListener('turbo:load', loadEditorResources);
|
39
|
-
document.addEventListener('turbo:render', loadEditorResources);
|
6
|
+
// Editor resources are now handled by panda-editor gem
|
7
|
+
// The panda-editor gem will load its own resources when needed
|