panda-core 0.2.3 → 0.4.1

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.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +185 -0
  3. data/app/assets/tailwind/application.css +279 -0
  4. data/app/assets/tailwind/tailwind.config.js +21 -0
  5. data/app/components/panda/core/UI/badge.rb +107 -0
  6. data/app/components/panda/core/UI/button.rb +89 -0
  7. data/app/components/panda/core/UI/card.rb +88 -0
  8. data/app/components/panda/core/admin/button_component.rb +46 -28
  9. data/app/components/panda/core/admin/container_component.rb +52 -4
  10. data/app/components/panda/core/admin/flash_message_component.rb +74 -9
  11. data/app/components/panda/core/admin/form_error_component.rb +48 -0
  12. data/app/components/panda/core/admin/form_input_component.rb +50 -0
  13. data/app/components/panda/core/admin/form_select_component.rb +68 -0
  14. data/app/components/panda/core/admin/heading_component.rb +52 -24
  15. data/app/components/panda/core/admin/panel_component.rb +33 -4
  16. data/app/components/panda/core/admin/slideover_component.rb +8 -4
  17. data/app/components/panda/core/admin/statistics_component.rb +19 -0
  18. data/app/components/panda/core/admin/tab_bar_component.rb +101 -0
  19. data/app/components/panda/core/admin/table_component.rb +90 -9
  20. data/app/components/panda/core/admin/tag_component.rb +21 -16
  21. data/app/components/panda/core/admin/user_activity_component.rb +43 -0
  22. data/app/components/panda/core/admin/user_display_component.rb +78 -0
  23. data/app/components/panda/core/base.rb +122 -0
  24. data/app/controllers/panda/core/admin/base_controller.rb +68 -0
  25. data/app/controllers/panda/core/admin/dashboard_controller.rb +7 -6
  26. data/app/controllers/panda/core/admin/my_profile_controller.rb +3 -3
  27. data/app/controllers/panda/core/admin/sessions_controller.rb +26 -5
  28. data/app/helpers/panda/core/sessions_helper.rb +21 -0
  29. data/app/javascript/panda/core/application.js +1 -0
  30. data/app/javascript/panda/core/vendor/@hotwired--stimulus.js +4 -0
  31. data/app/javascript/panda/core/vendor/@hotwired--turbo.js +160 -0
  32. data/app/javascript/panda/core/vendor/@rails--actioncable--src.js +4 -0
  33. data/app/models/panda/core/user.rb +17 -13
  34. data/app/views/layouts/panda/core/admin.html.erb +40 -57
  35. data/app/views/layouts/panda/core/admin_simple.html.erb +5 -0
  36. data/app/views/panda/core/admin/dashboard/_default_content.html.erb +73 -0
  37. data/app/views/panda/core/admin/dashboard/show.html.erb +4 -10
  38. data/app/views/panda/core/admin/my_profile/edit.html.erb +13 -27
  39. data/app/views/panda/core/admin/sessions/new.html.erb +13 -12
  40. data/app/views/panda/core/admin/shared/_breadcrumbs.html.erb +27 -34
  41. data/app/views/panda/core/admin/shared/_flash.html.erb +4 -30
  42. data/app/views/panda/core/admin/shared/_sidebar.html.erb +36 -20
  43. data/app/views/panda/core/shared/_footer.html.erb +2 -0
  44. data/app/views/panda/core/shared/_header.html.erb +19 -0
  45. data/config/importmap.rb +15 -0
  46. data/config/initializers/panda_core.rb +37 -1
  47. data/config/routes.rb +7 -7
  48. data/db/migrate/20250810120000_add_current_theme_to_panda_core_users.rb +7 -0
  49. data/lib/generators/panda/core/install_generator.rb +3 -9
  50. data/lib/generators/panda/core/templates/README +25 -0
  51. data/lib/generators/panda/core/templates/initializer.rb +28 -0
  52. data/lib/panda/core/asset_loader.rb +23 -8
  53. data/lib/panda/core/configuration.rb +41 -9
  54. data/lib/panda/core/debug.rb +47 -0
  55. data/lib/panda/core/engine.rb +82 -8
  56. data/lib/panda/core/version.rb +1 -1
  57. data/lib/panda/core.rb +1 -0
  58. data/lib/tasks/assets.rake +58 -392
  59. data/lib/tasks/panda_core_tasks.rake +16 -0
  60. metadata +102 -14
  61. data/app/components/panda/core/admin/container_component.html.erb +0 -12
  62. data/app/components/panda/core/admin/flash_message_component.html.erb +0 -31
  63. data/app/components/panda/core/admin/panel_component.html.erb +0 -7
  64. data/app/components/panda/core/admin/slideover_component.html.erb +0 -9
  65. data/app/components/panda/core/admin/table_component.html.erb +0 -29
  66. data/app/controllers/panda/core/admin_controller.rb +0 -28
