panda-core 0.12.2 → 1.1.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/LICENSE +1 -1
- data/README.md +53 -0
- data/app/assets/builds/panda_core_admin.css +2 -0
- data/app/assets/tailwind/application.css +413 -131
- data/app/builders/panda/core/form_builder.rb +129 -27
- data/app/components/panda/core/UI/badge.html.erb +10 -0
- data/app/components/panda/core/UI/badge.rb +14 -30
- data/app/components/panda/core/UI/button.html.erb +5 -0
- data/app/components/panda/core/UI/button.rb +15 -19
- data/app/components/panda/core/UI/card.html.erb +3 -0
- data/app/components/panda/core/UI/card.rb +7 -6
- data/app/components/panda/core/admin/attribute_diff_component.html.erb +21 -0
- data/app/components/panda/core/admin/attribute_diff_component.rb +29 -0
- data/app/components/panda/core/admin/breadcrumb_component.html.erb +36 -0
- data/app/components/panda/core/admin/breadcrumb_component.rb +12 -64
- data/app/components/panda/core/admin/breadcrumbs_component.html.erb +16 -0
- data/app/components/panda/core/admin/breadcrumbs_component.rb +26 -0
- data/app/components/panda/core/admin/button_component.html.erb +9 -0
- data/app/components/panda/core/admin/button_component.rb +37 -32
- data/app/components/panda/core/admin/callout_component.html.erb +17 -0
- data/app/components/panda/core/admin/callout_component.rb +57 -0
- data/app/components/panda/core/admin/code_block_component.html.erb +9 -0
- data/app/components/panda/core/admin/code_block_component.rb +23 -0
- data/app/components/panda/core/admin/container_component.html.erb +27 -0
- data/app/components/panda/core/admin/container_component.rb +11 -77
- data/app/components/panda/core/admin/contributors_summary_component.html.erb +15 -0
- data/app/components/panda/core/admin/contributors_summary_component.rb +23 -0
- data/app/components/panda/core/admin/dashboard_default_content_component.html.erb +70 -0
- data/app/components/panda/core/admin/dashboard_default_content_component.rb +32 -0
- data/app/components/panda/core/admin/delete_button_component.html.erb +4 -0
- data/app/components/panda/core/admin/delete_button_component.rb +41 -0
- data/app/components/panda/core/admin/dropdown_button_component.html.erb +28 -0
- data/app/components/panda/core/admin/dropdown_button_component.rb +100 -0
- data/app/components/panda/core/admin/dropdown_component.html.erb +32 -0
- data/app/components/panda/core/admin/dropdown_component.rb +65 -0
- data/app/components/panda/core/admin/empty_state_component.html.erb +16 -0
- data/app/components/panda/core/admin/empty_state_component.rb +25 -0
- data/app/components/panda/core/admin/file_gallery_component.html.erb +58 -0
- data/app/components/panda/core/admin/file_gallery_component.rb +26 -98
- data/app/components/panda/core/admin/filter_pills_component.html.erb +6 -0
- data/app/components/panda/core/admin/filter_pills_component.rb +29 -0
- data/app/components/panda/core/admin/flash_message_component.html.erb +11 -0
- data/app/components/panda/core/admin/flash_message_component.rb +33 -60
- data/app/components/panda/core/admin/form_error_component.html.erb +7 -0
- data/app/components/panda/core/admin/form_error_component.rb +8 -16
- data/app/components/panda/core/admin/form_footer_component.html.erb +16 -0
- data/app/components/panda/core/admin/form_footer_component.rb +65 -0
- data/app/components/panda/core/admin/form_input_component.html.erb +1 -0
- data/app/components/panda/core/admin/form_input_component.rb +21 -13
- data/app/components/panda/core/admin/form_section_component.html.erb +16 -0
- data/app/components/panda/core/admin/form_section_component.rb +64 -0
- data/app/components/panda/core/admin/form_select_component.html.erb +5 -0
- data/app/components/panda/core/admin/form_select_component.rb +25 -26
- data/app/components/panda/core/admin/heading_component.html.erb +26 -0
- data/app/components/panda/core/admin/heading_component.rb +23 -60
- data/app/components/panda/core/admin/login_form_component.html.erb +38 -0
- data/app/components/panda/core/admin/login_form_component.rb +28 -0
- data/app/components/panda/core/admin/main_layout_component.html.erb +88 -0
- data/app/components/panda/core/admin/main_layout_component.rb +19 -0
- data/app/components/panda/core/admin/my_profile/connected_account_component.html.erb +41 -0
- data/app/components/panda/core/admin/my_profile/connected_account_component.rb +27 -0
- data/app/components/panda/core/admin/navigation/item_component.html.erb +34 -0
- data/app/components/panda/core/admin/navigation/item_component.rb +69 -0
- data/app/components/panda/core/admin/navigation/sub_item_component.html.erb +9 -0
- data/app/components/panda/core/admin/navigation/sub_item_component.rb +44 -0
- data/app/components/panda/core/admin/navigation/user_menu_component.html.erb +30 -0
- data/app/components/panda/core/admin/navigation/user_menu_component.rb +36 -0
- data/app/components/panda/core/admin/page_header_component.html.erb +28 -0
- data/app/components/panda/core/admin/page_header_component.rb +19 -35
- data/app/components/panda/core/admin/pagination_component.html.erb +33 -0
- data/app/components/panda/core/admin/pagination_component.rb +56 -0
- data/app/components/panda/core/admin/panel_component.html.erb +19 -0
- data/app/components/panda/core/admin/panel_component.rb +4 -29
- data/app/components/panda/core/admin/prose_panel_component.html.erb +6 -0
- data/app/components/panda/core/admin/prose_panel_component.rb +43 -0
- data/app/components/panda/core/admin/search_bar_component.html.erb +19 -0
- data/app/components/panda/core/admin/search_bar_component.rb +31 -0
- data/app/components/panda/core/admin/search_filter_bar_component.html.erb +22 -0
- data/app/components/panda/core/admin/search_filter_bar_component.rb +27 -0
- data/app/components/panda/core/admin/secret_field_component.html.erb +24 -0
- data/app/components/panda/core/admin/secret_field_component.rb +31 -0
- data/app/components/panda/core/admin/sidebar_component.html.erb +160 -0
- data/app/components/panda/core/admin/sidebar_component.rb +55 -0
- data/app/components/panda/core/admin/slideover_component.html.erb +67 -0
- data/app/components/panda/core/admin/slideover_component.rb +31 -70
- data/app/components/panda/core/admin/statistics_component.html.erb +4 -0
- data/app/components/panda/core/admin/statistics_component.rb +6 -8
- data/app/components/panda/core/admin/tab_bar_component.html.erb +48 -0
- data/app/components/panda/core/admin/tab_bar_component.rb +34 -69
- data/app/components/panda/core/admin/table_component.html.erb +82 -0
- data/app/components/panda/core/admin/table_component.rb +54 -87
- data/app/components/panda/core/admin/tag_badge_component.html.erb +7 -0
- data/app/components/panda/core/admin/tag_badge_component.rb +21 -0
- data/app/components/panda/core/admin/tag_component.html.erb +1 -0
- data/app/components/panda/core/admin/tag_component.rb +51 -20
- data/app/components/panda/core/admin/tag_input_component.html.erb +37 -0
- data/app/components/panda/core/admin/tag_input_component.rb +22 -0
- data/app/components/panda/core/admin/tags_panel_component.html.erb +8 -0
- data/app/components/panda/core/admin/tags_panel_component.rb +33 -0
- data/app/components/panda/core/admin/user_activity_component.html.erb +15 -0
- data/app/components/panda/core/admin/user_activity_component.rb +9 -22
- data/app/components/panda/core/admin/user_display_component.html.erb +8 -0
- data/app/components/panda/core/admin/user_display_component.rb +19 -22
- data/app/components/panda/core/base.rb +35 -42
- data/app/components/panda/core/shared/footer_component.html.erb +2 -0
- data/app/components/panda/core/shared/footer_component.rb +11 -0
- data/app/components/panda/core/shared/header_component.html.erb +32 -0
- data/app/components/panda/core/shared/header_component.rb +19 -0
- data/app/constraints/panda/core/admin_constraint.rb +2 -2
- data/app/controllers/concerns/panda/core/admin_authorization.rb +58 -0
- data/app/controllers/concerns/panda/core/authorizable.rb +107 -0
- data/app/controllers/panda/core/admin/base_controller.rb +62 -3
- data/app/controllers/panda/core/admin/editor/search_controller.rb +17 -0
- data/app/controllers/panda/core/admin/feature_flags_controller.rb +35 -0
- data/app/controllers/panda/core/admin/file_categories_controller.rb +84 -0
- data/app/controllers/panda/core/admin/files_controller.rb +230 -0
- data/app/controllers/panda/core/admin/import_sessions_controller.rb +120 -0
- data/app/controllers/panda/core/admin/my_profile/logins_controller.rb +24 -0
- data/app/controllers/panda/core/admin/my_profile_controller.rb +31 -0
- data/app/controllers/panda/core/admin/search_controller.rb +15 -0
- data/app/controllers/panda/core/admin/sessions_controller.rb +85 -8
- data/app/controllers/panda/core/admin/tags_controller.rb +77 -0
- data/app/controllers/panda/core/admin/test_sessions_controller.rb +5 -6
- data/app/controllers/panda/core/admin/users_controller.rb +184 -0
- data/app/controllers/panda/core/application_controller.rb +13 -1
- data/app/helpers/panda/core/active_storage_helper.rb +24 -0
- data/app/helpers/panda/core/feature_flag_helper.rb +11 -0
- data/app/helpers/panda/core/form_helper.rb +15 -0
- data/app/javascript/panda/core/controllers/avatar_upload_controller.js +73 -0
- data/app/javascript/panda/core/controllers/clipboard_controller.js +119 -0
- data/app/javascript/panda/core/controllers/collapsible_item_controller.js +45 -0
- data/app/javascript/panda/core/controllers/custom_select_controller.js +256 -0
- data/app/javascript/panda/core/controllers/datepicker_controller.js +121 -0
- data/app/javascript/panda/core/controllers/daterange_controller.js +193 -0
- data/app/javascript/panda/core/controllers/file_gallery_controller.js +134 -0
- data/app/javascript/panda/core/controllers/file_upload_controller.js +165 -0
- data/app/javascript/panda/core/controllers/global_search_controller.js +184 -0
- data/app/javascript/panda/core/controllers/index.js +36 -0
- data/app/javascript/panda/core/controllers/mobile_sidebar_controller.js +58 -0
- data/app/javascript/panda/core/controllers/navigation_toggle_controller.js +49 -24
- data/app/javascript/panda/core/controllers/row_link_controller.js +27 -0
- data/app/javascript/panda/core/controllers/tag_input_controller.js +183 -0
- data/app/javascript/panda/core/tailwindcss-stimulus-components.js +2 -3
- data/app/javascript/panda/core/vendor/@fortawesome--fontawesome-free@7.2.0.js +8129 -0
- data/app/javascript/panda/core/vendor/@hotwired--turbo.js +7197 -100
- data/app/javascript/panda/core/vendor/@rails--actioncable--src.js +511 -2
- data/app/javascript/panda/core/vendor/@tailwindplus--elements@1.0.22.js +65 -0
- data/app/javascript/panda/core/vendor/cropperjs@2.1.0.js +3 -0
- data/app/javascript/panda/core/vendor/vanilla-calendar-pro.js +2 -0
- data/app/models/concerns/panda/core/has_metadata.rb +164 -0
- data/app/models/concerns/panda/core/importable.rb +79 -0
- data/app/models/concerns/panda/core/searchable.rb +66 -0
- data/app/models/concerns/panda/core/taggable.rb +37 -0
- data/app/models/panda/core/feature_flag.rb +56 -0
- data/app/models/panda/core/file_categorization.rb +14 -0
- data/app/models/panda/core/file_category.rb +45 -0
- data/app/models/panda/core/import_session.rb +79 -0
- data/app/models/panda/core/presence.rb +24 -0
- data/app/models/panda/core/tag.rb +33 -0
- data/app/models/panda/core/tagging.rb +14 -0
- data/app/models/panda/core/user.rb +96 -18
- data/app/models/panda/core/user_activity.rb +42 -0
- data/app/models/panda/core/user_session.rb +35 -0
- data/app/services/panda/core/attach_avatar_service.rb +15 -3
- data/app/services/panda/core/csv_import_service.rb +65 -0
- data/app/services/panda/core/file_categorizer.rb +52 -0
- data/app/services/panda/core/file_parser.rb +76 -0
- data/app/services/panda/core/invite_user_service.rb +44 -0
- data/app/services/panda/core/presence_service.rb +49 -0
- data/app/views/layouts/panda/core/admin.html.erb +6 -67
- data/app/views/layouts/panda/core/admin_simple.html.erb +2 -2
- data/app/views/panda/core/admin/dashboard/_default_content.html.erb +1 -73
- data/app/views/panda/core/admin/dashboard/show.html.erb +12 -15
- data/app/views/panda/core/admin/feature_flags/index.html.erb +56 -0
- data/app/views/panda/core/admin/file_categories/_form.html.erb +20 -0
- data/app/views/panda/core/admin/file_categories/edit.html.erb +5 -0
- data/app/views/panda/core/admin/file_categories/index.html.erb +55 -0
- data/app/views/panda/core/admin/file_categories/new.html.erb +5 -0
- data/app/views/panda/core/admin/files/_file_details.html.erb +156 -0
- data/app/views/panda/core/admin/files/index.html.erb +61 -0
- data/app/views/panda/core/admin/import_sessions/column_map.html.erb +43 -0
- data/app/views/panda/core/admin/import_sessions/index.html.erb +48 -0
- data/app/views/panda/core/admin/import_sessions/new.html.erb +37 -0
- data/app/views/panda/core/admin/import_sessions/preview.html.erb +51 -0
- data/app/views/panda/core/admin/import_sessions/show.html.erb +87 -0
- data/app/views/panda/core/admin/my_profile/edit.html.erb +51 -39
- data/app/views/panda/core/admin/my_profile/logins/show.html.erb +72 -0
- data/app/views/panda/core/admin/sessions/new.html.erb +1 -38
- data/app/views/panda/core/admin/shared/_breadcrumbs.html.erb +1 -18
- data/app/views/panda/core/admin/shared/_sidebar.html.erb +1 -99
- data/app/views/panda/core/admin/shared/_slideover.html.erb +3 -3
- data/app/views/panda/core/admin/tags/_form.html.erb +21 -0
- data/app/views/panda/core/admin/tags/edit.html.erb +4 -0
- data/app/views/panda/core/admin/tags/index.html.erb +41 -0
- data/app/views/panda/core/admin/tags/new.html.erb +4 -0
- data/app/views/panda/core/admin/users/activity.html.erb +90 -0
- data/app/views/panda/core/admin/users/edit.html.erb +48 -0
- data/app/views/panda/core/admin/users/index.html.erb +161 -0
- data/app/views/panda/core/admin/users/sessions.html.erb +103 -0
- data/app/views/panda/core/admin/users/show.html.erb +224 -0
- data/app/views/panda/core/shared/_footer.html.erb +1 -2
- data/app/views/panda/core/shared/_header.html.erb +4 -22
- data/config/brakeman.ignore +68 -31
- data/config/importmap.rb +13 -11
- data/config/routes.rb +49 -2
- data/db/migrate/20260202171614_create_panda_core_file_categories.rb +30 -0
- data/db/migrate/20260203000001_add_user_management_fields_to_panda_core_users.rb +21 -0
- data/db/migrate/20260203000002_create_panda_core_user_activities.rb +24 -0
- data/db/migrate/20260203000003_create_panda_core_user_sessions.rb +25 -0
- data/db/migrate/20260207100000_create_panda_core_presences.rb +21 -0
- data/db/migrate/20260213000001_fix_active_storage_attachments_record_id_type.rb +44 -0
- data/db/migrate/20260217000001_create_panda_core_feature_flags.rb +14 -0
- data/db/migrate/20260303000001_add_metadata_to_panda_core_users.rb +11 -0
- data/db/migrate/20260310000001_create_panda_core_tags.rb +27 -0
- data/db/migrate/20260310000002_create_panda_core_import_sessions.rb +29 -0
- data/lib/generators/panda/core/install_generator.rb +32 -0
- data/lib/generators/panda/core/templates/panda.rb +63 -0
- data/lib/panda/core/asset_loader.rb +6 -3
- data/lib/panda/core/authentication.rb +3 -3
- data/lib/panda/core/configuration.rb +195 -1
- data/lib/panda/core/engine/admin_controller_config.rb +4 -3
- data/lib/panda/core/engine/autoload_config.rb +21 -9
- data/lib/panda/core/engine/omniauth_config.rb +114 -32
- data/lib/panda/core/engine/pending_migrations_check.rb +46 -0
- data/lib/panda/core/engine/route_config.rb +1 -1
- data/lib/panda/core/engine/sqlite_schema_compatibility.rb +36 -0
- data/lib/panda/core/engine/{phlex_config.rb → view_component_config.rb} +5 -7
- data/lib/panda/core/engine.rb +90 -25
- data/lib/panda/core/middleware.rb +35 -0
- data/lib/panda/core/module_registry.rb +21 -13
- data/lib/panda/core/navigation_registry.rb +455 -0
- data/lib/panda/core/oauth_providers.rb +27 -0
- data/lib/panda/core/permission_registry.rb +89 -0
- data/lib/panda/core/search_registry.rb +69 -0
- data/lib/panda/core/seeds/file_categories.rb +30 -0
- data/lib/panda/core/shared/inflections_config.rb +1 -5
- data/lib/panda/core/testing/rails_helper.rb +87 -0
- data/lib/panda/core/testing/support/authentication_test_helpers.rb +22 -18
- data/lib/panda/core/testing/support/system/cuprite_helpers.rb +4 -4
- data/lib/panda/core/testing/view_component_test_controller.rb +19 -0
- data/lib/panda/core/version.rb +1 -1
- data/lib/panda/core/widget_registry.rb +50 -0
- data/lib/panda/core.rb +20 -0
- data/lib/tasks/panda/core/file_categories.rake +41 -0
- data/public/panda-core-assets/panda-core-0.12.2.css +2 -0
- data/public/panda-core-assets/panda-core-0.12.3.css +2 -0
- data/public/panda-core-assets/panda-core-0.12.5.css +2 -0
- data/public/panda-core-assets/panda-core-0.13.0.css +2 -0
- data/public/panda-core-assets/panda-core-0.14.0.css +2 -0
- data/public/panda-core-assets/panda-core-0.14.4.css +2 -0
- data/public/panda-core-assets/panda-core.css +2 -2
- data/public/panda-core-assets/vanilla-calendar.css +47 -0
- metadata +205 -26
- data/lib/panda/core/engine/inflections_config.rb +0 -23
data/lib/panda/core/engine.rb
CHANGED
|
@@ -5,6 +5,7 @@ require "omniauth"
|
|
|
5
5
|
|
|
6
6
|
require "panda/core/middleware"
|
|
7
7
|
require "panda/core/module_registry"
|
|
8
|
+
require "panda/core/search_registry"
|
|
8
9
|
|
|
9
10
|
# Shared engine mixins
|
|
10
11
|
require_relative "shared/inflections_config"
|
|
@@ -14,9 +15,11 @@ require_relative "shared/generator_config"
|
|
|
14
15
|
require_relative "engine/autoload_config"
|
|
15
16
|
require_relative "engine/importmap_config"
|
|
16
17
|
require_relative "engine/omniauth_config"
|
|
17
|
-
require_relative "engine/
|
|
18
|
+
require_relative "engine/view_component_config"
|
|
18
19
|
require_relative "engine/admin_controller_config"
|
|
19
20
|
require_relative "engine/route_config"
|
|
21
|
+
require_relative "engine/pending_migrations_check"
|
|
22
|
+
require_relative "engine/sqlite_schema_compatibility"
|
|
20
23
|
|
|
21
24
|
module Panda
|
|
22
25
|
module Core
|
|
@@ -35,9 +38,11 @@ module Panda
|
|
|
35
38
|
include AutoloadConfig
|
|
36
39
|
include ImportmapConfig
|
|
37
40
|
include OmniauthConfig
|
|
38
|
-
include
|
|
41
|
+
include ViewComponentConfig
|
|
39
42
|
include AdminControllerConfig
|
|
40
43
|
include RouteConfig
|
|
44
|
+
include PendingMigrationsCheck
|
|
45
|
+
include SqliteSchemaCompatibility
|
|
41
46
|
|
|
42
47
|
#
|
|
43
48
|
# Misc configuration point
|
|
@@ -46,33 +51,93 @@ module Panda
|
|
|
46
51
|
# Intentionally quiet — used as a stable anchor point
|
|
47
52
|
end
|
|
48
53
|
|
|
54
|
+
#
|
|
55
|
+
# Clean up FileCategorization records before blob destruction.
|
|
56
|
+
# Without this, ActiveStorage::Blob#purge silently fails because
|
|
57
|
+
# panda_core_file_categorizations has a FK to active_storage_blobs,
|
|
58
|
+
# and Rails rescues the resulting InvalidForeignKey error.
|
|
59
|
+
#
|
|
60
|
+
initializer "panda_core.active_storage_blob_cleanup" do
|
|
61
|
+
ActiveSupport.on_load(:active_storage_blob) do
|
|
62
|
+
before_destroy :cleanup_file_categorizations
|
|
63
|
+
|
|
64
|
+
private
|
|
65
|
+
|
|
66
|
+
def cleanup_file_categorizations
|
|
67
|
+
Panda::Core::FileCategorization.where(blob_id: id).delete_all
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
#
|
|
73
|
+
# Auto-categorize files when ActiveStorage attachments are created.
|
|
74
|
+
# Maps known attachment types (user avatars, page images, etc.) to
|
|
75
|
+
# their corresponding file categories via FileCategorizer.
|
|
76
|
+
#
|
|
77
|
+
initializer "panda_core.active_storage_categorization" do
|
|
78
|
+
ActiveSupport.on_load(:active_storage_attachment) do
|
|
79
|
+
after_create_commit :auto_categorize_blob
|
|
80
|
+
|
|
81
|
+
private
|
|
82
|
+
|
|
83
|
+
def auto_categorize_blob
|
|
84
|
+
Panda::Core::FileCategorizer.new.categorize_attachment(self)
|
|
85
|
+
rescue => e
|
|
86
|
+
Rails.logger.warn("[Panda::Core] Auto-categorization failed for blob #{blob_id}: #{e.message}")
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
#
|
|
92
|
+
# Ensure system file categories exist on every boot.
|
|
93
|
+
# Skipped in test env to avoid interfering with fixtures.
|
|
94
|
+
# Uses find_or_create_by! so it's idempotent.
|
|
95
|
+
#
|
|
96
|
+
initializer "panda_core.ensure_file_categories", after: "panda_core.active_storage_categorization" do
|
|
97
|
+
config.after_initialize do
|
|
98
|
+
next if Rails.env.test?
|
|
99
|
+
if ActiveRecord::Base.connection.table_exists?("panda_core_file_categories")
|
|
100
|
+
require "panda/core/seeds/file_categories"
|
|
101
|
+
Panda::Core::Seeds::FileCategories.seed!
|
|
102
|
+
end
|
|
103
|
+
rescue ActiveRecord::NoDatabaseError, ActiveRecord::ConnectionNotEstablished
|
|
104
|
+
# Skip when DB isn't available (asset precompilation, etc.)
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
49
108
|
#
|
|
50
109
|
# Static asset handling for:
|
|
51
110
|
# /panda-core-assets
|
|
52
111
|
#
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
112
|
+
# Configured during engine load phase to avoid Rails 8.1.2+ frozen middleware stack
|
|
113
|
+
# Use no-cache in development for easier debugging, long cache in production
|
|
114
|
+
config.app_middleware.use(
|
|
115
|
+
Rack::Static,
|
|
116
|
+
urls: ["/panda-core-assets"],
|
|
117
|
+
root: Panda::Core::Engine.root.join("public"),
|
|
118
|
+
header_rules: [
|
|
119
|
+
[
|
|
120
|
+
:all,
|
|
121
|
+
{
|
|
122
|
+
"Cache-Control" => if defined?(::Rails) && ::Rails.env.development?
|
|
123
|
+
"no-cache, no-store, must-revalidate"
|
|
124
|
+
else
|
|
125
|
+
"public, max-age=31536000"
|
|
126
|
+
end
|
|
127
|
+
}
|
|
69
128
|
]
|
|
70
|
-
|
|
129
|
+
]
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
config.app_middleware.use(Panda::Core::ModuleRegistry::JavaScriptMiddleware)
|
|
71
133
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
134
|
+
#
|
|
135
|
+
# Serve Chartkick vendor assets when the chartkick gem is available
|
|
136
|
+
# Must be inserted BEFORE Rack::Static so it handles chartkick requests
|
|
137
|
+
# before Rack::Static catches all /panda-core-assets/* paths and returns 404
|
|
138
|
+
#
|
|
139
|
+
if Gem.loaded_specs["chartkick"]
|
|
140
|
+
config.app_middleware.insert_before(Rack::Static, Panda::Core::ChartkickAssetMiddleware)
|
|
76
141
|
end
|
|
77
142
|
end
|
|
78
143
|
end
|
|
@@ -86,10 +151,10 @@ Panda::Core::ModuleRegistry.register(
|
|
|
86
151
|
engine: "Panda::Core::Engine",
|
|
87
152
|
paths: {
|
|
88
153
|
builders: "app/builders/panda/core/**/*.rb",
|
|
89
|
-
components: "app/components/panda/core/**/*.rb",
|
|
154
|
+
components: "app/components/panda/core/**/*.{rb,erb,js}",
|
|
90
155
|
helpers: "app/helpers/panda/core/**/*.rb",
|
|
91
156
|
views: "app/views/panda/core/**/*.erb",
|
|
92
157
|
layouts: "app/views/layouts/panda/core/**/*.erb",
|
|
93
|
-
javascripts: "app/
|
|
158
|
+
javascripts: "app/javascript/panda/core/**/*.js"
|
|
94
159
|
}
|
|
95
160
|
)
|
|
@@ -142,5 +142,40 @@ module Panda
|
|
|
142
142
|
end
|
|
143
143
|
private_class_method :normalize_stack
|
|
144
144
|
end
|
|
145
|
+
|
|
146
|
+
# Serves Chartkick vendor JS files (Chart.bundle.js, chartkick.js) from the
|
|
147
|
+
# chartkick gem's vendor directory at /panda-core-assets/chartkick/*.
|
|
148
|
+
class ChartkickAssetMiddleware
|
|
149
|
+
CHARTKICK_PATH_PREFIX = "/panda-core-assets/chartkick/"
|
|
150
|
+
ALLOWED_FILES = %w[Chart.bundle.js chartkick.js].freeze
|
|
151
|
+
|
|
152
|
+
def initialize(app)
|
|
153
|
+
@app = app
|
|
154
|
+
@vendor_root = Pathname.new(Gem.loaded_specs["chartkick"].gem_dir).join("vendor/assets/javascripts")
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def call(env)
|
|
158
|
+
path = Rack::Utils.unescape_path(env[Rack::PATH_INFO])
|
|
159
|
+
|
|
160
|
+
if path.start_with?(CHARTKICK_PATH_PREFIX)
|
|
161
|
+
filename = path.delete_prefix(CHARTKICK_PATH_PREFIX)
|
|
162
|
+
return @app.call(env) unless ALLOWED_FILES.include?(filename)
|
|
163
|
+
|
|
164
|
+
file_path = @vendor_root.join(filename)
|
|
165
|
+
return @app.call(env) unless file_path.file?
|
|
166
|
+
|
|
167
|
+
content = File.binread(file_path)
|
|
168
|
+
cache = Rails.env.local? ? "no-cache, no-store, must-revalidate" : "public, max-age=31536000"
|
|
169
|
+
|
|
170
|
+
[200, {
|
|
171
|
+
"Content-Type" => "application/javascript; charset=utf-8",
|
|
172
|
+
"Content-Length" => content.bytesize.to_s,
|
|
173
|
+
"Cache-Control" => cache
|
|
174
|
+
}, [content]]
|
|
175
|
+
else
|
|
176
|
+
@app.call(env)
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
end
|
|
145
180
|
end
|
|
146
181
|
end
|
|
@@ -343,6 +343,10 @@ module Panda
|
|
|
343
343
|
private
|
|
344
344
|
|
|
345
345
|
def find_javascript_file(relative_path)
|
|
346
|
+
# Build list of paths to try - include .js extension fallback
|
|
347
|
+
paths_to_try = [relative_path]
|
|
348
|
+
paths_to_try << "#{relative_path}.js" unless relative_path.end_with?(".js")
|
|
349
|
+
|
|
346
350
|
# Check each registered module's JavaScript directory
|
|
347
351
|
ModuleRegistry.modules.each do |gem_name, info|
|
|
348
352
|
next unless ModuleRegistry.send(:engine_available?, info[:engine])
|
|
@@ -350,24 +354,28 @@ module Panda
|
|
|
350
354
|
root = ModuleRegistry.send(:engine_root, info[:engine])
|
|
351
355
|
next unless root
|
|
352
356
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
357
|
+
paths_to_try.each do |path|
|
|
358
|
+
# Check in app/javascript/panda/ (primary location)
|
|
359
|
+
candidate = root.join("app/javascript/panda", path)
|
|
360
|
+
return candidate.to_s if candidate.exist? && candidate.file?
|
|
356
361
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
362
|
+
# Fallback to public/panda/ (for CI environments where assets are copied)
|
|
363
|
+
public_candidate = root.join("public/panda", path)
|
|
364
|
+
return public_candidate.to_s if public_candidate.exist? && public_candidate.file?
|
|
365
|
+
end
|
|
360
366
|
end
|
|
361
367
|
|
|
362
368
|
# Also check Rails.root if available (for dummy apps in CI)
|
|
363
369
|
if defined?(Rails.root)
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
370
|
+
paths_to_try.each do |path|
|
|
371
|
+
# Check app/javascript/panda/ in Rails.root
|
|
372
|
+
rails_candidate = Rails.root.join("app/javascript/panda", path)
|
|
373
|
+
return rails_candidate.to_s if rails_candidate.exist? && rails_candidate.file?
|
|
374
|
+
|
|
375
|
+
# Fallback to public/panda/ in Rails.root
|
|
376
|
+
rails_public_candidate = Rails.root.join("public/panda", path)
|
|
377
|
+
return rails_public_candidate.to_s if rails_public_candidate.exist? && rails_public_candidate.file?
|
|
378
|
+
end
|
|
371
379
|
end
|
|
372
380
|
|
|
373
381
|
nil
|