@@ -1,10 +1,46 @@
1
1
  Panda::Core.configure do |config|
2
+ config.admin_path = "/admin"
3
+
4
+ config.login_page_title = "Panda Admin"
5
+ config.admin_title = "Panda Admin"
6
+
7
+ # Configure authentication providers
8
+ # Uncomment and configure the providers you want to use
9
+ # Don't forget to add the corresponding gems (e.g., omniauth-google-oauth2)
10
+ #
11
+ # config.authentication_providers = {
12
+ # google_oauth2: {
13
+ # enabled: true,
14
+ # name: "Google", # Display name for the button
15
+ # icon: "google", # FontAwesome icon name (optional, auto-detected if not specified)
16
+ # path_name: "google", # Optional: Override URL path (default uses strategy name)
17
+ # # e.g., "google" gives /admin/auth/google instead of /admin/auth/google_oauth2
18
+ # client_id: Rails.application.credentials.dig(:google, :client_id),
19
+ # client_secret: Rails.application.credentials.dig(:google, :client_secret),
20
+ # options: {
21
+ # scope: "email,profile",
22
+ # prompt: "select_account",
23
+ # hd: "yourdomain.com" # Specify your domain here if you want to restrict admin logins
24
+ # }
25
+ # }
26
+ # }
27
+
28
+ # Configure the session token cookie name
29
+ config.session_token_cookie = :panda_session
30
+
2
31
  # Configure the user class for the application
3
- # config.user_class = "User"
32
+ config.user_class = "Panda::Core::User"
33
+
34
+ # Configure the user identity class for the application
35
+ config.user_identity_class = "Panda::Core::UserIdentity"
4
36
 
5
37
  # Configure the storage provider (default: :active_storage)
6
38
  # config.storage_provider = :active_storage
7
39
 
8
40
  # Configure the cache store (default: :memory_store)
9
41
  # config.cache_store = :memory_store
42
+
43
+ # Configure EditorJS tools (optional)
44
+ # config.editor_js_tools = []
45
+ # config.editor_js_tool_config = {}
10
46
  end
data/config/routes.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  Panda::Core::Engine.routes.draw do
2
- # Use the configured admin path (defaults to "/admin")
3
- admin_path = Panda::Core.configuration.admin_path.delete_prefix("/")
2
+ # Get admin_path from configuration
3
+ # Default to "/admin" if not yet configured
4
+ admin_path = (Panda::Core.config.admin_path || "/admin").delete_prefix("/")
4
5
 
5
6
  scope path: admin_path, as: "admin" do
6
7
  get "/login", to: "admin/sessions#new", as: :login
@@ -12,11 +13,10 @@ Panda::Core::Engine.routes.draw do
12
13
  get "/auth/failure", to: "admin/sessions#failure", as: :auth_failure
13
14
  delete "/logout", to: "admin/sessions#destroy", as: :logout
14
15
 
15
- constraints Panda::Core::AdminConstraint.new do
16
- get "/", to: "admin/dashboard#show", as: :root
16
+ # Dashboard and admin routes - authentication handled by AdminController
17
+ get "/", to: "admin/dashboard#show", as: :root
17
18
 
18
- # Profile management
19
- resource :my_profile, only: %i[edit update], controller: "admin/my_profile", path: "my_profile"
20
- end
19
+ # Profile management
20
+ resource :my_profile, only: %i[edit update], controller: "admin/my_profile", path: "my_profile"
21
21
  end
22
22
  end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AddCurrentThemeToPandaCoreUsers < ActiveRecord::Migration[7.1]
4
+ def change
5
+ add_column :panda_core_users, :current_theme, :string unless column_exists?(:panda_core_users, :current_theme)
6
+ end
7
+ end
@@ -23,7 +23,7 @@ module Panda
23
23
  end
24
24
 
25
25
  def create_initializer
26
- template "initializer.rb", "config/initializers/panda_core.rb"
26
+ template "initializer.rb", "config/initializers/panda.rb"
27
27
  end
28
28
 
29
29
  def mount_engine
@@ -33,14 +33,8 @@ module Panda
33
33
  route 'mount Panda::Core::Engine => "/"'
34
34
  end
35
35
 
36
- def copy_migrations
37
- return if options[:skip_migrations]
38
- return unless options[:orm] == "active_record"
39
-
40
- migrations_path = File.expand_path("../../../../db/migrate", __dir__)
41
- Dir.glob("#{migrations_path}/*.rb").each do |migration|
42
- migration_template migration, "db/migrate/#{File.basename(migration)}"
43
- end
36
+ def show_readme
37
+ readme "README" if behavior == :invoke
44
38
  end
45
39
  end
46
40
  end
@@ -0,0 +1,25 @@
1
+ ===============================================================================
2
+
3
+ Panda Core has been installed!
4
+
5
+ Next steps:
6
+
7
+ 1. Install and run migrations:
8
+
9
+ rails panda:core:install:migrations
10
+ rails db:migrate
11
+
12
+ 2. Configure authentication providers in config/initializers/panda.rb
13
+ (Uncomment and configure the providers you want to use)
14
+
15
+ 3. Add the required OAuth gems to your Gemfile:
16
+
17
+ gem 'omniauth-google-oauth2' # For Google authentication
18
+ gem 'omniauth-microsoft_graph' # For Microsoft authentication
19
+ gem 'omniauth-github' # For GitHub authentication
20
+
21
+ 4. Configure your OAuth credentials in Rails credentials:
22
+
23
+ rails credentials:edit
24
+
25
+ ===============================================================================
@@ -1,4 +1,28 @@
1
1
  Panda::Core.configure do |config|
2
+ config.admin_path = "/admin"
3
+
4
+ config.login_page_title = "Panda Admin"
5
+ config.admin_title = "Panda Admin"
6
+
7
+ # Configure authentication providers
8
+ # Uncomment and configure the providers you want to use
9
+ # Don't forget to add the corresponding gems (e.g., omniauth-google-oauth2)
10
+ #
11
+ # config.authentication_providers = {
12
+ # google_oauth2: {
13
+ # enabled: true,
14
+ # name: "Google", # Display name for the button
15
+ # icon: "google", # FontAwesome icon name (optional, auto-detected if not specified)
16
+ # client_id: Rails.application.credentials.dig(:google, :client_id),
17
+ # client_secret: Rails.application.credentials.dig(:google, :client_secret),
18
+ # options: {
19
+ # scope: "email,profile",
20
+ # prompt: "select_account",
21
+ # hd: "yourdomain.com" # Specify your domain here if you want to restrict admin logins
22
+ # }
23
+ # }
24
+ # }
25
+
2
26
  # Configure the session token cookie name
3
27
  config.session_token_cookie = :panda_session
4
28
 
@@ -13,4 +37,8 @@ Panda::Core.configure do |config|
13
37
 
14
38
  # Configure the cache store (default: :memory_store)
15
39
  # config.cache_store = :memory_store
40
+
41
+ # Configure EditorJS tools (optional)
42
+ # config.editor_js_tools = []
43
+ # config.editor_js_tool_config = {}
16
44
  end
@@ -105,9 +105,19 @@ module Panda
105
105
  end
106
106
 
107
107
  else
108
- # Development mode - use importmap
108
+ # Development mode - use importmap for JS and static CSS
109
109
  tags = []
110
110
  tags << javascript_include_tag("panda/core/application", type: "module")
111
+
112
+ # Add CSS if available
113
+ css_path = development_css_url
114
+ if css_path
115
+ css_attrs = {
116
+ rel: "stylesheet",
117
+ href: css_path
118
+ }
119
+ tags << tag(:link, css_attrs)
120
+ end
111
121
  end
112
122
  tags.join("\n").html_safe
113
123
  end
@@ -144,11 +154,16 @@ module Panda
144
154
  end
145
155
 
146
156
  def development_css_url
147
- return unless compiled_assets_available?
148
-
157
+ # Try versioned file first
149
158
  version = asset_version
150
- css_file = "/panda-core-assets/panda-core-#{version}.css"
151
- File.exist?(Rails.root.join("public#{css_file}")) ? css_file : nil
159
+ versioned_file = "/panda-core-assets/panda-core-#{version}.css"
160
+ return versioned_file if File.exist?(Rails.public_path.join("panda-core-assets", "panda-core-#{version}.css"))
161
+
162
+ # Fall back to unversioned file (always available from engine's public directory)
163
+ unversioned_file = "/panda-core-assets/panda-core.css"
164
+ return unversioned_file if File.exist?(Panda::Core::Engine.root.join("public", "panda-core-assets", "panda-core.css"))
165
+
166
+ nil
152
167
  end
153
168
 
154
169
  def asset_version
@@ -193,9 +208,9 @@ module Panda
193
208
  end.compact.join(" ")
194
209
 
195
210
  if content || block_given?
196
- "<#{name}#{attrs.present? ? " #{attrs}" : ""}>#{content || (block_given? ? yield : "")}</#{name}>"
211
+ "<#{name}#{" #{attrs}" if attrs.present?}>#{content || (block_given? ? yield : "")}</#{name}>"
197
212
  else
198
- "<#{name}#{attrs.present? ? " #{attrs}" : ""}><#{name}>"
213
+ "<#{name}#{" #{attrs}" if attrs.present?}><#{name}>"
199
214
  end
200
215
  end
201
216
 
@@ -208,7 +223,7 @@ module Panda
208
223
  end
209
224
  end.compact.join(" ")
210
225
 
211
- "<#{name}#{attrs.present? ? " #{attrs}" : ""} />"
226
+ "<#{name}#{" #{attrs}" if attrs.present?} />"
212
227
  end
213
228
 
214
229
  def javascript_include_tag(source, options = {})
@@ -19,8 +19,10 @@ module Panda
19
19
  :authorization_policy,
20
20
  :additional_user_params,
21
21
  :available_themes,
22
+ :default_theme,
22
23
  :login_logo_path,
23
24
  :login_page_title,
25
+ :admin_title,
24
26
  :initial_admin_breadcrumb,
25
27
  :dashboard_redirect_path
26
28
 
@@ -36,9 +38,35 @@ module Panda
36
38
  @session_token_cookie = :panda_session
37
39
  @authentication_providers = {}
38
40
  @admin_path = "/admin"
41
+ @default_theme = "default"
39
42
 
40
- # Hook system for extending admin UI
41
- @admin_navigation_items = ->(user) { [] }
43
+ # Hook system for extending admin UI with sensible defaults
44
+ @admin_navigation_items = ->(user) {
45
+ items = [
46
+ {
47
+ label: "Dashboard",
48
+ path: @admin_path,
49
+ icon: "fa-solid fa-house"
50
+ }
51
+ ]
52
+
53
+ # Add CMS navigation if available
54
+ if defined?(Panda::CMS)
55
+ items << {
56
+ label: "Content",
57
+ path: "#{@admin_path}/cms",
58
+ icon: "fa-solid fa-file-lines"
59
+ }
60
+ end
61
+
62
+ items << {
63
+ label: "My Profile",
64
+ path: "#{@admin_path}/my_profile/edit",
65
+ icon: "fa-solid fa-user"
66
+ }
67
+
68
+ items
69
+ }
42
70
  @admin_dashboard_widgets = ->(user) { [] }
43
71
  @user_attributes = []
44
72
  @user_associations = []
@@ -48,26 +76,30 @@ module Panda
48
76
  @additional_user_params = []
49
77
  @available_themes = [["Default", "default"], ["Sky", "sky"]]
50
78
  @login_logo_path = nil
51
- @login_page_title = "Sign in to your account"
79
+ @login_page_title = "Panda Admin"
80
+ @admin_title = "Panda Admin"
52
81
  @initial_admin_breadcrumb = nil # Proc that returns [label, path]
53
82
  @dashboard_redirect_path = nil # Path to redirect to after login (defaults to admin_root_path)
54
83
  end
55
84
  end
56
85
 
57
86
  class << self
58
- attr_writer :configuration
87
+ attr_writer :config
59
88
 
60
- def configuration
61
- @configuration ||= Configuration.new
89
+ def config
90
+ @config ||= Configuration.new
62
91
  end
63
92
 
64
93
  def configure
65
- yield(configuration)
94
+ yield(config)
66
95
  end
67
96
 
68
- def reset_configuration!
69
- @configuration = Configuration.new
97
+ def reset_config!
98
+ @config = Configuration.new
70
99
  end
100
+
101
+ # Alias for backward compatibility with test expectations
102
+ alias_method :reset_configuration!, :reset_config!
71
103
  end
72
104
  end
73
105
  end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Panda
4
+ module Core
5
+ module Debug
6
+ class << self
7
+ # Check if debug mode is enabled via PANDA_DEBUG environment variable
8
+ def enabled?
9
+ ENV["PANDA_DEBUG"].to_s.downcase == "true" || ENV["PANDA_DEBUG"] == "1"
10
+ end
11
+
12
+ # Log a debug message if debug mode is enabled
13
+ def log(message, prefix: "PANDA")
14
+ return unless enabled?
15
+
16
+ timestamp = Time.current.strftime("%Y-%m-%d %H:%M:%S")
17
+ puts "[#{prefix} DEBUG #{timestamp}] #{message}"
18
+ end
19
+
20
+ # Log an object with pretty printing (using awesome_print if available)
21
+ def inspect(object, label: nil, prefix: "PANDA")
22
+ return unless enabled?
23
+
24
+ timestamp = Time.current.strftime("%Y-%m-%d %H:%M:%S")
25
+ header = label ? "#{label}: " : ""
26
+
27
+ puts "\n[#{prefix} DEBUG #{timestamp}] #{header}"
28
+ if defined?(AwesomePrint)
29
+ ap object
30
+ else
31
+ pp object
32
+ end
33
+ puts
34
+ end
35
+
36
+ # Enable HTTP debugging for Net::HTTP requests
37
+ def enable_http_debug!
38
+ return unless enabled? || ENV["DEBUG_HTTP"].to_s.downcase == "true"
39
+
40
+ require "net/http"
41
+ Net::HTTP.set_debug_output($stdout)
42
+ log("HTTP debugging enabled - all HTTP requests will be logged")
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -13,11 +13,24 @@ module Panda
13
13
  config.eager_load_namespaces << Panda::Core::Engine
14
14
 
15
15
  # Add engine's app directories to autoload paths
16
+ # Note: Only add the root directories, not nested subdirectories
17
+ # Zeitwerk will automatically discover nested modules from these roots
16
18
  config.autoload_paths += Dir[root.join("app", "models")]
17
19
  config.autoload_paths += Dir[root.join("app", "controllers")]
18
20
  config.autoload_paths += Dir[root.join("app", "builders")]
19
21
  config.autoload_paths += Dir[root.join("app", "components")]
20
22
 
23
+ # Make files in public available to the main app (e.g. /panda-core-assets/panda-logo.png)
24
+ config.app_middleware.use(
25
+ Rack::Static,
26
+ urls: ["/panda-core-assets"],
27
+ root: Panda::Core::Engine.root.join("public"),
28
+ header_rules: [
29
+ # Disable caching in development for instant CSS updates
30
+ [:all, {"Cache-Control" => Rails.env.development? ? "no-cache, no-store, must-revalidate" : "public, max-age=31536000"}]
31
+ ]
32
+ )
33
+
21
34
  config.generators do |g|
22
35
  g.test_framework :rspec
23
36
  g.fixture_replacement :factory_bot
@@ -32,34 +45,95 @@ module Panda
32
45
  end
33
46
  end
34
47
 
35
- initializer "panda_core.configuration" do |app|
48
+ initializer "panda_core.config" do |app|
36
49
  # Configuration is already initialized with defaults in Configuration class
37
50
  end
38
51
 
52
+ # Add importmap paths from the engine
53
+ initializer "panda_core.importmap", before: "importmap" do |app|
54
+ if app.config.respond_to?(:importmap)
55
+ # Create a new array if frozen
56
+ app.config.importmap.paths = app.config.importmap.paths.dup if app.config.importmap.paths.frozen?
57
+
58
+ # Add our paths
59
+ app.config.importmap.paths << root.join("config/importmap.rb")
60
+
61
+ # Handle cache sweepers similarly
62
+ if app.config.importmap.cache_sweepers.frozen?
63
+ app.config.importmap.cache_sweepers = app.config.importmap.cache_sweepers.dup
64
+ end
65
+ app.config.importmap.cache_sweepers << root.join("app/javascript")
66
+ end
67
+ end
68
+
39
69
  initializer "panda_core.omniauth" do |app|
40
70
  # Mount OmniAuth at configurable admin path
41
71
  app.middleware.use OmniAuth::Builder do
42
72
  # Configure OmniAuth to use the configured admin path
43
73
  configure do |config|
44
- config.path_prefix = "#{Panda::Core.configuration.admin_path}/auth"
45
- # Allow POST requests for request phase (required for CSRF protection)
46
- config.allowed_request_methods = [:get, :post]
74
+ config.path_prefix = "#{Panda::Core.config.admin_path}/auth"
75
+ # POST-only for CSRF protection (CVE-2015-9284)
76
+ # All login forms use POST via form_tag method: "post"
77
+ config.allowed_request_methods = [:post]
47
78
  end
48
79
 
49
- Panda::Core.configuration.authentication_providers.each do |provider_name, settings|
80
+ Panda::Core.config.authentication_providers.each do |provider_name, settings|
81
+ # Build provider options, allowing custom path name override
82
+ provider_options = settings[:options] || {}
83
+
84
+ # If path_name is specified, use it to override the default strategy name in URLs
85
+ if settings[:path_name].present?
86
+ provider_options = provider_options.merge(name: settings[:path_name])
87
+ end
88
+
50
89
  case provider_name.to_s
51
90
  when "microsoft_graph"
52
- provider :microsoft_graph, settings[:client_id], settings[:client_secret], settings[:options] || {}
91
+ provider :microsoft_graph, settings[:client_id], settings[:client_secret], provider_options
53
92
  when "google_oauth2"
54
- provider :google_oauth2, settings[:client_id], settings[:client_secret], settings[:options] || {}
93
+ provider :google_oauth2, settings[:client_id], settings[:client_secret], provider_options
55
94
  when "github"
56
- provider :github, settings[:client_id], settings[:client_secret], settings[:options] || {}
95
+ provider :github, settings[:client_id], settings[:client_secret], provider_options
57
96
  when "developer"
58
97
  provider :developer if Rails.env.development?
59
98
  end
60
99
  end
61
100
  end
62
101
  end
102
+
103
+ # Load Phlex base component after Rails application is initialized
104
+ # This ensures Rails.application.routes is available
105
+ initializer "panda_core.phlex_base", after: :load_config_initializers do
106
+ require "phlex"
107
+ require "phlex-rails"
108
+ require "literal"
109
+ require "tailwind_merge"
110
+
111
+ # Load the base component
112
+ require root.join("app/components/panda/core/base")
113
+ end
114
+
115
+ # Set up ViewComponent and Lookbook previews
116
+ initializer "panda_core.view_component" do |app|
117
+ app.config.view_component.preview_paths ||= []
118
+ app.config.view_component.preview_paths << root.join("spec/components/previews")
119
+
120
+ # Add preview directories to autoload paths in development
121
+ if Rails.env.development?
122
+ # Handle frozen autoload_paths array
123
+ if app.config.autoload_paths.frozen?
124
+ app.config.autoload_paths = app.config.autoload_paths.dup
125
+ end
126
+ app.config.autoload_paths << root.join("spec/components/previews")
127
+ end
128
+ end
129
+
130
+ # Create AdminController alias after controllers are loaded
131
+ # This allows other gems to inherit from Panda::Core::AdminController
132
+ initializer "panda_core.admin_controller_alias", after: :load_config_initializers do
133
+ ActiveSupport.on_load(:action_controller_base) do
134
+ Panda::Core.const_set(:AdminController, Panda::Core::Admin::BaseController) unless Panda::Core.const_defined?(:AdminController)
135
+ end
136
+ end
63
137
  end
64
138
  end
65
139
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Panda
4
4
  module Core
5
- VERSION = "0.2.3"
5
+ VERSION = "0.4.1"
6
6
  end
7
7
  end
data/lib/panda/core.rb CHANGED
@@ -13,4 +13,5 @@ end
13
13
  require_relative "core/version"
14
14
  require_relative "core/configuration"
15
15
  require_relative "core/asset_loader"
16
+ require_relative "core/debug"
16
17
  require_relative "core/engine" if defined?(Rails)